setwd("/Users/isaiahmireles/Desktop/Misconceptions")
cohorts <- read.csv("cohorts.csv")

1 Student Counts (ct) per term & (term, exam) :

library(tidyverse)
cohorts |> group_by(term) |> summarize(ct = n())
cohorts |> group_by(term, exam) |> summarize(ct = n())
lst <- cohorts |>
  group_by(term, exam) |>
  group_split() 

2 S24 Midterm

S24M <- lst[[4]]
# only the Qs
S24MQ <- S24M |> select(matches("^Q\\d+$"))
dim(S24MQ)
## [1] 149  34
S24MQ |> head()
library(eRm)
Rasch_CML <- RM(S24MQ)
help(RM)
  • eRm package uses : conditional maximum likelihood (CML) estimation. Therefore it does not require the specification of the latent trait distribution ( \(\theta\) ).

    • Above I fit a Rasch Model

      • Here we assume \(\sum_{i=1}^{34}b_i=0\) ; meaning, the sum of item difficulty is 0.

        • Typical item Difficulty

          • \(b_i\approx0\) – about avr. difficulty
        • Easy Item Difficulty

          • Making \(b_i < 0\) – below avr. difficulty
        • Hard Item Difficulty

          • Making \(b_i > 0\) – above avr. difficulty

2.1 Inspect Model Object :

Rasch_CML |> attributes()
## $names
##  [1] "X"           "X01"         "model"       "loglik"      "npar"       
##  [6] "iter"        "convergence" "etapar"      "se.eta"      "hessian"    
## [11] "betapar"     "se.beta"     "W"           "call"       
## 
## $class
## [1] "dRm" "Rm"  "eRm"

3 Did our model converge normally?

Rasch_CML$conv
## [1] 1
  • Yes! Finished within the default stopping criteria without being flagged by particular problems.

4 Item Difficulty & Standard Error

item_difficulty <- cbind(-Rasch_CML$betapar, Rasch_CML$se.beta)
colnames(item_difficulty) <- c("est", "SE")
item_difficulty <- item_difficulty |> as.data.frame(); item_difficulty

5 Difficulty Confidence Interval

difficulty_CI <- cbind(-confint(Rasch_CML)[,2], -confint(Rasch_CML)[,1])
colnames(difficulty_CI) <- c("Low", "High")
difficulty_CI <- difficulty_CI |> as.data.frame(); difficulty_CI
difficulty <- cbind(difficulty_CI, est=item_difficulty[,1], item = names(Rasch_CML$betapar))

# summary(Rasch_CML)
# better method^
difficulty |>
  ggplot(aes(
    x = est,
    y = reorder(item, est),
    xmin = Low,
    xmax = High
  )) +
  geom_pointrange() +
  geom_vline(
    xintercept = 0,
    linetype = "dashed"
  ) +
  labs(
    title = "Item Difficulty CI-95%",
    x = "Item Difficulty",
    y = "Item"
  ) +
  theme_minimal()

# set margin sizes
par(
  mfrow = c(2, 1),
  mar = c(3, 4, 2, 1)
)

hist(
  item_difficulty$est,
  main = "Item Difficulty Dist"
)

boxplot(
  item_difficulty$est,
  horizontal = TRUE
)

# reset 
par(mfrow = c(1, 1))
  • As we can see difficulty is normally distributed

    • Most problems are typical difficulty with few being extremely easy, few being extremely hard.

6 What percent of people got each item correct?

percent_correct <- S24MQ |>
  summarize(
    across(
      everything(),
      ~ mean(.x, na.rm = TRUE) * 100
    )
  )
percent_correct

7 Do these measures correlate?

percent_correct_long <- percent_correct |>
  pivot_longer(
    cols = everything(),
    names_to = "item",
    values_to = "percent_correct"
  )

difficulty_percent <- difficulty |>
  mutate(
    item = str_remove(item, "^beta ")
  ) |>
  left_join(
    percent_correct_long,
    by = "item"
  )
difficulty_percent |>
  ggplot(aes(
    x = est,
    y = percent_correct
  )) +
  geom_point() +
  geom_text(
    aes(label = item),
    nudge_y = 2,
    size = 3
  ) +
  labs(
    title = "Item Difficulty vs. Percent Correct",
    x = "Item Difficulty",
    y = "Percent Correct"
  ) +
  theme_minimal()

  • clear, non-linear relationship
cor(difficulty_percent$est, difficulty_percent$percent_correct)^2
## [1] 0.9154302
  • about 92% of variation can be described via regressing est and percent_correct

    • Therefore despite non-linear trend, we may adequately summarize relationship linearly

8 Item Characteristic Curve (ICC)

plotICC(Rasch_CML, empICC = list("raw"))

  • usually for this we go per-item and analyze each. Above is just a demonstration.

9 Person Specific latent trait

Person.Rasch_CML <- person.parameter(Rasch_CML)
plot(Person.Rasch_CML) 

  • estimated latent trait scores using the estimated item parameters and data from the previously fitted Rasch object

  • Notice ability rises increasingly fast near the maximum possible score