统计每个组的观察值/行数,并将结果添加到数据帧

说我有一个data.frame对象:

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

现在我要计算每个nametype组合的观察次数。 这可以这样做:

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

或者也可能与plyr ,(虽然我不知道如何)。

但是,如何将结果合并到原始数据框中呢? 所以结果将如下所示:

 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 

现在count存储汇总的结果。

plyr的解决方案也很有趣,但是我想知道如何用base R来完成。

使用plyr

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

使用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']] 

编辑(mnel)

使用data.table版本1.8.2或更高有:=按组。 还有值.N (引入的版本1.6.2),这是组中的行数),所以它就像

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

使用dplyr

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

随着新版本的dplyr0.6.0

 df %>% add_count(name, type) 

你可以使用ave

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

你可以这样做:

 > 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 

或者可能更直观地

 > 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 

这应该做你的工作:

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)

另一种推广更多的方式:

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

基本的R函数aggregate将获得data.frame计数,但将这些计数加回到原始数据。 data.frame似乎需要一些处理。

 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 

一个两行的替代方法是生成一个0的变量,然后用split<-splitlengths填充它,如下所示:

 # 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")])) 

这将返回所需的结果

 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 

本质上,RHS计算每个名称类型组合的长度,为“red.chair”和“black.plate”返回长度为6的命名向量为0。 这被送到LHS与split <-这将采取向量,并适当地增加值在他们的给定点。 这实际上就是ave所做的,正如你所看到的, ave的第二个到最后一行是

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

然而, lengthssapply(list, length)的优化版本。