knitr::opts_chunk$set(
  echo = TRUE, 
  fig.width = 6, 
  fig.asp = 0.618, 
  out.width = "70%",
  fig.align = "center", 
  warning = FALSE, 
  message = FALSE
)
library(tidyverse)

Install examMarking package

This is done with

remotes::install_github("jonotuke/examMarking")

If you do not have the package remotes installed, then use

install.packages("remotes")

Libraries

library(tidyverse)
library(examMarking)

Get data

There is some in-built data to play with. This is the anonomised SMI 2018 data.

data("SMI_2018_marks")
SMI_2018_marks

This is the form that you get from canvas. We have also added the marks for the exam questions columns Q1 to Q6.

Canvas sets any mark that the students did not submit as NA, and exemptions as EX.

SMI_2018_marks %>% 
  filter(str_detect(`Assignment 1 (77417)`, "EX"))

Cleaning the data

Renaming columns

With this data, we have 5 assignments, then the project, then 8 online quizzes, and finally the exam questions. We will rename this to make cleaning easier.

colnames(SMI_2018_marks)  <- c("ID", 
                               str_c("A", 1:5), 
                               "P", 
                               str_c("OQ0", 1:8), 
                               str_c("Q", 1:6))

Dealing with exemptions and missing

We can convert missing to zero and EX to NA with the following:

SMI_2018_marks
SMI_2018_marks  <- 
  SMI_2018_marks %>% 
  clean_marks_df("^A") %>% 
  clean_marks_df("^P$") %>% 
  clean_marks_df("^OQ") %>% 
  clean_marks_df("^Q")

Note that we can use regular expressions to give the columns that need cleaning.

Summarising the data

Get proportions

For each assessment piece, we can calculate the proportions. This assumes that there is a row with the totals. In canvas, this is the first row.

SMI_2018_marks <- 
  SMI_2018_marks %>% 
  get_prop_df("^A", total_row = 1) %>% # Assignments
  get_prop_df("^P$", total_row = 1) %>% # project
  get_prop_df("^OQ", total_row = 1) # Online quizzes
SMI_2018_marks

Get totals

For the exam, we need to exam total, we obtain this by adding the question columns

SMI_2018_marks$E  <- 
  SMI_2018_marks %>% 
  get_total("^Q")

And then convert this to a proportion and the exam questions.

SMI_2018_marks  <- 
  SMI_2018_marks %>% 
  get_prop_df("^E$|^Q", total_row = 1)
SMI_2018_marks

Get means

For each assessment part - assignments and online quizzes, we get the average proportion

SMI_2018_marks$A  <- 
  SMI_2018_marks %>% 
  get_mean("^A")
SMI_2018_marks$OQ  <- 
  SMI_2018_marks %>% 
  get_mean("^OQ")

Convert to percent of course

So we now have the proportion for the various parts of the course. We need to convert this to proportion of the assessment.

SMI_2018_marks %>% 
  select(ID, A, OQ, P, E)
SMI_2018_marks  <- 
  SMI_2018_marks %>% 
  mutate(
    A = A * 15, 
    OQ = OQ * 5,
    P = P * 10, 
    E = E * 70
  )
SMI_2018_marks %>% 
  select(ID, A, OQ, P, E)

Get course total

SMI_2018_marks$Total  <- 
  SMI_2018_marks %>% 
  get_total("^A$|^OQ$|^P$|^E$")
SMI_2018_marks %>% 
  select(ID, A, OQ, P, E, Total)

Get grades

SMI_2018_marks$grade  <- get_grades(SMI_2018_marks$Total, trace = TRUE)
SMI_2018_marks %>% 
  select(ID, A, OQ, P, E, Total, grade)

Finally we can get rid of the totals column

SMI_2018_marks  <- SMI_2018_marks[-1, ]
SMI_2018_marks

Examine the course

Grades

We can get a summary of each grade for the grade roster summary with

get_grade_summary(SMI_2018_marks$grade)

Plot assessment

First we can look at individual students breakdown for each section of the course with the plot_assessment() plot.

SMI_2018_marks %>% 
  plot_assessment(RE = "^A$|^OQ$|^P$|^E$", 
                  name = ID, 
                  grade = grade)

Exam plot

To assess if the exam worked, then we can look at the separation for each question and also the average mark.

SMI_2018_marks %>% 
  profile_plot(RE = "^Q", 
               grade = grade)

This can also be used for other parts of the course

SMI_2018_marks %>% 
  profile_plot(RE = "^A\\d", 
               grade = grade)

Normalisation

Glonek function

This normalisation works on the logit scale

tibble(raw = 0:100, 
           norm = norm_glonek(raw, a = 0.5, b = 2)) %>% 
  ggplot(aes(raw, norm)) + 
  geom_point()

Applying this to the SMI dataset we get

SMI_2018_marks  <- 
  SMI_2018_marks %>% 
  mutate(norm = norm_glonek(Total, a = 0.2, b = 2))

Comparing norm

We can compare the raw and norm

norm_compare(SMI_2018_marks$Total, SMI_2018_marks$norm)

McCann spike

df  <- tibble(
  total = 1:100
)
df  <- df %>% 
  mutate(norm_total = add_mccann_spike(total))
df %>% ggplot(aes(total, norm_total)) + geom_point()
norm_compare(df$total, df$norm_total)

Grade rosters

The function fill_grade_roster() will put the marks into the blank grade roster.

For this example, we have a grade roster

grade_roster  <- read_lines("../inst/grade_example.csv")
grade_roster

Also we need the totals to be rounded

SMI_2018_marks  <- 
  SMI_2018_marks %>% 
  mutate(Total = round(Total))
fill_grade_roster(SMI_2018_marks$ID, SMI_2018_marks$Total, 
                  infile = "../inst/grade_example.csv", 
                  outfile = "../inst/example_output.csv")
grade_roster  <- read_lines("../inst/example_output.csv")
grade_roster

Open, check and save a correct CSV form.

Auditing

This function asked for by Barry will run a audit on all students with a few marks of a boundary. The default is one mark for the boundaries 50, 65, 75, and 85.

run_audit(SMI_2018_marks, Total)

Exam report

Not that you may have to restart RStudio to get this after installing hte package.

There is a template of a exam report that can be obtained from the Rmarkdown menu:

knitr::include_graphics("rmarkdown.png")


jonotuke/examMarking documentation built on Nov. 26, 2019, 3:48 p.m.