Chapter 2 Preparar o banco

Preparação do ambiente e manipulação dos bancos.

2.1 Preparar o ambiente

Importar pacotes.

library (flexdashboard)
library (dplyr)
library (mirt)
library (ggplot2)
library (plotly)
library (mirtCAT)
library (DT)
library (xlsx)
library (readxl)
library (lordif)
library (reactable)
library (ModelMetrics)

2.2 Manipular o banco

Importamos os bancos da Unesp já manipulados. Só temos o ID da pessoa, o ano e as respostas.

load('bancos_unesp_mascara.RData')

banco_unesp <- rbind (
  banco_2019,
  banco_2020,
  banco_2021
)

names (banco_unesp) <- c ('ID', 'ano_aluno', 'anoTP', paste0('i', 1:120))

banco_unesp$grupo <- 'unesp'

banco_unesp <- select (banco_unesp, ID, anoTP, ano_aluno, grupo, everything())

Importar o banco da Unicamp.

# importar banco unicamp
banco_unicamp <- read_xlsx('../../banco/Dario 3.xlsx')
banco_unicamp <- data.frame (banco_unicamp)

# selecionar de 2019 a 2021
banco_unicamp <- subset (banco_unicamp, anoTP %in% c(2019:2021))

# novo ID (começando com 7777 é Unicamp)
banco_unicamp$ID <- paste0('7777', banco_unicamp$ID)

# grupo
banco_unicamp$grupo <- 'unicamp'

# selecionar variáveis de interesse
banco_unicamp <- select (banco_unicamp, ID, anoTP, anoCurso, grupo, starts_with('q'))

# renomear variáveis
names (banco_unicamp) <- c ('ID', 'anoTP', 'ano_aluno', 'grupo', paste0('i', 1:120))

Juntar todos os bancos e selecionar quem fez pelo menos um ponto na prova. Aqui também vamos excluir as linhas “sujas”do banco original do xls

banco <- rbind(
  banco_unesp,
  banco_unicamp
)

names (banco)[5:124] <- paste0('Q', 1:120)

banco$total <- rowSums(select (banco, starts_with('Q')))

banco <- subset (banco, total > 0)

# transformar o ano em variável numérica
banco$ano_aluno <- as.numeric(banco$ano_aluno)
banco$anoTP <- as.numeric(banco$anoTP)

É importante lembrar que o mesmo sujeito aparece em mais de um banco, porque ele fez a prova mais de um ano. Cada sujeito possui uma identificação única.

Para montar o banco para a calibração, precisamos juntar os bancos e deixar o banco “wide”. Ou seja, cada linha é um sujeito e cada coluna é um item. Se o sujeito não respondeu aquele item (por exemplo, não fez a prova de 2019), o valor é NA.

É importante ressaltar que só mantivemos o ID dos sujeitos utilizados na ligação entre as provas. Ou seja, os sujeitos do: 1. 5o ano 2019/6o ano 2020 2. 5o ano 2020/6o ano 2021

Para as demais observações, criamos outro ID. Mesmo para os sujeitos que estavam no 5o ano de alguma aplicação listada acima. Por exemplo, o 4o ano 2014, que são as mesmas pessoas do 5o ano 2015.

Primeiro, criar novo ID mantendo o antigo para os sujeitos dos grupos de ligação. As pessoas que erraram tudo serão excluídas do banco

# o ID2 começa em 8888 para todos
banco$ID2 <- paste0('8888', 1:nrow(banco))

# os pares:

# 2019 com 2020
banco$ID2 <- ifelse (banco$anoTP == 2019 & banco$ano_aluno == 5, banco$ID, banco$ID2)
banco$ID2 <- ifelse (banco$anoTP == 2020 & banco$ano_aluno == 6, banco$ID, banco$ID2)

# 2020 com 2021
banco$ID2 <- ifelse (banco$anoTP == 2020 & banco$ano_aluno == 5, banco$ID, banco$ID2)
banco$ID2 <- ifelse (banco$anoTP == 2021 & banco$ano_aluno == 6, banco$ID, banco$ID2)

banco$ID3 <- paste0(banco$ID, banco$anoTP)

# retirar a pessoa duplicada
banco <- subset (banco, banco$ID3 != banco$ID3[duplicated(banco$ID3)])

# reordenar as variáveis
banco <- select (banco, "ID", "ID2", "ID3", "anoTP", "ano_aluno", "grupo", "total", everything())

# objeto com os grupos
grupos <- data.frame(
  ID2 = banco$ID2,
  grupo = banco$grupo
)

grupos <- grupos[!duplicated(grupos$ID2),]

Agora deixar o banco wide de fato.

banco_total <- data.frame()
for (ano in unique (banco$anoTP))
{
  # ano = 2020
  # selecionar os sujeitos do ano da prova
  banco_total. <- subset(banco, anoTP == ano)
  names(banco_total.)[8:127] <- c(
    paste0(
      'Q',
      ano,
      '_',
      sprintf('%03d',1:120)
    )
  )
  
  # selecionar as variáveis necessárias nesse momento (ID2 e os itens)
  banco_total. <- select (banco_total., 'ID2', starts_with('Q'))
  
  # fazer o join
  # se já tiver alguém no banco_total, fazer o join. Se não tiver, pega o banco_total.
  if(nrow(banco_total)>0)
  {
    banco_total <- full_join(banco_total, banco_total., by = 'ID2')
  } else {
    banco_total <- banco_total.
  }
}

banco_total <- left_join(banco_total, grupos, by = 'ID2') %>%
  select(ID2, grupo, everything())

2.3 Banco para equalização

Agora vamos preparar os bancos para avaliar a equalização dos testes. Primeiro, filtrar o banco pelo ano da prova e a turma do sujeito. Pegar somente quem acertou pelo menos uma

# 2019 com 2020
banco19.5 <- subset (banco, anoTP == 2019 & ano_aluno == 5)

banco20.6 <- subset (banco, anoTP == 2020 & ano_aluno == 6) %>%
  select(ID, starts_with('Q'))

names(banco19.5)[8:127] <- c(
  paste0(
    'Q',
    2019,
    '_',
    sprintf('%03d',1:120)
  )
)

names(banco20.6)[2:121] <- c(
  paste0(
    'Q',
    2020,
    '_',
    sprintf('%03d',1:120)
  )
)

# 2020 com 2021
banco20.5 <- subset (banco, anoTP == 2020 & ano_aluno == 5)

banco21.6 <- subset (banco, anoTP == 2021 & ano_aluno == 6) %>%
  select(ID, starts_with('Q'))


names(banco20.5)[8:127] <- c(
  paste0(
    'Q',
    2020,
    '_',
    sprintf('%03d',1:120)
  )
)

names(banco21.6)[2:121] <- c(
  paste0(
    'Q',
    2021,
    '_',
    sprintf('%03d',1:120)
  )
)

Agora montar os bancos dois a dois.

banco19_20 <- inner_join(banco19.5, banco20.6, by = 'ID')
banco20_21 <- inner_join(banco20.5, banco21.6, by = 'ID')

Para cada equalização, temos as seguintes observações:

nrow(banco19_20)
## [1] 185
nrow(banco20_21)
## [1] 171

Cada banco possui os seguintes quantitativos de itens:

ncol(banco19_20)-7
## [1] 240
ncol(banco20_21)-7
## [1] 240

2.4 Checagens

Verificar se algum item teve 100% de acerto ou 0% de acerto. Vou criar uma função para excluir esses itens e deixar um aviso.

acerto_erro <- function(x)
{
  # verificar a média do item (se der 0, é 100% de erro; se der 1, é 100% de acerto)
  media <- apply(x[,-c(1:7)], 2, mean, na.rm = TRUE)
  x <- select(x, -names(media)[which(media == 1)])
  x <- select(x, -names(media)[which(media == 0)])
  
  # texto caso tenha havido algum item com 100% de acerto
  if (sum(media == 1)>0)
  {
    print(
      paste0(
        'Os itens ',
        paste0(names(media)[which(media == 1)], collapse = ' '),
        ' tiveram 100% de acerto.'
      )
    )
  } else {
    print('Nenhum item teve 100% de acerto')
  }
  
  # texto caso tenha havido algum item com 100% de erro
  if (sum(media == 0)>0)
  {
    print(
      paste0(
        'Os itens ',
        paste0(names(media)[which(media == 0)], collapse = ' '),
        ' tiveram 100% de erro'
      )
    )
  } else {
    print('Nenhum item teve 100% de erro')
  }
  
  return(x)
}
banco19_20 <- acerto_erro(banco19_20)
## [1] "Nenhum item teve 100% de acerto"
## [1] "Os itens Q2020_091 Q2020_105 tiveram 100% de erro"
banco20_21 <- acerto_erro(banco20_21)
## [1] "Nenhum item teve 100% de acerto"
## [1] "Os itens Q2020_091 Q2020_105 tiveram 100% de erro"

Agora para o banco_total.

media <- apply(banco_total[,-c(1:2)], 2, mean, na.rm = TRUE)

banco_total <- select(banco_total, -names(media)[which(media == 1)])

Nenhum item teve 100% de acerto

media <- apply(banco_total[,-c(1:2)], 2, mean, na.rm = TRUE)

banco_total <- select(banco_total, -names(media)[which(media == 0)])

Nenhum item teve 100% de erro

Agora temos 359 itens. Para fins de checagem, vamos verificar se todos os itens do mesmo período/ano possuem a mesma quantidade de respostas.

for (ano in 2019:2021)
{
  # selecionar os itens do ano
  banco.ano <- select (banco_total, starts_with(paste0('Q', ano)))
  
  freq <- apply (
    # verificar onde não tem NA
    data.frame (!is.na (banco.ano)),
    2,
    sum
  )
  print(paste0(
    'Ano: ',
    paste0(ano),
    ': ',
    ifelse(min(freq)==max(freq), 'OK', 'Problema')
  )
  )
  
  print(
    paste0(
      'min = ',
      min(freq),
      '; max = ',
      max(freq)
    )
  )
}
## [1] "Ano: 2019: OK"
## [1] "min = 1198; max = 1198"
## [1] "Ano: 2020: OK"
## [1] "min = 1157; max = 1157"
## [1] "Ano: 2021: OK"
## [1] "min = 1179; max = 1179"