Crear una columna con valores agrupados basados ​​en otra columna

Estoy seguro de que esto se ha preguntado antes, pero no sé qué buscar, así que me disculpo por adelantado.

Digamos que tengo el siguiente dataframe:

grades <- data.frame(a = 1:40, b = sample(45:100, 40)) 

Utilizando deplyr, quiero crear una nueva variable que indique la calificación que recibió el alumno, de acuerdo con los siguientes criterios: 90-100 = excelente, 80-90 = muy bueno, etc.

Pensé que podría usar lo siguiente para obtener ese resultado con nestling ifelse () dentro de mutate ():

 grades %>% mutate(ifelse(b >= 90, "excellent"), ifelse(b >= 80 & b = 70 & b = 60 & b < 70, "poor", "fail")) 

Esto no funciona, ya que aparece el mensaje de error “falta el argumento no, sin valor predeterminado”). Pensé que el “no” sería el “fracaso” al final, pero obviamente estoy obteniendo la syntax incorrecta.

Puedo obtener esto para obtener si primero filtro los datos originales de forma individual, y luego invoco ifelse, de la siguiente manera:

 a % filter( b >= 90) %>% mutate(final = ifelse(b >= 90, "excellent")) 

y el rbind a, b, c, etc. Obviamente, no es así como quiero hacerlo, pero quería entender la syntax de ifelse (). Supongo que esto último funciona porque no hay ningún valor que no cumpla los criterios, pero todavía no puedo encontrar la manera de hacerlo funcionar cuando hay más de un ifelse.

Defina los vectores con los niveles y las tags y luego use cut en la columna b :

 levels <- c(-Inf, 60, 70, 80, 90, Inf) labels <- c("Fail", "Poor", "fair", "very good", "excellent") grades %>% mutate(x = cut(b, levels, labels = labels)) abx 1 1 66 Poor 2 2 78 fair 3 3 97 excellent 4 4 46 Fail 5 5 89 very good 6 6 57 Fail 7 7 80 fair 8 8 98 excellent 9 9 100 excellent 10 10 93 excellent 11 11 59 Fail 12 12 51 Fail 13 13 69 Poor 14 14 75 fair 15 15 72 fair 16 16 48 Fail 17 17 74 fair 18 18 54 Fail 19 19 62 Poor 20 20 64 Poor 21 21 88 very good 22 22 70 Poor 23 23 85 very good 24 24 58 Fail 25 25 95 excellent 26 26 56 Fail 27 27 65 Poor 28 28 68 Poor 29 29 91 excellent 30 30 76 fair 31 31 82 very good 32 32 55 Fail 33 33 96 excellent 34 34 83 very good 35 35 61 Poor 36 36 60 Fail 37 37 77 fair 38 38 47 Fail 39 39 73 fair 40 40 71 fair 

O usando data.table:

 library(data.table) setDT(grades)[, x := cut(b, levels, labels)] 

O simplemente en la base R:

 grades$x <- cut(grades$b, levels, labels) 

Nota

Después de analizar de cerca su enfoque inicial, noté que debería incluir right = FALSE en la llamada de cut , porque, por ejemplo, 90 puntos deberían ser "excelentes", no solo "muy buenos". Por lo tanto, se usa para definir dónde se debe cerrar el intervalo (izquierda o derecha) y el valor predeterminado está a la derecha, que es ligeramente diferente del enfoque inicial de OP. Entonces en dplyr, sería entonces:

 grades %>% mutate(x = cut(b, levels, labels, right = FALSE)) 

y en consecuencia en las otras opciones.

Todos los ifelse s necesitan estar uno dentro del otro. Prueba esto:

 mutate(ifelse(b >= 90, "excellent", ifelse(b >= 80 & b < 90, "very_good", ifelse(b >= 70 & b < 80, "fair", ifelse(b >= 60 & b < 70, "poor", "fail"))))) 
 grades$c = grades$b # creating a new column #and filling in the grades grades$c[grades$c >= 90] = "exellent" grades$c[grades$c <= 90 & grades$c >= 80] = "very good" grades$c[grades$c <= 80 & grades$c >= 70] = "fair" grades$c[grades$c <= 70 & grades$c >= 60] = "poor" grades$c[grades$c <= 60] = "fail"