Another gradeR Vignette
Written on May 22nd , 2022 by Christopher KinsonTaylor Brown developed the gradeR package for R. His original vignette explains foundations of using the package. I am writing this vignette to supplement aspects of the original because I had questions. I explored answers for my questions and thought it might be useful to others.
The big picture is that the gradeR package can be thought of as a localized autograder (automatic grading of .R files on one’s own computer). With some additional work and licenses, it can be connected to online systems such as Gradescope and GitHub. This can make it a versatile and powerful tool, especially for large courses that incorporate computing or programming technology with or without teaching assistants, course assistants, or hourly employees.
Let’s take a look at some of the questions I had while learning about this helpful package. If you want to follow along and try out these ideas yourself, you can download the another-gradeR-vignette.zip, extract it, and set your working directory in R or RStudio to “another-gradeR-vignette”.
setwd("~/another-gradeR-vignette")
Can students submit .Rmd files?
Yes. gradeR automatically grades R code within .R or
.r files. As someone who enjoys using notebooks and R markdown for
reproducibility and checking student answers to questions about data
wrangling and programming, I did not want to give up using .Rmd files
for my courses. After searching online for possibilities, there was one:
knitr::purl()
. The purl()
function within the
knitr package is interesting
in that it can convert .Rmd documents to .R documents through extracting
the .R code from within that .Rmd file. It searches for R code chunks
and removes all the code chunk scripting to keep the raw R code. It’s
remarkable!
If you have created a main gradebook (see
course-semester-gradebook.csv
) file for storing students’
grades in your course, then you can loop through those students in order
to extract the R code from their .Rmd files.
# import course-semester-gradebook.csv (official one for the course)
library(tidyverse)
netids <- read_csv("course-staff-resources/course-semester-gradebook.csv") %>%
select(NetID)
# extract R code from .Rmd files
for (i in 1:nrow(netids)){
knitr::purl(input = paste0("student-homework/student-homework00/homework00-", netids[i,], ".Rmd"),
output = paste0("student-homework/student-homework00/homework00-", netids[i,], ".R"),
documentation = 0)
}
Above, I am repeating the extraction of R code chunks for each
student in my roster. The netids
object is a vector of
student IDs for students in your roster; only these students’ files
exist in your submission directory. The input=
and
output=
arguments refer to file locations, while the
documentation=
argument controls what to do with the text
and markdown syntax that is not R code. See the help
documentation for details on these purl()
arguments.
Can the instructor compute the total score per student?
Yes! While the original vignette describes using gradeR
interactively, I know that it will be difficult to remember the flow of
code each time I need to compute grades for all students per assignment.
Thus, I will suggest a separate R file (see
homework00-gradeR-script.R
) that contains all the code
mentioned in the original’s interactive section. One thing Brown didn’t
mention was what to do now that the grades
object has been
created. Are we done after that?
The grades
object (created within
homework00-gradeR-script.R
) is structured as \(n\) rows and \(p\) columns, where \(n\) represents the number of .R files
within the submission directory, and \(p\) represents the number of
test_that()
functions used in the
homework00-instructor-solutions.R
file. The values in those
\(p\) columns are either 1 (correct) or
0 (incorrect). In a typical assignment, I would likely setup the
test_that()
functions to correspond to a unique
problem/question in the assignment with names that make sense. In this
way, we know exactly which column is referring to which problem/question
in the assignment and its point value. Then after all problem/questions
are automatically graded, we can run a row sum on that
grades
object. Since I do teach about coding in the
tidyverse, I’ll use tidyverse code in this row sum example.
library(tidyverse)
# to add specific columns for easier grade distribution
grades2 <- as_tibble(grades) %>%
rowwise() %>%
mutate(TotalPoints = sum(c_across(problem01:problem06)))
grades2
## # A tibble: 3 × 8
## # Rowwise:
## id problem01 problem02 problem03 problem04 problem05 problem06 TotalPoints
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 stude… 1 1 0 0 1 1 4
## 2 stude… 1 1 1 1 1 1 6
## 3 stude… 1 0 1 0 1 1 4
Recently, I learned that the rowwise()
function operates
like the group_by()
function in that it doesn’t do anything
explicitly. It works behind-the-scenes storing how the process for the
next data wrangling steps will affect the tibble currently in the
pipeline.
What kinds of problems/questions can I write?
Given that test_that()
requires R code for the automatic
grading, it might seem limiting in the kinds of questions we as
instructors may want to ask students in assignments. But maybe this just
means we need to be more creative. Seems to me that any type or style of
question can be written and automatically graded.
Multiple choice and True/False
An example of a multiple choice problem/question is Problem
#6 in the
homework00-instructor-solutions.R
. An example of a
True/False problem/question is Problem #2.
Problem: Choose a single letter that represents the most correct choice, then create an R vector named prob06 with the lower case letter chosen in quotes. For example,
prob06 <- "e"
. This R code should be written in the code chunk of the Answer section below. This code chunk should be executable and able to be evaluated.
- Question: In which of the following cases is the file name in bold Homework01Kinson2 written?
pascal case
snake case
camel case
kebab case
none of these
Multiple answer
An example of a multiple answer problem/question is Problem
#4 in the
homework00-instructor-solutions.R
Problem: Choose all letters that represent the correct choice(s), then create an R vector named prob04 with the lower case letter(s) chosen in quotes. If choosing more than one lower case letter, the elements in the vector prob04 need to be separated by a comma. For example,
prob04 <- c("e","f")
. This R code should be written in the code chunk of the Answer section below. This code chunk should be executable and able to be evaluated.
- Question: Which of the following cases are discussed in this course?
pascal case
snake case
camel case
kebab case
none of these
Fill-in-the-blank and Exact answer
I omit a specific fill-in-the-blank problem/question, but I recognize this style as an exact answer problem/question. Examples of exact answer problems/questions include: Problems #1 and #3.
Problem: Create an R vector named prob01 that contains the following 3 elements (in this order): first name, last name, and netID with each element enclosed in quotes. For example,
prob01 <- c("Chris","Kinson", "kinson2")
. This R code should be written in the code chunk of the Answer section below.
Short answer (1 complete sentence) and Long answer (3 or more complete sentences)
I omit a specific short answer problem/question, but I recognize this style as a version of a long answer problem/question. An example of a long answer problem/question is Problem #5.
Problem: Create a character-type vector of length 1 in R named prob05 with at least two complete sentences that answer the following question(s). This R code should be written in the code chunk of the Answer section below. This code chunk should be executable and able to be evaluated.
- Question: In your own words, describe the best way(s) for you to learn new things. What specific things do you require for you to retain information? How frequently do you refer back to notes or textbooks when learning new information?
Can we connect this to GitHub?
Yes, especially if you are the owner of a GitHub organization (org for short), where your students are members of that org. In this sense, GitHub can be considered as your Learning Management System (LMS). All that’s needed is to connect your local machine to your GitHub account such that it is authorized for your account. Then run code from the command line.
We can even use R script to run git operations such as:
for (i in 1:nrow(netids)){
url <- paste0("git clone ", "https://github.com/course-semester/", netids[i], ".git",
" ", netids[i])
shell(url)
}
I hope to share more on GitHub as an LMS at a later date.