swirl sistema programación programacion parámetros lección introducción install_course_github ifunam gráficos grafica funciones forma estadística estadistica escalonada curso con ahora r data.table subset lapply

sistema - Aplicar la función en un subconjunto de columnas(.SDcols) mientras se aplica una función diferente en otra columna(dentro de los grupos)



lección de swirl 8 parámetros en el sistema de gráficos (2)

Esto es muy similar a una pregunta que aplica una función común a varias columnas de una data.table datos .SDcols Unidades .SDcols contestó detalladamente aquí .

La diferencia es que me gustaría aplicar simultáneamente una función diferente en otra columna que no es parte del subconjunto .SD . Publico un ejemplo simple a continuación para mostrar mi intento de resolver el problema:

dt = data.table(grp = sample(letters[1:3],100, replace = TRUE), v1 = rnorm(100), v2 = rnorm(100), v3 = rnorm(100)) sd.cols = c("v2", "v3") dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]

Da el siguiente error:

Error in `[.data.table`(dt, , list(v1 = sum(v1), lapply(.SD, mean)), by = grp, : object ''v1'' not found

Ahora esto tiene sentido porque la columna v1 no está incluida en el subconjunto de columnas que debe evaluarse primero. Así que exploré más a fondo incluyéndolo en mi subconjunto de columnas:

sd.cols = c("v1","v2", "v3") dt.out = dt[, list(sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]

Ahora esto no causa un error, pero proporciona una respuesta que contiene 9 filas (para 3 grupos), con la suma repetida tres veces en la columna V1 y los medios para las 3 columnas (como se esperaba pero no se desea) colocadas en V2 como se muestra a continuación:

> dt.out grp V1 V2 1: c -1.070608 -0.0486639841313638 2: c -1.070608 -0.178154270921521 3: c -1.070608 -0.137625003604012 4: b -2.782252 -0.0794929150464099 5: b -2.782252 -0.149529237116445 6: b -2.782252 0.199925178109264 7: a 6.091355 0.141659419355985 8: a 6.091355 -0.0272192037753071 9: a 6.091355 0.00815760216214876

Solución de solución utilizando 2 pasos

Claramente, es posible resolver el problema en varios pasos al calcular la mean por grupo para el subconjunto de columnas y unirlo a la sum por grupo para la columna única de la siguiente manera:

dt.out1 = dt[, sum(v1), by = grp] dt.out2 = dt[, lapply(.SD,mean), by = grp, .SDcols = sd.cols] dt.out = merge(dt.out1, dt.out2, by = "grp") > dt.out grp V1 v2 v3 1: a 6.091355 -0.0272192 0.008157602 2: b -2.782252 -0.1495292 0.199925178 3: c -1.070608 -0.1781543 -0.137625004

Estoy seguro de que me falta algo, gracias de antemano por cualquier orientación.


Prueba esto:

dt[,list(sum(v1), mean(v2), mean(v3)), by=grp]

En data.table , usar list() en el segundo argumento le permite describir un conjunto de columnas que dan como resultado la data.table final.

Para lo que vale, .SD puede ser bastante lento [^ 1], por lo que es posible que desee evitarlo a menos que realmente necesite todos los datos suministrados en la tabla de datos data.table como lo data.table para una función más sofisticada.

Otra opción, si tiene muchas columnas para .SDcols sería hacer la combinación en una línea usando la sintaxis de combinación data.table .

Por ejemplo:

dt[, sum(v1), by=grp][dt[,lapply(.SD,mean), by=grp, .SDcols=sd.cols]]

Para usar la merge de data.table , primero debe usar setkey() en su data.table para que sepa cómo hacer coincidir las cosas.

Así que realmente, primero necesitas:

setkey(dt, grp)

Luego puedes usar la línea de arriba para producir un resultado equivalente.

[^ 1]: Encuentro que esto es especialmente cierto a medida que su número de grupos se acerca al número de filas totales. Por ejemplo, esto puede suceder cuando su clave es una identificación individual y muchas personas solo tienen una o dos observaciones.


Actualización: el problema #495 se resolvió ahora con este reciente compromiso , ahora podemos hacerlo bien:

require(data.table) # v1.9.7+ set.seed(1L) dt = data.table(grp = sample(letters[1:3],100, replace = TRUE), v1 = rnorm(100), v2 = rnorm(100), v3 = rnorm(100)) sd.cols = c("v2", "v3") dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]

Sin embargo, tenga en cuenta que en este caso, v2 se devolvería como una lista. Eso es porque estás haciendo la list(val, list()) efectiva. Lo que pretendes hacer tal vez sea:

dt[, c(list(v1=sum(v1)), lapply(.SD, mean)), by=grp, .SDcols = sd.cols] # grp v1 v2 v3 # 1: a -6.440273 0.16993940 0.2173324 # 2: b 4.304350 -0.02553813 0.3381612 # 3: c 0.377974 -0.03828672 -0.2489067

Ver historia para mayor respuesta.