2011-09-16 12 views
32

Decir que tengo un objeto data.frame:Contar el número de observaciones/filas por grupo y añadir a consecuencia trama de datos

df <- data.frame(name=c('black','black','black','red','red'), 
       type=c('chair','chair','sofa','sofa','plate'), 
       num=c(4,5,12,4,3)) 

Ahora quiero contar el número de observaciones por cada combinación de name y type. Esto se puede hacer de esta manera:

table(df[ , c("name","type")]) 

o posiblemente también con plyr, (aunque no estoy seguro de cómo).

Sin embargo, ¿cómo obtengo los resultados incorporados en el marco de datos original? Por lo que los resultados se vería así:

df 
# name type num count 
# 1 black chair 4  2 
# 2 black chair 5  2 
# 3 black sofa 12  1 
# 4 red sofa 4  1 
# 5 red plate 3  1 

donde count ahora almacena los resultados de la agregación.

Una solución con plyr podría ser interesante conocer también, aunque me gustaría ver cómo se hace esto con R. base de

Respuesta

1

Otra forma en que g eneralizes más:

df$count <- unsplit(lapply(split(df, df[c("name","type")]), nrow), df[c("name","type")]) 
+6

Por favor explique cómo se generaliza esto más? – smci

7

Usted puede hacer esto:

> ddply(df,.(name,type),transform,count = NROW(piece)) 
    name type num count 
1 black chair 4  2 
2 black chair 5  2 
3 black sofa 12  1 
4 red plate 3  1 
5 red sofa 4  1 

o tal vez de forma más intuitiva ,

> ddply(df,.(name,type),transform,count = length(num)) 
    name type num count 
1 black chair 4  2 
2 black chair 5  2 
3 black sofa 12  1 
4 red plate 3  1 
5 red sofa 4  1 
23

Usted puede utilizar ave:

df$count <- ave(df$num, df[,c("name","type")], FUN=length) 
50

Usando plyr:

plyr::ddply(df, .(name, type), transform, count = length(num)) 

Usando data.table:

library(data.table) 
dt = data.table(df) 
# using setkey or setkeyv to set the key 
setkeyv(dt, c('name', 'type')) 
# self 
dt[dt[ , count = length(num), 'name, type']] 

EDIT (mnel)

Al usar la versión data.table 1.8.2 o mayor tiene := por grupo. Hay también el valor .N (versión introducido 1.6.2), que es el número de filas en el grupo), por lo que es tan fácil como

dt[ , count := .N, by = list(name, type)] 

Usando dplyr:

library(dplyr) 
df %>% 
    group_by(name, type) %>% 
    mutate(count = n()) 

Con la nueva versión de dplyr (0.6.0)

df %>% 
    add_count(name, type) 
+0

¿Necesita "setkeyv (dt, c ('nombre', 'tipo'))? – skan

2

La base de R función aggregate obtendrán los recuentos con una sola línea, pero la adición de los recuentos de nuevo a la original data.frame parece tomar un poco de procesamiento.

df <- data.frame(name=c('black','black','black','red','red'), 
       type=c('chair','chair','sofa','sofa','plate'), 
       num=c(4,5,12,4,3)) 
df 
# name type num 
# 1 black chair 4 
# 2 black chair 5 
# 3 black sofa 12 
# 4 red sofa 4 
# 5 red plate 3 

rows.per.group <- aggregate(rep(1, length(paste0(df$name, df$type))), 
          by=list(df$name, df$type), sum) 
rows.per.group 
# Group.1 Group.2 x 
# 1 black chair 2 
# 2  red plate 1 
# 3 black sofa 1 
# 4  red sofa 1 

my.summary <- do.call(data.frame, rows.per.group) 
colnames(my.summary) <- c(colnames(df)[1:2], 'rows.per.group') 
my.data <- merge(df, my.summary, by = c(colnames(df)[1:2])) 
my.data 
# name type num rows.per.group 
# 1 black chair 4    2 
# 2 black chair 5    2 
# 3 black sofa 12    1 
# 4 red plate 3    1 
# 5 red sofa 4    1 
3

Esto debería hacer su trabajo:

df_agg <- aggregate(num~name+type,df,FUN=NROW) names(df_agg)[3] <- "count" df <- merge(df,df_agg,by=c('name','type'),all.x=TRUE)

0

Una alternativa dos línea es generar una variable de 0s y luego rellenarlo con split<-, split, y lengths así:

# generate vector of 0s 
df$count <-0L 

# fill it in 
split(df$count, df[c("name", "type")]) <- lengths(split(df$num, df[c("name", "type")])) 

Esto devuelve el resultado deseado

df 
    name type num count 
1 black chair 4  2 
2 black chair 5  2 
3 black sofa 12  1 
4 red sofa 4  1 
5 red plate 3  1 

Básicamente, el RHS calcula las longitudes de cada combinación de nombre y tipo, devolviendo un vector con nombre de longitud 6 con 0 para "red.chair" y "black.plate". Esto se envía al LHS con split <-, que toma el vector y agrega los valores apropiadamente en sus lugares determinados. Esto es esencialmente lo que hace ave, como se puede ver que el segundo a última línea de ave es

split(x, g) <- lapply(split(x, g), FUN) 

Sin embargo, lengths es una versión optimizada de sapply(list, length).

0

Estaba a un paso de incorporar el recuento de filas en el conjunto de datos base.

Uso de la función tidy() del paquete broom, convertir la tabla de frecuencia en una trama de datos y la combinación interna con df:

df <- data.frame(name=c('black','black','black','red','red'), 
         type=c('chair','chair','sofa','sofa','plate'), 
         num=c(4,5,12,4,3)) 
library(broom) 
df <- merge(df, tidy(table(df[ , c("name","type")])), by=c("name","type")) 
df 
    name type num Freq 
1 black chair 4 2 
2 black chair 5 2 
3 black sofa 12 1 
4 red plate 3 1 
5 red sofa 4 1 
Cuestiones relacionadas