seleccionar matrices filtrar filas datos data contar concatenar columnas agrupar agregar r data.table

filtrar - matrices en r



Agregar nuevas columnas a una tabla de datos que contiene muchas variables (4)

Creo que con una pequeña modificación en su último código, puede hacer ambas cosas fácilmente para la cantidad de variables que desee.

vars <- c("x2", "x3") # <- Choose the variable you want to operate on d[, paste0(vars, "_", "scale") := lapply(.SD, function(x) scale(x)[, 1]), .SDcols = vars, by = Stock] d[, paste0(vars, "_", "sum") := lapply(.SD, sum), .SDcols = vars, by = Stock] ## Time Stock x1 x2 x3 x2_scale x3_scale x2_sum x3_sum ## 1: 2014-08-22 A 13 14 32 -1.1338934 1.1323092 87 44 ## 2: 2014-08-23 A 25 39 9 0.7559289 -0.3701780 87 44 ## 3: 2014-08-24 A 18 34 3 0.3779645 -0.7621312 87 44 ## 4: 2014-08-22 B 44 8 6 -0.4730162 -0.7258662 59 32 ## 5: 2014-08-23 B 49 3 18 -0.6757374 1.1406469 59 32 ## 6: 2014-08-24 B 15 48 8 1.1487535 -0.4147807 59 32

Para funciones simples (que no requieren un tratamiento especial como la scale ), podría hacer fácilmente algo como:

vars <- c("x2", "x3") # <- Define the variable you want to operate on funs <- c("min", "max", "mean", "sum") # <- define your function for(i in funs){ d[, paste0(vars, "_", i) := lapply(.SD, eval(i)), .SDcols = vars, by = Stock] }

Quiero agregar muchas columnas nuevas simultáneamente a una data.table basada en cálculos por grupo. Un ejemplo de trabajo de mis datos se vería así:

Time Stock x1 x2 x3 1: 2014-08-22 A 15 27 34 2: 2014-08-23 A 39 44 29 3: 2014-08-24 A 20 50 5 4: 2014-08-22 B 42 22 43 5: 2014-08-23 B 44 45 12 6: 2014-08-24 B 3 21 2

Ahora quiero scale y sum muchas de las variables para obtener una salida como:

Time Stock x1 x2 x3 x2_scale x3_scale x2_sum x3_sum 1: 2014-08-22 A 15 27 34 -1.1175975 0.7310560 121 68 2: 2014-08-23 A 39 44 29 0.3073393 0.4085313 121 68 3: 2014-08-24 A 20 50 5 0.8102582 -1.1395873 121 68 4: 2014-08-22 B 42 22 43 -0.5401315 1.1226726 88 57 5: 2014-08-23 B 44 45 12 1.1539172 -0.3274462 88 57 6: 2014-08-24 B 3 21 2 -0.6137858 -0.7952265 88 57

Una implementación de fuerza bruta de mi problema sería:

library(data.table) set.seed(123) d <- data.table(Time = rep(seq.Date( Sys.Date(), length=3, by="day" )), Stock = rep(LETTERS[1:2], each=3 ), x1 = sample(1:50, 6), x2 = sample(1:50, 6), x3 = sample(1:50, 6)) d[,x2_scale:=scale(x2),by=Stock] d[,x3_scale:=scale(x3),by=Stock] d[,x2_sum:=sum(x2),by=Stock] d[,x3_sum:=sum(x3),by=Stock]

Otras publicaciones que describen un problema similar (¿ Agregar varias columnas a R data.table en una llamada de función? Y Asignar múltiples columnas usando: = en data.table, por grupo ) sugieren la siguiente solución:

d[, c("x2_scale","x3_scale"):=list(scale(x2),scale(x3)), by=Stock] d[, c("x2_sum","x3_sum"):=list(sum(x2),sum(x3)), by=Stock]

Pero, de nuevo, esto se volvería muy desordenado con muchas variables y también muestra un mensaje de error con la scale (pero no con la sum ya que no devuelve un vector).

¿Existe una manera más eficiente de lograr el resultado requerido (teniendo en cuenta que mi conjunto de datos real es bastante grande)?


EDITAR: versión más limpia utilizando functional . Creo que esta es la respuesta más cercana a la dplyr .

library(functional) funs <- list(scale=Compose(scale, c), sum=sum) # See data.table issue #783 on github for the need for this cols <- paste0("x", 2:3) cols.all <- outer(cols, names(funs), paste, sep="_") d[, c(cols.all) := unlist(lapply(funs, Curry(lapply, X=.SD)), rec=F), .SDcols=cols, by=Stock ]

Produce:

Time Stock x1 x2 x3 x2_scale x3_scale x2_sum x3_sum 1: 2014-08-22 A 15 27 34 -1.1175975 0.7310560 121 68 2: 2014-08-23 A 39 44 29 0.3073393 0.4085313 121 68 3: 2014-08-24 A 20 50 5 0.8102582 -1.1395873 121 68 4: 2014-08-22 B 42 22 43 -0.5401315 1.1226726 88 57 5: 2014-08-23 B 44 45 12 1.1539172 -0.3274462 88 57 6: 2014-08-24 B 3 21 2 -0.6137858 -0.7952265 88 57


Otra variación utilizando data.table

vars <- c("x2", "x3") d[, paste0(rep(vars, each=2), "_", c("scale", "sum")) := do.call(`cbind`, lapply(.SD, function(x) list(scale(x)[,1], sum(x)))), .SDcols=vars, by=Stock] d # Time Stock x1 x2 x3 x2_scale x2_sum x3_scale x3_sum #1: 2014-08-22 A 15 27 34 -1.1175975 121 0.7310560 68 #2: 2014-08-23 A 39 44 29 0.3073393 121 0.4085313 68 #3: 2014-08-24 A 20 50 5 0.8102582 121 -1.1395873 68 #4: 2014-08-22 B 42 22 43 -0.5401315 88 1.1226726 57 #5: 2014-08-23 B 44 45 12 1.1539172 88 -0.3274462 57 #6: 2014-08-24 B 3 21 2 -0.6137858 88 -0.7952265 57

Basado en los comentarios de @Arun, también puedes hacer:

cols <- paste0(rep(vars, each=2), "_", c("scale", "sum")) d[,(cols):= unlist(lapply(.SD, function(x) list(scale(x)[,1L], sum(x))), rec=F), by=Stock, .SDcols=vars]


Probablemente esté buscando una solución de data.table pura, pero también podría considerar el uso de dplyr aquí, ya que funciona con data.table también (no es necesario realizar la conversión). Luego, desde dplyr podría usar la función mutate_all como lo hago en este ejemplo aquí (con el primer conjunto de datos que mostró en su pregunta):

library(dplyr) dt %>% group_by(Stock) %>% mutate_all(funs(sum, scale), x2, x3) #Source: local data table [6 x 9] #Groups: Stock # # Time Stock x1 x2 x3 x2_sum x3_sum x2_scale x3_scale #1 2014-08-22 A 15 27 34 121 68 -1.1175975 0.7310560 #2 2014-08-23 A 39 44 29 121 68 0.3073393 0.4085313 #3 2014-08-24 A 20 50 5 121 68 0.8102582 -1.1395873 #4 2014-08-22 B 42 22 43 88 57 -0.5401315 1.1226726 #5 2014-08-23 B 44 45 12 88 57 1.1539172 -0.3274462 #6 2014-08-24 B 3 21 2 88 57 -0.6137858 -0.7952265

Puede agregar fácilmente más funciones para calcular, lo que creará más columnas para usted. Tenga en cuenta que mutate_all aplica la función a cada columna, excepto la variable de agrupación (Stock) por defecto. Pero puede especificar las columnas a las que solo desea aplicar las funciones (lo que hice en este ejemplo) o puede especificar a qué columnas no desea aplicar las funciones (eso sería, por ejemplo, -c(x2,x3) lugar de donde escribí x2, x3 ).

EDIT: se reemplazó mutate_each anterior con mutate_all ya que mutate_each quedará en desuso en un futuro próximo.