¿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
ifelse
Añadido - if_else: tenga en cuenta que en dplyr 0.5 hay una
if_else
función definida, por lo que una alternativa sería reemplazarifelse
conif_else
; sin embargo, tenga en cuenta que dado queif_else
es más estricto queifelse
(ambas partes de la condición deben tener el mismo tipo), entoncesNA
en ese caso tendría que ser reemplazado porNA_real_
.Agregado - case_when Desde que se publicó esta pregunta, dplyr ha agregado,
case_when
por 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_if
al 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
g
correctamente. No hay copia deg
hecho, 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_fun
está 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$g
que ya está asignado?), El resultado también se propaga de regresoans1
y, por lo tanto, podría ( Si optimizador de R estime necesario? No estoy seguro de esto ...) evitar otra copia queDPLYR_fun
yBASE_fun
es necesario hacer?data.table
solución es excelente, y la usodata.table
donde 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_when
que ofrece un if vectorizado. La sintaxis es un poco extraña en comparación con el hecho demosaic:::derivedFactor
que 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 == 1
dentrocase_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_when
tambié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
derivedFactor
función delmosaic
paquete 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
derivedFactor
unaas.numeric
llamada).derivedFactor
también se puede usar para un número arbitrario de condicionales.fuente
.asFactor = F
opción o usando la función (similar)derivedVariable
en el mismo paquete.recode
desde dplyr 0.5 hará esto. Sin embargo, aún no lo he investigado. Ver blog.rstudio.org/2016/06/27/dplyr-0-5-0case_when
ahora 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