setwd("/Users/isaiahmireles/Desktop/Misconceptions")

# Midterm : 
# F23 
F23_M_VA <- 
  read.csv("F23_Midterm_Version_Set_Scores/Midterm_Version_A_scores.csv")
F23_M_VB <- 
  read.csv("F23_Midterm_Version_Set_Scores/Midterm_Version_B_scores.csv")

# W24 
W24_M_VA <- 
  read.csv("W24_Midterm_Version_Set_Scores/Midterm_Version_A_scores.csv")
W24_M_VB <- 
  read.csv("W24_Midterm_Version_Set_Scores/Midterm_Version_B_scores.csv")

# S24 
S24_M <- 
  read.csv("24S-STATS-10-LEC-4_Midterm/S24_Midterm_student_responses copy.csv")

# ------------------------------------------------------------------------------- #

# Final :
# F23
F23_F_VA <- 
  read.csv("F23_Final_Exam_Version_Set_Scores/Final_Exam_Version_A_scores.csv")
F23_F_VB <- 
  read.csv("F23_Final_Exam_Version_Set_Scores/Final_Exam_Version_B_scores.csv")

# W24 
W24_F_VA <- 
  read.csv("W24_Final_Exam_Version_Set_Scores/Final_Exam_Version_A_scores.csv")
W24_F_VB <- 
  read.csv("W24_Final_Exam_Version_Set_Scores/Final_Exam_Version_B_scores.csv")

# S24 
S24_F_VA <- 
  read.csv("S24_Final_Exam_Version_Set_Scores/Final_Exam_Version_A_scores.csv")
S24_F_VB <- 
  read.csv("S24_Final_Exam_Version_Set_Scores/Final_Exam_Version_B_scores.csv")
n_std <-
  F23_F_VA |> nrow() + F23_F_VB |> nrow() + W24_F_VA |> nrow() + W24_F_VB |> nrow() + S24_F_VA |> nrow() + S24_F_VB |> nrow()  
n_std
## [1] 1520

1 Fall Cohort/Class

1.1 Midterm

Count how many times a user occurs multiple times

library(tidyverse)
bind_rows(
  F23_M_VA |> mutate(dataset = "A"),
  F23_M_VB |> mutate(dataset = "B")
) |>
  group_by(First.Name, Last.Name) |>
  summarise(
    times = n(),
    datasets = paste(unique(dataset), collapse = ", "),
    .groups = "drop"
  ) |>
  filter(times > 1) 


bind_rows(
  F23_M_VA |> mutate(dataset = "A"),
  F23_M_VB |> mutate(dataset = "B")
) |>
  group_by(First.Name, Last.Name) |>
  summarise(
    times = n(),
    datasets = paste(unique(dataset), collapse = ", "),
    .groups = "drop"
  ) |>
  filter(times > 1) |>
  count(datasets)
  • unfortunately, people are appearing for both version A, B

Perhaps its only because non-graded are repeated in both?

bind_rows(
  F23_M_VA |> filter(Status == "Graded") |> mutate(dataset = "A"),
  F23_M_VB |> filter(Status == "Graded") |> mutate(dataset = "B")
) |>
  group_by(First.Name, Last.Name) |>
  summarise(
    times = n(),
    datasets = paste(unique(dataset), collapse = ", "),
    .groups = "drop"
  ) |>
  filter(times > 1)
  • yes, as we can see only unidentified student, Graded students appear in both – which makes sense given its non-identifiable

1.1.1 Combine into F23 Midterm Versions (A,B)

F23_M <-
  bind_rows(
  F23_M_VA |> filter(Status == "Graded") |> mutate(version = "A"),
  F23_M_VB |> filter(Status == "Graded") |> mutate(version = "B")
)

1.2 irregular SID Func

check_sid <- function(df) {
  
  # Check whether SID column exists
  if (is.null(df$SID)) {
    return("SID column is NULL or does not exist")
  }
  
  df |>
    mutate(idx = row_number()) |>
    filter(
      is.na(SID) |
      trimws(as.character(SID)) == "" |
      !grepl("^[0-9]+$", as.character(SID))
    ) |>
    select(idx, SID)
}
check_sid(F23_M) |> count(SID)
  • irregular SID are all NA
F23_M |> filter(is.na(SID)) |> select(SID, First.Name, Last.Name) |> count(First.Name)
  • notice all the NA SID are all unidentified students, that makes sense.
F23_M <- F23_M |> mutate(unidentified = First.Name == "unidentified" & Last.Name == "student") 
  • here i added a binary indicator

1.3 Anonymize & Split id./non-id Students

F23_M <- 
  F23_M |>
  mutate(
    student_id = if_else(
      unidentified,
      paste0("unidentified_", cumsum(unidentified)),
      paste0(
        "student_",
        match(SID, unique(SID[!is.na(SID)]))
      )
    )
  )

1.3.1 Create dictionary :

F23_M_dictionary <- F23_M |>
  select(
    student_id,
    SID,
    Submission.ID,
    First.Name,
    Last.Name,
    Email
  )
  • the purpose is so we can connect students across exams anonymously

1.4 Find Duplicates Func

find_duplicates <- function(df) {
  df |>
    mutate(idx = row_number()) |>
    group_by(SID) |> # grp by student id 
    filter(n() > 1) |>
    ungroup() |> 
    pull(idx) # make vector
}
F23_M[find_duplicates(F23_M),] |> count(SID)
  • meaning the only repeated SID are NA – so those are the unidentified students

1.5 Anonymize

F23_M <- 
  F23_M |>
  select(
    student_id,
    version,
    Total.Score,
    Max.Points,
    everything(),
    -Status,
    -SID,
    -Submission.Count,
    -Submission.ID,
    -First.Name,
    -Last.Name,
    -Email,
    -Lateness..H.M.S.,
    -View.Count,
    -Submission.Time
  )
F23_M <- F23_M |> mutate(exam = "Midterm", term = "F23")
rm(list=c("F23_M_VA", "F23_M_VB"))
F23_M <- 
  F23_M |> select(unidentified, term, exam, version, student_id, Sections, Total.Score, everything())

1.6 Final

bind_rows(
  F23_F_VA |> filter(Status == "Graded") |> mutate(dataset = "A"),
  F23_F_VB |> filter(Status == "Graded") |> mutate(dataset = "B")
) |>
  group_by(First.Name, Last.Name) |>
  summarise(
    times = n(),
    datasets = paste(unique(dataset), collapse = ", "),
    .groups = "drop"
  ) |>
  filter(times > 1)
  • in other words, graded students only appear once in each data set

1.6.1 Combine Versions

F23_F <- 
  bind_rows(
  F23_F_VA |> filter(Status == "Graded") |> mutate(version = "A"),
  F23_F_VB |> filter(Status == "Graded") |> mutate(version = "B")
)

1.6.2 Check SID

check_sid(F23_F)
  • nothing weird going on

1.6.3 unidentified feature

F23_F |> 
  mutate(unidentified = First.Name == "unidentified" & Last.Name == "student") |> count(unidentified)
F23_F <- 
  F23_F |> 
  mutate(unidentified = First.Name == "unidentified" & Last.Name == "student")
  • there arent any unidentified students
F23_F <- F23_F |> mutate(exam = "Final", term = "F23")

1.6.4 student_id

F23_M |> count(unidentified)
  • there can be at most 297 students whom took the final

1.7 Connect student ids

F23_F <- F23_F |>
  left_join(
    F23_M_dictionary |>
      filter(!is.na(SID)) |>
      distinct(SID, student_id),
    by = "SID"
  )
F23_F |>
  count(is.na(student_id))
# F23_F |> filter(is.na(student_id)) 
# F23_F |> filter(is.na(student_id)) |> select(Total.Score)
  • Notice 1 student did not appear in the identifiable midterm dictionary

1.8 Provide std with student id

max_id <- F23_M_dictionary |>
  filter(grepl("^student_", student_id)) |>
  pull(student_id) |>
  readr::parse_number() |>
  max()

F23_F <- F23_F |>
  mutate(
    student_id = if_else(
      is.na(student_id),
      paste0("student_", max_id + 1),
      student_id
    )
  )

1.9 Anonymize

F23_F <- 
  F23_F |>
  select(
    student_id,
    version,
    Total.Score,
    Max.Points,
    everything(),
    -Status,
    -SID,
    -Submission.Count,
    -Submission.ID,
    -First.Name,
    -Last.Name,
    -Email,
    -Lateness..H.M.S.,
    -View.Count,
    -Submission.Time
  )

1.10 Combine into one cohort

# reconfigure questions
F23_M <- F23_M |>
  rename_with(
    ~ paste0(
      "Q",
      sub("^X([0-9]+).*", "\\1", .x),
      "_F23M"
    ),
    matches("^X[0-9]+\\.\\.Question")
  )
F23_F <- 
  F23_F |>
  rename_with(
    ~ paste0(
      "Q",
      sub("^X([0-9]+).*", "\\1", .x),
      "_F23F"
    ),
    matches("^X[0-9]+\\.\\.Question")
  )
F23_F <- F23_F |>
  select(
    unidentified,
    term,
    exam,
    version,
    student_id,
    Sections,
    Total.Score,
    Max.Points,
    everything()
  )
# actually just change Questions to Qx :
F23_M <- F23_M |>
  rename_with(
    ~ sub("_F23M$", "", .x),
    starts_with("Q")
  )

F23_F <- F23_F |>
  rename_with(
    ~ sub("_F23F$", "", .x),
    starts_with("Q")
  )

2 F23 Class

F23 <- bind_rows(F23_M, F23_F)

So the final has 31Qs and Midterm has 34, so im checking what those values become :

F23 |> filter(exam=="Final") |> select(Q32:Q34) |> head()
rm(F23_F, F23_F_VA, F23_F_VB, F23_M)
rm(max_id)

3 Winter Cohort/Class

3.1 Midterm

W24_M_VA |> count(Status == "Graded")
W24_M_VB |> count(Status == "Graded")
W24_M_VA <- W24_M_VA |> 
  filter(Status == "Graded") |> 
  mutate(version = "A", exam = "Midterm", term = "W24")

W24_M_VB <- W24_M_VB |> 
  filter(Status == "Graded") |> 
  mutate(version = "B", exam = "Midterm", term = "W24")
W24_M <- bind_rows(W24_M_VA, W24_M_VB)
W24_M <- W24_M |> select(-Status)
check_sid(W24_M)
nrow(W24_M)
## [1] 297
W24_M |> count(SID) |> nrow()
## [1] 297
  • beautiful
W24_M <-
  W24_M |>
  mutate(
    student_id = paste0(
      "student_",
      match(SID, unique(SID))
    )
  )

3.1.1 Dictionary

W24_M_dictionary <- W24_M |>
  select(
    student_id,
    SID,
    Submission.ID,
    First.Name,
    Last.Name,
    Email
  )
find_duplicates(W24_M)
## integer(0)
find_duplicates
## function (df) 
## {
##     pull(ungroup(filter(group_by(mutate(df, idx = row_number()), 
##         SID), n() > 1)), idx)
## }
## <bytecode: 0x12cd74f50>
  • life is good — no duplicate SID

3.1.1.1 Anonymize

W24_M <-
  W24_M |> 
  select(student_id, everything(),
                -c(
                  SID,
                  Submission.ID,
                  First.Name,
                  Last.Name,
                  Email,
                  Lateness..H.M.S.,
                  Submission.Time,
                  View.Count, 
                  Submission.Count
                  )) 
W24_M <-
  W24_M |>
  rename_with(
    ~ paste0(
      "Q",
      sub("^X([0-9]+).*", "\\1", .x)
    ),
    matches("^X[0-9]+\\.\\.Question")
  )
W24_M
rm(list=c("W24_M_VA", "W24_M_VB"))

3.2 Final

W24_F_VA |> count(Status)
W24_F_VB |> count(Status)
W24_F_VA <- 
  W24_F_VA |> 
  filter(Status == "Graded") |> 
  mutate(version = "A", exam = "Final", term = "W24")

W24_F_VB <-
  W24_F_VB |> 
  filter(Status == "Graded") |> 
  mutate(version = "B", exam = "Final", term = "W24")
W24_F <- bind_rows(W24_F_VA, W24_F_VB)
rm(list=c("W24_F_VA", "W24_F_VB"))
W24_F |> check_sid()
  • perfect!
find_duplicates(W24_F)
## integer(0)
  • perfect!

3.2.1 Combine Cohort

W24_F <-
  W24_F |>
  left_join(
    W24_M_dictionary |>
      distinct(SID, student_id),
    by = "SID"
  )
W24_F |>
  count(is.na(student_id))
  • notice 6 students didnt take the final

3.2.1.1 Anonymize

W24_F <-
  W24_F |>
  select(
    student_id,
    everything(),
    -c(
      Status,
      SID,
      Submission.ID,
      First.Name,
      Last.Name,
      Email,
      Lateness..H.M.S.,
      Submission.Time,
      View.Count,
      Submission.Count
    )
  ) |>
  rename_with(
    ~ paste0(
      "Q",
      sub("^X([0-9]+).*", "\\1", .x)
    ),
    matches("^X[0-9]+\\.\\.Question")
  )
W24 <-
  bind_rows(
    W24_M,
    W24_F
  )
W24 <- W24 |> mutate(unidentified=FALSE)
rm(list=c("W24_M", "W24_F"))
bind_rows(F23, W24)
  • accidentally forgot to put unidentified binary indicator
bind_rows(F23, W24) |>
  filter(is.na(unidentified)) |>
  mutate(
    student_id_type = grepl("^student_[0-9]+$", student_id)
  ) |>
  count(student_id_type)
  • okay, so all are identified
cohort <- bind_rows(F23, W24)
cohort <-
  bind_rows(F23, W24) |>
  mutate(
    unidentified = replace_na(unidentified, FALSE)
  )
cohort |> count(unidentified)
  • fantastic

4 Spring Cohort/Class

S24_F_VA |> count(Status == "Graded")
S24_F_VA |> summarize(pct=mean(Status == "Graded"))
S24_F_VB |> count(Status == "Graded")
S24_F_VB |> summarize(pct=mean(Status == "Graded"))
  • many ungraded
S24_M |> select(contains("Q")) |> select(1:4)
  • unfortunately this one doesnt fit the same pattern of col-names so coding is difficult

  • However note the ability to view typical student responses

rm(list=ls())

S24_M
S24_F_VA |> colnames()
##  [1] "First.Name"                 "Last.Name"                 
##  [3] "SID"                        "Email"                     
##  [5] "Sections"                   "Total.Score"               
##  [7] "Max.Points"                 "Status"                    
##  [9] "Submission.ID"              "Submission.Time"           
## [11] "Lateness..H.M.S."           "View.Count"                
## [13] "Submission.Count"           "X1..Question.1..1.0.pts."  
## [15] "X2..Question.2..1.0.pts."   "X3..Question.3..1.0.pts."  
## [17] "X4..Question.4..1.0.pts."   "X5..Question.5..1.0.pts."  
## [19] "X6..Question.6..1.0.pts."   "X7..Question.7..1.0.pts."  
## [21] "X8..Question.8..1.0.pts."   "X9..Question.9..1.0.pts."  
## [23] "X10..Question.10..1.0.pts." "X11..Question.11..1.0.pts."
## [25] "X12..Question.12..1.0.pts." "X13..Question.13..1.0.pts."
## [27] "X14..Question.14..1.0.pts." "X15..Question.15..1.0.pts."
## [29] "X16..Question.16..1.0.pts." "X17..Question.17..1.0.pts."
## [31] "X18..Question.18..1.0.pts." "X19..Question.19..1.0.pts."
## [33] "X20..Question.20..1.0.pts." "X21..Question.21..1.0.pts."
## [35] "X22..Question.22..1.0.pts." "X23..Question.23..1.0.pts."
## [37] "X24..Question.24..1.0.pts." "X25..Question.25..1.0.pts."
## [39] "X26..Question.26..1.0.pts." "X27..Question.27..1.0.pts."
## [41] "X28..Question.28..1.0.pts." "X29..Question.29..1.0.pts."
## [43] "X30..Question.30..1.0.pts." "X31..Question.31..1.0.pts."
## [45] "X32..Question.32..1.0.pts."