varias resueltos reales rango por limites julioprofe funciones ejercicios dominio definicion continuidad r aggregate

resueltos - limites de funciones de varias variables definicion



Aplicar varias funciones de resumen en varias variables por grupo en una llamada (6)

Tengo el siguiente marco de datos

x <- read.table(text = " id1 id2 val1 val2 1 a x 1 9 2 a x 2 4 3 a y 3 5 4 a y 4 9 5 b x 1 7 6 b y 4 4 7 b x 3 9 8 b y 2 8", header = TRUE)

Quiero calcular la media de val1 y val2 agrupados por id1 e id2, y simultáneamente contar el número de filas para cada combinación id1-id2. Puedo realizar cada cálculo por separado:

# calculate mean aggregate(. ~ id1 + id2, data = x, FUN = mean) # count rows aggregate(. ~ id1 + id2, data = x, FUN = length)

Para hacer ambos cálculos en una llamada, lo intenté

do.call("rbind", aggregate(. ~ id1 + id2, data = x, FUN = function(x) data.frame(m = mean(x), n = length(x))))

Sin embargo, obtengo una salida confusa junto con una advertencia:

# m n # id1 1 2 # id2 1 1 # 1.5 2 # 2 2 # 3.5 2 # 3 2 # 6.5 2 # 8 2 # 7 2 # 6 2 # Warning message: # In rbind(id1 = c(1L, 2L, 1L, 2L), id2 = c(1L, 1L, 2L, 2L), val1 = list( : # number of columns of result is not a multiple of vector length (arg 1)

Podría usar el paquete plyr, pero mi conjunto de datos es bastante grande y plyr es muy lento (casi inutilizable) cuando crece el tamaño del conjunto de datos.

¿Cómo puedo usar funciones aggregate u otras para realizar varios cálculos en una llamada?


Puede agregar una columna de count , agregar con sum y luego volver a escalar para obtener la mean :

x$count <- 1 agg <- aggregate(. ~ id1 + id2, data = x,FUN = sum) agg # id1 id2 val1 val2 count # 1 a x 3 13 2 # 2 b x 4 16 2 # 3 a y 7 14 2 # 4 b y 6 12 2 agg[c("val1", "val2")] <- agg[c("val1", "val2")] / agg$count agg # id1 id2 val1 val2 count # 1 a x 1.5 6.5 2 # 2 b x 2.0 8.0 2 # 3 a y 3.5 7.0 2 # 4 b y 3.0 6.0 2

Tiene la ventaja de preservar los nombres de sus columnas y crear una sola columna de count .


Puede hacerlo todo en un solo paso y obtener un etiquetado adecuado:

> aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) # id1 id2 val1.mn val1.n val2.mn val2.n # 1 a x 1.5 2.0 6.5 2.0 # 2 b x 2.0 2.0 8.0 2.0 # 3 a y 3.5 2.0 7.0 2.0 # 4 b y 3.0 2.0 6.0 2.0

Esto crea un marco de datos con dos columnas de id y dos columnas de matriz:

str( aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) ) ''data.frame'': 4 obs. of 4 variables: $ id1 : Factor w/ 2 levels "a","b": 1 2 1 2 $ id2 : Factor w/ 2 levels "x","y": 1 1 2 2 $ val1: num [1:4, 1:2] 1.5 2 3.5 3 2 2 2 2 ..- attr(*, "dimnames")=List of 2 .. ..$ : NULL .. ..$ : chr "mn" "n" $ val2: num [1:4, 1:2] 6.5 8 7 6 2 2 2 2 ..- attr(*, "dimnames")=List of 2 .. ..$ : NULL .. ..$ : chr "mn" "n"

Como señala @lord.garbage a continuación, esto se puede convertir a un marco de datos con columnas "simples" mediante do.call(data.frame, ...)

str( do.call(data.frame, aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) ) ) ''data.frame'': 4 obs. of 6 variables: $ id1 : Factor w/ 2 levels "a","b": 1 2 1 2 $ id2 : Factor w/ 2 levels "x","y": 1 1 2 2 $ val1.mn: num 1.5 2 3.5 3 $ val1.n : num 2 2 2 2 $ val2.mn: num 6.5 8 7 6 $ val2.n : num 2 2 2 2

Esta es la sintaxis para múltiples variables en el LHS:

aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )


Tal vez quieres fusionarte ?

x.mean <- aggregate(. ~ id1+id2, p, mean) x.len <- aggregate(. ~ id1+id2, p, length) merge(x.mean, x.len, by = c("id1", "id2")) id1 id2 val1.x val2.x val1.y val2.y 1 a x 1.5 6.5 2 2 2 a y 3.5 7.0 2 2 3 b x 2.0 8.0 2 2 4 b y 3.0 6.0 2 2


También puede usar plyr::each() para introducir funciones múltiples:

aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = plyr::each(avg = mean, n = length))


Teniendo esto en cuenta en la pregunta:

Podría usar el paquete plyr, pero mi conjunto de datos es bastante grande y plyr es muy lento (casi inutilizable) cuando crece el tamaño del conjunto de datos.

Luego, en data.table ( 1.9.4+ ) puedes probar:

> DT id1 id2 val1 val2 1: a x 1 9 2: a x 2 4 3: a y 3 5 4: a y 4 9 5: b x 1 7 6: b y 4 4 7: b x 3 9 8: b y 2 8 > DT[ , .(mean(val1), mean(val2), .N), by = .(id1, id2)] # simplest id1 id2 V1 V2 N 1: a x 1.5 6.5 2 2: a y 3.5 7.0 2 3: b x 2.0 8.0 2 4: b y 3.0 6.0 2 > DT[ , .(val1.m = mean(val1), val2.m = mean(val2), count = .N), by = .(id1, id2)] # named id1 id2 val1.m val2.m count 1: a x 1.5 6.5 2 2: a y 3.5 7.0 2 3: b x 2.0 8.0 2 4: b y 3.0 6.0 2 > DT[ , c(lapply(.SD, mean), count = .N), by = .(id1, id2)] # mean over all columns id1 id2 val1 val2 count 1: a x 1.5 6.5 2 2: a y 3.5 7.0 2 3: b x 2.0 8.0 2 4: b y 3.0 6.0 2

Para los tiempos que comparan el aggregate (usado en la pregunta y las otras 3 respuestas) con data.table vea este benchmark (los casos agg y agg.x ).


Usando el paquete dplyr puedes lograr esto usando summarise_all . Con esta función de resumen puede aplicar otras funciones (en este caso, mean n() ) a cada una de las columnas que no se agrupan:

x %>% group_by(id1, id2) %>% summarise_all(funs(mean, n()))

lo que da:

id1 id2 val1_mean val2_mean val1_n val2_n 1 a x 1.5 6.5 2 2 2 a y 3.5 7.0 2 2 3 b x 2.0 8.0 2 2 4 b y 3.0 6.0 2 2

Si no desea aplicar la (s) función (es) a todas las columnas que no se agrupan, especifique las columnas a las que se deben aplicar o excluyendo el elemento no deseado con un signo menos usando la función summarise_at() :

# inclusion x %>% group_by(id1, id2) %>% summarise_at(vars(val1, val2), funs(mean, n())) # exclusion x %>% group_by(id1, id2) %>% summarise_at(vars(-val2), funs(mean, n()))