Análise artigo 1 - Evidências de validade iniciais da TASComp

Author

Carolina Aguiar (Mestranda)

Dados individuos grupo controle

  • Foram analisadas a acurácia e o tempo médio de resposta por cada participante em cada tipo de sentença, e agrupado por cada tipo de sentença considerando a amostra total

  • Neste arquivo será apresentado o passo a passo do código para leitura dos dados

    Carregando pacotes

library(stringr)
library(readr)
library(dplyr) 
library(data.table) 
library(readxl)
library(tidyr)
library(fuzzyjoin)
library(xfun)
library(purrr)
library(knitr)
library(reactable)
library(plotly)
library(ggplot2)
.libPaths()
[1] "C:/Users/carol/AppData/Local/R/win-library/4.4"
[2] "C:/Program Files/R/R-4.4.2/library"            

Selecionando o diretório

  • Selecionar o diretório para “puxar” os dados da pasta

  • Os arquivos do Psytoolkit são salvos separadamente, por participante - e também separados em arquivos de experimento e arquivos de eperimento

Unindo os arquivos separados em um dataframe

  • Juntando os arquivos do psytookit em um mesmo dataframe

  • 100 participantes saudáveis – sem comprometimento cognitivo autorrelatado

dadossaudaveis <- list.files(full.names = FALSE, pattern = "\\.txt$") %>%# organiza arquivos da pasta
  sapply(., read_table, col_names = FALSE , simplify = F) %>% 
  # faz a leitura dos arquivos e transforma em lista
  rbindlist(., use.names = TRUE, idcol = "id", fill= TRUE) %>% 
  # transforma a variavel em um data frame e cria uma coluna com o nome do arquivo de origem
  mutate(id = str_sub(id, end = -5)) # para tirar os textos "a mais"

names(dadossaudaveis)=c("ID", "exp","questao" ,"tipo", "condicao","RT", "pontuacao", "tempo", "acerto", "resposta") #renomeia o nome de cada coluna do data frame

# Count the number of unique IDs
num_unique_IDs <- length(unique(dadossaudaveis$ID))

# Print the result
num_unique_IDs
[1] 101
  • Salvando data frame em um arquivo csv - corrigir pontuações erradas do script primeiramente para depois calcular os acertos no teste
write.csv(dadossaudaveis, "banco_101part.csv")
  • Nesse primeiro momento o tempo não será calculado, aqui estará calculada as respostas corretas
  • Primeiramente carregando o banco do experimento já corrigido respostas corretas e incorretas
bloco_101 <- read.csv("banco101_correct.csv", sep= ";")
  • Calculando a porcentagem de acertos

  • acerto_bl - porcentagem de acertos por participante em cada condição

  • cond_percent - porcentagem de acertos por condição

  • acerto_part -porcentagem de acertos em cada participante

#  Percent correct by ID and condition
acerto_bl <- bloco_101 %>%
  group_by(ID, condicao) %>%
  summarise(percent = round(sum(acerto == "Correto") * 100 / n(), 2))

#  Percent correct by condition
cond_percent <- bloco_101 %>%
  group_by(condicao) %>%
  summarise(percent = round(sum(acerto == "Correto") * 100 / n(), 2))

#  Percent correct by participant (ID)
acerto_part <- bloco_101 %>%
  group_by(ID) %>%
  summarise(percent = round(sum(acerto == "Correto") * 100 / n(), 2))

# percent para tipo de sentença
acerto_tipo <- bloco_101 %>%
  group_by(tipo) %>%
  summarise(percent = round(sum(acerto == "Correto") * 100 / n(), 2))

Arquivos

  • O arquivo dados saudaveis contém todas as respostas de todos os participantes

  • O arquivo final_dados já agrupa o tempo e os acertos por condição, em cada participante - assim como define a acurácia em porcentagem

Cálculo do tempo de resposta

  • Não estamos calculando o tempo
#remover outliers +- 2dp
#dados <- subset(filtro,filtro$RT > mean(filtro$RT, na.rm = TRUE) - 
                  #2*sd(filtro$RT, na.rm = TRUE) & 
                  #filtro$RT < mean(filtro$RT, na.rm = TRUE) + 
                  #2*sd(filtro$RT, na.rm = TRUE)) 

#filtro <- dadospiloto %>%  filter(ID != "", Status == "Correto",
                              #Block != "training")

Tabela - porcentagem de acertos em cada bloco e em cada participante

Gráfico ggplot

  • Gráfico da porcentragem de erros por item
library(dplyr)

corretos_sum <- bloco_101 %>%
  group_by(questao) %>%
  summarise(total_corretos = sum(pontuacao, na.rm = TRUE))


corretos_pct <- bloco_101 %>%
  group_by(questao) %>%
  summarise(percent_corretos = sum(pontuacao, na.rm = TRUE) / 100 * 100)

library(ggplot2)

ggplot(corretos_pct, aes(x = reorder(questao, -percent_corretos), y = percent_corretos)) +
  geom_bar(stat = "identity", fill = "#2E86AB") +
  labs(
    title = "N de acertos por item",
    x = "Item",
    y = "Número de acertos por item"
  ) +
  theme_minimal()

library(plotly)

fig <- plot_ly(corretos_pct, 
    x = ~questao,
    y = ~percent_corretos,
    type = "bar"
)

fig
reactable(corretos_sum)

graph_lines <- ggplot(corretos_pct, aes(x = reorder(questao, percent_corretos), y = percent_corretos, color = questao, group = 1)) +
  geom_line(size = 1) +
  geom_point(size = 3) +
  coord_flip() +  # horizontal orientation
  scale_y_continuous(limits = c(70, 100), breaks = seq(70, 100, 0.5)) +
  labs(
    title = "Porcentagem de respostas corretas por item",
    x = "Item",
    y = "Porcentagem de respostas corretas (%)"
  ) +
  theme_minimal() +
  theme(
    axis.line = element_blank(),       # remove all axis lines
    axis.ticks = element_blank(),       # remove all axis ticks
    panel.grid.minor = element_blank(), 
    axis.text.y = element_text(size = 8),          # increase y-axis labels
    axis.text.x = element_text(size = 10),         # increase x-axis labels
    axis.title.x = element_text(size = 12),        # x-axis title
    axis.title.y = element_text(size = 12),        # y-axis title
    plot.title = element_text(size = 14, face = "bold")
    

  )

ggsave("percent_correct_items.jpg", width = 18, height = 20, units = "in", dpi = 500)

fig <- ggplotly(graph_lines)
fig
corretos_part <-bloco_101 %>%
  filter(tipo != "treino") %>%                # exclude treino items
  group_by(ID) %>%
  summarise(perct_part = sum(pontuacao, na.rm = TRUE / 48 * 100))

corretos_part$perct_part <- as.numeric(corretos_part$perct_part)

library(dplyr)
library(ggplot2)
library(plotly)

# (Assumindo que 'bloco_100' existe)
# (Usando dados fictícios se 'bloco_100' não existir para este exemplo)
if (!exists("bloco_101")) {
  bloco_100 <- data.frame(
    ID = rep(paste0("P", 1:10), each = 50),
    tipo = rep(c("teste", "treino", "teste", "teste", "teste"), times = 100),
    pontuacao = sample(c(0, 1), 500, replace = TRUE, prob = c(0.15, 0.85))
  )
}

# --- 1. CÁLCULO CORRIGIDO ---
corretos_part <- bloco_101 %>%
  filter(tipo != "treino") %>%
  group_by(ID) %>%
  # Parênteses corrigidos para o cálculo da porcentagem
  summarise(perct_part = (sum(pontuacao, na.rm = TRUE) / 48) * 100)

# (A linha as.numeric não é mais necessária, pois o cálculo já retorna numeric)
# corretos_part$perct_part <- as.numeric(corretos_part$perct_part)


# --- 2. GGPLOT CORRIGIDO ---
graph_lines_part <- ggplot(corretos_part, 
                           # AES CORRIGIDO:
                           # x = ID reordenado por perct_part
                           # y = perct_part
                           # group = 1 (para conectar a linha)
                           aes(x = reorder(ID, perct_part), 
                               y = perct_part, 
                               color = ID, 
                               group = 1)) +
  geom_line(size = 1) +
  geom_point(size = 3) +
  coord_flip() +  
  
  # ESCALA CORRIGIDA (ex: 60% a 100%)
  scale_y_continuous(limits = c(60, 100), breaks = seq(60, 100, 5)) +
  
  labs(
    title = "Porcentagem de respostas corretas por participante",
    # Os eixos são trocados pelo coord_flip, então X é 'Participant'
    x = "Participante", 
    y = "Porcentagem de respostas corretas (%)"
  ) +
  theme_minimal() +
  theme(
    axis.line = element_blank(),    
    axis.ticks = element_blank(),   
    panel.grid.minor = element_blank(),
    axis.text.y = element_text(size = 8),      
    axis.text.x = element_text(size = 10),     
    axis.title.x = element_text(size = 12),     
    axis.title.y = element_text(size = 12),     
    plot.title = element_text(size = 14, face = "bold"),
    
    # Adicionado para remover a legenda de cores (costuma poluir este tipo de gráfico)
    legend.position = "none" 
  )

# --- 3. PLOTLY ---
fig1 <- ggplotly(graph_lines_part)
fig1

Gráfico

% acurácia em cada bloco

# Gráfico de barras com formatação dos eixos e título
cond_graph <- ggplot(cond_percent, aes(x = condicao, y = percent, fill= condicao)) +
  geom_bar(stat = "identity") +
  labs(
    title = "% de acertos em cada bloco",   # título geral
    x = "Condição",                         # título eixo X
    y = "Média de Acurácia"                 # título eixo Y
  ) +
  theme_classic() +  # estilo mais limpo
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),  # centraliza e negrita o título
    axis.title.x = element_text(size = 12, face = "bold"),             # título eixo X
    axis.title.y = element_text(size = 12, face = "bold"),             # título eixo Y
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)     # texto eixo X na vertical
  ) +
  coord_cartesian(ylim = c(50, 100))  # define limites do eixo Y

# Converter para gráfico interativo
cond_g_plotly <- ggplotly(cond_graph) %>%
  layout(
    showlegend = FALSE,               # <--- hides the legend
    yaxis = list(range = c(50, 100))  # <--- keeps same y range
  )

cond_g_plotly
plot_ly(
  data = acerto_tipo,
  x = ~tipo,
  y = ~percent,
  type = "bar",
  color = ~tipo,              # <- cada bloco com cor diferente
  colors = "Set2",            # <- paleta de cores (pode trocar: "Set1", "Viridis", "Dark2", etc.)
  name = "Média de Acurácia"
) %>%
  layout(
    title = "% de acertos no tipo de sentença",
    xaxis = list(title = "Condição", tickangle = 45),
    yaxis = list(
      title = "Média de Acurácia",
      range = c(50, 100)      # <- define mínimo e máximo do eixo Y
    ),
    bargap = 0.3,
    showlegend = FALSE
  )
  • acertos de questões por cada participante
  • criando um dataframe com os acertos dos participantes em cada bloco, para que depois possa juntar com o data frame do survey criando um data para analise por bloco

  • unindo o data frame dos dados sociodemografico, do survey do psytookit, com as colunas do número de acertos em cada bloco em colunas

  • por último iremos colocar cada item como uma coluna diferente, evidenciando acertos e erros - para calculo do alfa e do omega de mcdonald

  • agora vamos unir todos os bancos - questao - acertos e etc

  • calculando o KR-20 para os itens do teste

    Análise do KR-20 Consistência Interna

    Consistência interna para itens dicotômicos - Kuder-Richardson 20 (KR-20) e 21 (KR-21)

# install.packages("psych")

library(psych)

# Assuming your data frame is named ãct_quest and has a column "ID"
# Rename it for safe variable handling:
act_quest <- `act_quest`

# Remove the ID, treino_1, and treino_2 columns
items <- act_quest[ , !(names(act_quest) %in% c("ID", "treino_1", "treino_2"))]

# --- Check ---
dim(items)   # should show 101 rows × 46 items
[1] 101  48
head(items)
# A tibble: 6 × 48
  bl1_1 bl1_10 bl1_11 bl1_12 bl1_13 bl1_14 bl1_15 bl1_16 bl1_2 bl1_3 bl1_4 bl1_5
  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int> <int> <int> <int> <int>
1     1      1      1      1      1      1      1      1     0     1     0     1
2     0      1      1      1      0      0      1      0     0     1     1     1
3     1      1      1      1      1      1      1      1     1     1     1     1
4     1      1      1      1      1      1      1      1     1     1     1     1
5     1      1      1      1      1      1      1      1     1     1     1     1
6     1      1      1      1      1      1      1      1     1     0     1     1
# ℹ 36 more variables: bl1_6 <int>, bl1_7 <int>, bl1_8 <int>, bl1_9 <int>,
#   bl2_17 <int>, bl2_18 <int>, bl2_19 <int>, bl2_20 <int>, bl2_21 <int>,
#   bl2_22 <int>, bl2_23 <int>, bl2_24 <int>, bl3_25 <int>, bl3_26 <int>,
#   bl3_27 <int>, bl3_28 <int>, bl3_29 <int>, bl3_30 <int>, bl3_31 <int>,
#   bl3_32 <int>, bl3_33 <int>, bl3_34 <int>, bl3_35 <int>, bl3_36 <int>,
#   bl4_37 <int>, bl4_38 <int>, bl4_39 <int>, bl4_40 <int>, bl4_41 <int>,
#   bl4_42 <int>, bl4_43 <int>, bl4_44 <int>, bl4_45 <int>, bl4_46 <int>, …
# --- KR-20 calculation ---
k <- ncol(items)                       # number of items (should be 46)
p <- colMeans(items, na.rm = TRUE)     # proportion correct
q <- 1 - p                             # proportion incorrect
total_score <- rowSums(items, na.rm = TRUE)
var_total <- var(total_score, na.rm = TRUE)

KR20 <- (k / (k - 1)) * (1 - (sum(p * q) / var_total))
KR20
[1] 0.6705232

Interpret KR-20 like Cronbach’s α:

  • ≥ 0.9 = Excellent

    0.8–0.9 = Good

    0.7–0.8 = Acceptable

    < 0.7 = Low internal consistency

  • índice assume que todos os itens apresentam a mesma dificuldade, assim não seria consistente.

  • Calculando o KR-20 por bloco

    # install.packages("psych")
    library(psych)
    library(dplyr)
    
    # --- Data preparation ---
    act_quest <- `act_quest`
    
    # Remove non-item columns
    items <- act_quest %>%
      select(-ID, -treino_1, -treino_2)
    
    # Check structure
    dim(items)
    [1] 101  48
    # bloco_101 should have columns: "questao" (item name) and "condicao"
    head(bloco_101)
      Column1  ID         exp  questao     tipo                condicao RT
    1       1 AF1      treino treino_1   treino             treino_inst  B
    2       2 AF1      treino treino_2   treino             treino_inst  A
    3       3 AF1 experimento    bl1_9 relativa rel_sujeito_ram_direita  A
    4       4 AF1 experimento    bl1_1 relativa         rel_obj_central  D
    5       5 AF1 experimento   bl2_23  clivada         clivada_sujeito  A
    6       6 AF1 experimento   bl1_16 relativa     rel_obj_ram_direita  A
      pontuacao tempo  acerto resposta
    1         1  3460 Correto        2
    2         1  8254 Correto        1
    3         1  9151 Correto        1
    4         1 30615 Correto        4
    5         1 12864 Correto        1
    6         1 18833 Correto        1
    # --- Define a KR20 function ---
    kr20 <- function(df) {
      k <- ncol(df)
      p <- colMeans(df, na.rm = TRUE)
      q <- 1 - p
      total_score <- rowSums(df, na.rm = TRUE)
      var_total <- var(total_score, na.rm = TRUE)
      (k / (k - 1)) * (1 - (sum(p * q) / var_total))
    }
    
    # --- Calculate KR-20 per condition ---
    kr20_results <- bloco_101 %>%
      group_by(condicao) %>%
      summarise(
        KR20 = {
          item_names <- questao[questao %in% names(items)]
          if (length(item_names) > 1) {
            kr20(items[, item_names, drop = FALSE])
          } else {
            NA  # cannot compute KR-20 with < 2 items
          }
        },
        n_items = sum(questao %in% names(items))
      )
    
    kr20_results
    # A tibble: 13 × 3
       condicao                     KR20 n_items
       <chr>                       <dbl>   <int>
     1 ativa_irresversivel         0.992     404
     2 ativa_perspectiva           0.992     404
     3 ativa_reversivel            0.995     404
     4 clivada_objeto              0.995     404
     5 clivada_sujeito             0.992     404
     6 passiva_irreversivel        0.994     404
     7 passiva_revers_implausivel  0.994     404
     8 passiva_revers_neutra       0.992     404
     9 rel_obj_central             0.996     404
    10 rel_obj_ram_direita         0.995     404
    11 rel_sujeito_central         0.995     404
    12 rel_sujeito_ram_direita     0.992     404
    13 treino_inst                NA           0
    reactable(kr20_results)
# install.packages(c("psych", "dplyr", "reactable"))
library(psych)
library(dplyr)
library(reactable)
library(reactablefmtr)


# --- Prepare data ---
act_quest <- `act_quest`
items <- act_quest %>% select(-ID, -treino_1, -treino_2)

# KR-20 function
kr20 <- function(df) {
  k <- ncol(df)
  if (k < 2) return(NA)  # avoid division by zero
  p <- colMeans(df, na.rm = TRUE)
  q <- 1 - p
  total_score <- rowSums(df, na.rm = TRUE)
  var_total <- var(total_score, na.rm = TRUE)
  (k / (k - 1)) * (1 - (sum(p * q) / var_total))
}

# --- Compute KR20 per condition ---
kr20_results <- bloco_101 %>%
  group_by(condicao) %>%
  summarise(
    KR20 = {
      item_names <- questao[questao %in% names(items)]
      if (length(item_names) > 1) {
        kr20(items[, item_names, drop = FALSE])
      } else {
        NA
      }
    },
    n_items = sum(questao %in% names(items)),
    .groups = "drop"
  )

# --- Display in interactive table ---
reactable(
  kr20_results,
  filterable = TRUE,
  searchable = TRUE,
  sortable = TRUE,
  pagination = TRUE,
  highlight = TRUE,
  striped = TRUE,
  bordered = TRUE,
  defaultPageSize = 10,
  columns = list(
    condicao = colDef(name = "Condition", align = "center"),
    KR20 = colDef(name = "KR-20", align = "center", format = colFormat(digits = 3)),
    n_items = colDef(name = "Number of Items", align = "center")
  ),
  theme = reactablefmtr::fivethirtyeight()
)