En un marco de datos grande ("myfile") con cuatro columnas, tengo que agregar una quinta columna con valores condicionalmente basados en las primeras cuatro columnas.
Prefiere respuestas con dplyr
y mutate
, principalmente debido a su velocidad en grandes conjuntos de datos.
Mi marco de datos se ve así:
V1 V2 V3 V4
1 1 2 3 5
2 2 4 4 1
3 1 4 1 1
4 4 5 1 3
5 5 5 5 4
...
Los valores de la quinta columna (V5) se basan en algunas reglas condicionales:
if (V1==1 & V2!=4) {
V5 <- 1
} else if (V2==4 & V3!=1) {
V5 <- 2
} else {
V5 <- 0
}
Ahora quiero usar la mutate
función para usar estas reglas en todas las filas (para evitar bucles lentos). Algo como esto (y sí, ¡sé que no funciona de esta manera!):
myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
else if (V2==4 & V3!=1){V5 = 2}
else {V5 = 0})
Este debería ser el resultado:
V1 V2 V3 V4 V5
1 1 2 3 5 1
2 2 4 4 1 2
3 1 4 1 1 0
4 4 5 1 3 0
5 5 5 5 4 0
¿Cómo hacer esto dplyr
?
NA
, (NaN, +Inf, -Inf
)?dplyr
, entonces lo utilizaría mejordata.table
.Respuestas:
Prueba esto:
myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))
dando:
V1 V2 V3 V4 V5 1 1 2 3 5 1 2 2 4 4 1 2 3 1 4 1 1 0 4 4 5 1 3 0 5 5 5 5 4 0
o esto:
myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))
dando:
V1 V2 V3 V4 V5 1 1 2 3 5 1 2 2 4 4 1 2 3 1 4 1 1 0 4 4 5 1 3 0 5 5 5 5 4 0
Nota
Sugiero que obtenga un nombre mejor para su marco de datos. myfile hace que parezca que tiene un nombre de archivo.
Anteriormente utilizó esta entrada:
myfile <- structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L, 5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L )), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1", "2", "3", "4", "5"))
Actualización 1 Desde que se publicó originalmente, dplyr ha cambiado
%.%
para%>%
modificar la respuesta en consecuencia.La actualización 2 dplyr ahora tiene lo
case_when
que proporciona otra solución:myfile %>% mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1, V2 == 4 & V3 != 1 ~ 2, TRUE ~ 0))
fuente
ifelse
declaraciones:myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, 0), V5 = ifelse(V2 == 4 & V3 != 1, 2, V5))
Con
dplyr 0.7.2
, puede utilizar lacase_when
función muy útil :x=read.table( text="V1 V2 V3 V4 1 1 2 3 5 2 2 4 4 1 3 1 4 1 1 4 4 5 1 3 5 5 5 5 4") x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1, x$V2==4 & x$V3!=1 ~ 2, TRUE ~ 0)
Expresado con
dplyr::mutate
, da:x = x %>% mutate( V5 = case_when( V1==1 & V2!=4 ~ 1, V2==4 & V3!=1 ~ 2, TRUE ~ 0 ) )
Tenga en cuenta que
NA
no se tratan de forma especial, ya que puede ser engañoso. La función regresaráNA
solo cuando no coincida ninguna condición. Si pones una línea conTRUE ~ ...
, como hice en mi ejemplo, el valor de retorno nunca seráNA
.Por lo tanto, debe indicar expresamente
case_when
que coloqueNA
donde pertenece agregando una declaración comois.na(x$V1) | is.na(x$V3) ~ NA_integer_
. Sugerencia: ¡ladplyr::coalesce()
función puede ser realmente útil aquí a veces!Además, tenga en cuenta que
NA
solo generalmente no funciona, usted tiene que poner especialNA
los valores:NA_integer_
,NA_character_
oNA_real_
.fuente
Parece que
derivedFactor
elmosaic
paquete fue diseñado para esto. En este ejemplo, se vería así:library(mosaic) myfile <- mutate(myfile, V5 = derivedFactor( "1" = (V1==1 & V2!=4), "2" = (V2==4 & V3!=1), .method = "first", .default = 0 ))
(Si desea que el resultado sea numérico en lugar de un factor, envuelva el
derivedFactor
con unas.numeric
.)Tenga en cuenta que la
.default
opción combinada con.method = "first"
establece la condición "else"; este enfoque se describe en el archivo de ayuda dederivedFactor
.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, todavía no lo he investigado. Ver blog.rstudio.org/2016/06/27/dplyr-0-5-0mosaic::derivedFactor
familia de funciones son muy lentas. Si averigua por qué, responda mi SO pregunta al respecto: stackoverflow.com/questions/33787691/… . Me alegra ver en su otro comentario quedplyr::case_when
es más rápido, tendré que cambiar a eso.