valores una operaciones mutate función funcion filtrar entre datos contar con columnas columna cambiar agrupar r dplyr

una - Realizar dplyr mutate en el subconjunto de columnas



función filter en r (4)

¿Me estoy perdiendo algo o funcionaría como se esperaba?

cols <- paste0("X", c(2,4)) dd %>% mutate(evensum = rowSums(.[cols]), evenmean = rowMeans(.[cols])) # id X1 X2 X3 X4 X5 evensum evenmean #1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380811 #2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439 #3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535 #4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478768

¿O está buscando específicamente una función personalizada para hacer esto?

No es exactamente lo que está buscando, pero si desea hacerlo dentro de una tubería, puede usar select explícitamente dentro de mutate esta manera:

dd %>% mutate(xy = select(., num_range("X", c(2,4))) %>% rowSums) # id X1 X2 X3 X4 X5 xy #1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 #2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 #3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 #4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535

Sin embargo, es un poco más complicado si desea aplicar varias funciones. Podrías usar una función auxiliar en la línea de (... no probado exhaustivamente ...):

f <- function(x, ...) { n <- nrow(x) x <- lapply(list(...), function(y) if (length(y) == 1L) rep(y, n) else y) matrix(unlist(x), nrow = n, byrow = FALSE) }

Y luego aplicarlo así:

dd %>% mutate(xy = select(., num_range("X", c(2,4))) %>% f(., rowSums(.), max(.))) # id X1 X2 X3 X4 X5 xy.1 xy.2 #1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.9888592 #2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.9888592 #3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.9888592 #4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.9888592

Tengo un data.frame como este (el conjunto de datos real tiene muchas más filas y columnas)

set.seed(15) dd <- data.frame(id=letters[1:4], matrix(runif(5*4), nrow=4)) # id X1 X2 X3 X4 X5 # 1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 # 2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 # 3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 # 4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125

Me gustaría poder escribir una declaración dplyr donde pueda seleccionar un subconjunto de columnas y mutarlas. (Estoy tratando de hacer algo similar a usar .SDcols en data.table).

Para un ejemplo simplificado, aquí está la función que me gustaría poder escribir para agregar columnas para las sumas y los medios de las columnas "X" pares mientras se conservan todas las demás columnas. La salida deseada usando la base R es

(cols<-paste0("X", c(2,4))) # [1] "X2" "X4" cbind(dd,evensum=rowSums(dd[,cols]),evenmean=rowMeans(dd[,cols])) # id X1 X2 X3 X4 X5 evensum evenmean # 1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380811 # 2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439 # 3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535 # 4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478768

pero quería usar una cadena tipo dplyr para hacer lo mismo. En el caso general, me gustaría poder usar cualquiera de las funciones auxiliares de select() como starts_with , ends_with , matches , etc. y cualquier función. Esto es lo que probé

library(dplyr) partial_mutate1 <- function(x, colspec, ...) { select_(x, .dots=list(lazyeval::lazy(colspec))) %>% transmute_(.dots=lazyeval::lazy_dots(...)) %>% cbind(x,.) } dd %>% partial_mutate1(num_range("X", c(2,4)), evensum=rowSums(.), evenmean=rowMeans(.))

Sin embargo, esto arroja un error que dice

Error in rowSums(.) : ''x'' must be numeric

Lo cual parece ser porque . parece estar refiriéndose a todo el marco de fecha en lugar del subconjunto seleccionado. (mismo error que rowSums(dd) ). Sin embargo, tenga en cuenta que esto produce la salida deseada

partial_mutate2 <- function(x, colspec) { select_(x, .dots=list(lazyeval::lazy(colspec))) %>% transmute(evensum=rowSums(.), evenmean=rowMeans(.)) %>% cbind(x,.) } dd %>% partial_mutate2(seq(2,ncol(dd),2))

¿Supongo que esto es algún tipo de problema ambiental? Cualquier sugerencia sobre cómo pasar los argumentos a partial_mutate1 para que el . tomará correctamente los valores del conjunto de datos "select () - ed"?


En las versiones más recientes de dplyr, puede usar el nuevo mutate_at()

función

mutate_at(dd, vars(starts_with("X")), somefunction)


Un enfoque agnóstico de varias columnas usando dplyr:

dd %>% select(-id) %>% mutate(evensum = rowSums(.[,1:length(.[1,])%%2==0]), evenmean = rowMeans(.[,1:length(.[1,])%%2==0])) %>% cbind(id=dd[,1],.) id X1 X2 X3 X4 X5 evensum evenmean 1 a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380812 2 b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439 3 c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535 4 d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478767


tidyr::nest() entiende la misma sintaxis de selector que dplyr::select() , por lo que un enfoque sería consolidar las columnas de interés en una sola columna de marcos de datos, realizar las operaciones necesarias en esa columna de marcos de datos , y ansioso por recuperar un marco de datos plano:

library( tidyverse ) dd %>% nest( X2, X4, .key="Slice" ) %>% mutate( evensum = map(Slice, rowSums), evenmean = map(Slice, rowMeans), evensd = map(Slice, pmap_dbl, lift_vd(sd)) ) %>% unnest # id X1 X3 X5 evensum evenmean evensd X2 X4 # 1 a 0.602 0.687 0.447 0.876 0.438 0.100 0.367 0.509 # 2 b 0.195 0.831 0.965 1.70 0.848 0.200 0.989 0.707 # 3 c 0.966 0.105 0.141 1.68 0.839 0.0333 0.815 0.862 # 4 d 0.651 0.646 0.777 1.10 0.548 0.416 0.254 0.842

Dado que los marcos de datos son básicamente listas, este enfoque es naturalmente adecuado para aplicar funciones arbitrarias (como sd arriba) para arbitrar un conjunto de columnas usando la familia de funciones purrr::pmap() .

Nota al purrr::lift_vd : dado que sd funciona en vectores, usamos purrr::lift_vd para convertir su interfaz para que sea adecuada para pmap :

sd( c(0.367, 0.509) ) # 0.100 lift_vd(sd)( 0.367, .509 ) # 0.100