¿Se puede usar la mutación cuando la mutación es condicional (dependiendo de los valores de ciertos valores de columna)?
Este ejemplo ayuda a mostrar lo que quiero decir.
structure(list(a = c(1, 3, 4, 6, 3, 2, 5, 1), b = c(1, 3, 4,
2, 6, 7, 2, 6), c = c(6, 3, 6, 5, 3, 6, 5, 3), d = c(6, 2, 4,
5, 3, 7, 2, 6), e = c(1, 2, 4, 5, 6, 7, 6, 3), f = c(2, 3, 4,
2, 2, 7, 5, 2)), .Names = c("a", "b", "c", "d", "e", "f"), row.names = c(NA,
8L), class = "data.frame")
a b c d e f
1 1 1 6 6 1 2
2 3 3 3 2 2 3
3 4 4 6 4 4 4
4 6 2 5 5 5 2
5 3 6 3 3 6 2
6 2 7 6 7 7 7
7 5 2 5 2 6 5
8 1 6 3 6 3 2
Esperaba encontrar una solución a mi problema usando el paquete dplyr (y sí, sé que este código no debería funcionar, pero supongo que aclara el propósito) para crear una nueva columna g:
library(dplyr)
df <- mutate(df,
if (a == 2 | a == 5 | a == 7 | (a == 1 & b == 4)){g = 2},
if (a == 0 | a == 1 | a == 4 | a == 3 | c == 4) {g = 3})
El resultado del código que estoy buscando debería tener este resultado en este ejemplo particular:
a b c d e f g
1 1 1 6 6 1 2 3
2 3 3 3 2 2 3 3
3 4 4 6 4 4 4 3
4 6 2 5 5 5 2 NA
5 3 6 3 3 6 2 NA
6 2 7 6 7 7 7 2
7 5 2 5 2 6 5 2
8 1 6 3 6 3 2 3
¿Alguien tiene una idea sobre cómo hacer esto en dplyr? Este marco de datos es solo un ejemplo, los marcos de datos con los que estoy tratando son mucho más grandes. Debido a su velocidad, traté de usar dplyr, pero ¿quizás hay otras formas mejores de manejar este problema?

dplyr::case_when()es mucho más claro que unifelse,Respuestas:
Utilizar
ifelseAñadido - if_else: tenga en cuenta que en dplyr 0.5 hay una
if_elsefunción definida, por lo que una alternativa sería reemplazarifelseconif_else; sin embargo, tenga en cuenta que dado queif_elsees más estricto queifelse(ambas partes de la condición deben tener el mismo tipo), entoncesNAen ese caso tendría que ser reemplazado porNA_real_.Agregado - case_when Desde que se publicó esta pregunta, dplyr ha agregado,
case_whenpor lo que otra alternativa sería:Agregado - aritmética / na_if Si los valores son numéricos y las condiciones (excepto el valor predeterminado de NA al final) son mutuamente excluyentes, como es el caso en la pregunta, entonces podemos usar una expresión aritmética de manera que cada término se multiplique por el resultado deseado usando
na_ifal final para reemplazar 0 con NA.fuente
NA, quiero que las filas que no cumplen con las condiciones permanezcan igual?mutate(g = ifelse(condition1, 2, ifelse(condition2, 3, g))Dado que solicita otras formas mejores de manejar el problema, aquí hay otra forma de usar
data.table:Tenga en cuenta que el orden de las declaraciones condicionales se invierte para obtener
gcorrectamente. No hay copia deghecho, incluso durante la segunda asignación, se reemplaza en el lugar .En datos más grandes, esto tendría un mejor rendimiento que el uso anidado
if-else, ya que puede evaluar los casos 'sí' y 'no' , y la anidación puede ser más difícil de leer / mantener en mi humilde opinión.Aquí hay un punto de referencia en datos relativamente más grandes:
No estoy seguro de si esta es una alternativa que había pedido, pero espero que ayude.
fuente
DT_funestá modificando su entrada en el lugar, el punto de referencia podría no ser del todo justo, además de no recibir la misma entrada desde la segunda iteración hacia adelante (¿qué podría afectar el tiempo yaDT$gque ya está asignado?), El resultado también se propaga de regresoans1y, por lo tanto, podría ( Si optimizador de R estime necesario? No estoy seguro de esto ...) evitar otra copia queDPLYR_funyBASE_funes necesario hacer?data.tablesolución es excelente, y la usodata.tabledonde sea que realmente necesite velocidad para las operaciones en tablas y no quiero llegar hasta C ++. ¡Sin embargo, requiere tener mucho cuidado con las modificaciones en el lugar!dplyr ahora tiene una función
case_whenque ofrece un if vectorizado. La sintaxis es un poco extraña en comparación con el hecho demosaic:::derivedFactorque no puede acceder a las variables en la forma estándar dplyr, y necesita declarar el modo de NA, pero es considerablemente más rápido quemosaic:::derivedFactor.EDITAR: Si está utilizando
dplyr::case_when()desde la versión 0.7.0 anterior del paquete, entonces necesita preceder los nombres de las variables con '.$' (por ejemplo, escribir.$a == 1dentrocase_when).Punto de referencia : para el punto de referencia (reutilizando funciones de la publicación de Arun) y reduciendo el tamaño de la muestra:
Esto da:
fuente
case_whentambién podría escribirse como:df %>% mutate(g = with(., case_when(a %in% c(2,5,7) | (a==1 & b==4) ~ 2L, a %in% c(0,1,3,4) | c==4 ~ 3L, TRUE ~ NA_integer_))).$en la nueva versión de dplyrLa
derivedFactorfunción delmosaicpaquete parece estar diseñada para manejar esto. Usando este ejemplo, se vería así:(Si desea que el resultado sea numérico en lugar de un factor, puede completar
derivedFactorunaas.numericllamada).derivedFactortambién se puede usar para un número arbitrario de condicionales.fuente
.asFactor = Fopción o usando la función (similar)derivedVariableen el mismo paquete.recodedesde dplyr 0.5 hará esto. Sin embargo, aún no lo he investigado. Ver blog.rstudio.org/2016/06/27/dplyr-0-5-0case_whenahora es una implementación bastante limpia del caso de estilo SQL cuando:Usando dplyr 0.7.4
El manual: http://dplyr.tidyverse.org/reference/case_when.html
fuente