Caitlin Caitlin - 10 months ago 45
R Question

Trying to convert a column of number grades to letter grades within a function

I am trying to write a grade calculation function. The function is supposed to:

  • Alert the user if the read in file type is not a data frame or matrix

  • Assign 0 to any empty values in the data frame or matrix

  • Calculate the final grade percentage by finding the weighted average of 8 homeworks (each worth 5 points), 5 quizzes (each worth 10 points), and 3 exams (each worth 100 points)

  • Convert the final grades to letter grades, with any grades in the range [90,100] being an A, [80,90) being a B, [70,80) being a C, [60,70) being a D, and [0,60) being an F.

  • Print messages allerting the user as to how the grade was calculated

  • Print all columns of the original matrix or data frame, with columns for the final number and final letter grades appended to the end (I only need to print the data for the first 3 students).

I've written the following code:

grades = read.table('',
header=T, sep=',', fill=TRUE)

grade_cal = function (graded, hw_w, quiz_w, exam_w){

if(!is.matrix(grades) & !{
stop('Grades must be in a data frame or a matrix.')

grades[] = 0;


grades$Letter = {
if (grades$Final >=90) {
grade = "A"
else if (grades$Final >=80){
grade = "B"
else if(grades$Final >=70){
grade = "C"
else if(grades$Final >=60){
grade = "D"
else {grade = "F"}

message("There are 8 HWs, 4 Quizzes and 3 Exams Calculated for each person.")
message("Weights are", hw_w, ",", quiz_w, ",", exam_w, "respectively for HW, Quiz and Exam.")


grade_cal(graded= grades, 0.2, 0.2, 0.2)

This code currently returns the following "Error in
(grades, Final) : object 'Final' not found". When I remove the section to try to calculate the letter grade, my code runs so that is where the error is (I only included the rest of the code to give some background). How can I fix the letter calculation section to make it run? Thanks

Edit: Upon changing grades[Final] to grades$Final, I now get the following warning: "In if (grades$Final >= 90) { :
the condition has length > 1 and only the first element will be used"

Answer Source

As pointed out by @Haboryme, if else as you use it only works for single values, and not for vectors. Sticking with your (rather cumbersome) requirement of using the if-else logic, this might do it:

grades$Letter = ifelse(grades$Final >=90, "A",
                   ifelse(grades$Final >=80, "B",
                          ifelse(grades$Final >=70, "C", 
                                 ifelse(grades$Final >=60, "D", "F"))))

Alternatively, you could write a for loop (as an example of bad, bad coding):

grades$Letter = ""
for (i in seq_along(grades$Final)) {
   grades$Letter[i] = {
      if (grades$Final[i] >=90) {
      else if (grades$Final[i] >=80){
      else if(grades$Final[i] >=70){
      else if(grades$Final[i] >=60){
      else {"F"}

This second option is especially bad because it makes you read a lot of code before you can understand what is going on, and because there are already some nice vectorized solutions in R already as pointed by others in this thread.