-2

I've been trying to convert 538's poll 'grading' system (A+ to F- much like school grades) into a series of numbers using if-else statements and functions as outlined

here.

I have also attempted using the switch() function, but nothing has worked. Any thoughts on how to get this done?

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
Raruther
  • 1
  • 1
  • 3
    *"but nothing has worked."* Please edit your post to include reproducible sample data and the code you've tried. Also include your expected output. Be specific, "nothing has worked" doesn't tell us anything. – Maurits Evers Mar 05 '19 at 00:39
  • 1
    Put your (short) sample code into the question instead of adding links to somewhere. – U. Windl Mar 05 '19 at 00:42
  • From the picture of your code, it seems like you are using `if{} else{}` when you need `ifelse()`. But since you're using `dplyr` already, look into `case_when`. See the examples at the bottom of `?case_when` – Gregor Thomas Mar 05 '19 at 00:49
  • 1
    A `match` operation would be simpler, faster, and easier to maintain. – IRTFM Mar 05 '19 at 01:28
  • In the future, please consider [this](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) to better formulate your question. – NelsonGon Mar 05 '19 at 03:08

4 Answers4

2

It's cleaner to do a left join with a lookup data.frame that contains the mappings grade to gradenumber. That way you avoid the many ifelse statements.

Here is a reproducible example:

# Grades
grades <- paste0(rep(LETTERS[c(1:4,6)], each = 3), c("+", "", "-"))[-c(1, 13)]
grades
#[1] "A"  "A-" "B+" "B"  "B-" "C+" "C"  "C-" "D+" "D"  "D-" "F"  "F-"

Generate lookup data.frame

lookup <- data.frame(
    grade = grades,
    gradenumber = length(grades):1)

We now generate some sample data PollsFiltered and then left_join the data with lookup on grade.

set.seed(2018)
PollsFiltered <- data.frame(
    grade = sample(grades, 20, replace = T)
)

library(dplyr)
PollsFiltered %>%
    left_join(lookup, by = "grade")
#   grade gradenumber
#1     B-           9
#2      C           7
#3      A          13
#4     B+          11
#5      C           7
#6      B          10
#7     C-           6
#8     A-          12
#9     F-           1
#10    C-           6
#11    C+           8
#12    D+           5
#13    F-           1
#14    D+           5
#15    D-           3
#16    D+           5
#17     B          10
#18    C-           6
#19     D           4
#20    D-           3
Maurits Evers
  • 49,617
  • 4
  • 47
  • 68
0

There is no need for ifelse, you could do the following:

df$numericGrade = NA
df$numericGrade[df$grade=="A"] = 13
df$numericGrade[df$grade=="A-"] = 12
df$numericGrade[df$grade=="B+"] = 11
df$numericGrade[df$grade=="C-"] = 6

For example:

df = data.frame(Name = c("John", "Mary", "Timmy", "Susan"), grade = c("B+", "A", "C-", "DNF"))

   Name grade
1  John    B+
2  Mary     A
3 Timmy    C-
4 Susan   DNF

applying the previous lines results in:

   Name grade numericGrade
1  John    B+           11
2  Mary     A           13
3 Timmy    C-            6
4 Susan   DNF           NA

Of course this takes one line for every case and my example is not complete.

Using Merge

Another option is to use merge. In this case you need to have another data frame with the grades conversion:

gradesDict = data.frame(letter = c("A", "A-", "B+", "C-"),
                        number = c(13, 12, 11, 6))

  letter number
1      A     13
2     A-     12
3     B+     11
4     C-      6

and then do:

df = merge(df, gradesDict, by.x = "grade", by.y = "letter", all.x = T)

  grade  Name number
1     A  Mary     13
2    B+  John     11
3    C- Timmy      6
4   DNF Susan     NA
R. Schifini
  • 9,085
  • 2
  • 26
  • 32
0

Another option using dplyr is to use the case_when statement as follows:

df$Num_grade <- NA
df <- mutate(df, Num_grade = case_when(
   grades == 'A' ~ 13,
   grades == 'A-' ~ 12,
   grades == 'B+' ~ 11,
   .
   .
   .
   grades == 'F-' ~ 1
))

Wich works a lot like several ifelse statements, but easier to understand in my opinion

0

Here's how to use match (building on the MCVE offered byt Maurits:

 grades <- paste0(rep(LETTERS[c(1:4,6)], each = 3), c("+", "", "-"))[-c( 13)] # keep A+
 PollsFiltered$nums <- match(PollsFiltered$grade, rev(grades) ) # F(1) to A+(14)

> head(PollsFiltered)
  grade nums
1     B   10
2    C+    8
3    A+   14
4    A-   12
5    C+    8
6     B   10
IRTFM
  • 258,963
  • 21
  • 364
  • 487