计算每组观察/行数,并将结果添加到数据框

时间:2011-09-16 21:33:05

标签: r count aggregate r-faq

说我有一个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的解决方案也很有趣,但我希望看到如何使用基础R来完成。

10 个答案:

答案 0 :(得分:58)

使用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())

或者简单地说:

add_count(df, name, type)

答案 1 :(得分:25)

您可以使用ave

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

答案 2 :(得分:7)

你可以这样做:

> 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

答案 3 :(得分:5)

这应该做你的工作:

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)

答案 4 :(得分:3)

基础R函数aggregate将使用单行获取计数,但将这些计数添加回原始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

答案 5 :(得分:2)

使用 sqldf 软件包:

library(sqldf)

sqldf("select a.*, b.cnt
       from df a,
           (select name, type, count(1) as cnt
            from df
            group by name, type) b
      where a.name = b.name and
            a.type = b.type")

#    name  type num cnt
# 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

答案 6 :(得分: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计算每个名称类型组合的长度,返回长度为6的命名向量,其中0为&#34; red.chair&#34;和&#34; black.plate。&#34;这将通过split <-提供给LHS,它采用向量并在给定的点中适当地添加值。这基本上是ave的作用,因为您可以看到ave的第二行到最后一行是

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

但是,lengthssapply(list, length)的优化版本。

答案 7 :(得分:1)

您距离将行数纳入基础数据集只需一步。

使用tidy()包中的broom函数,将频率表转换为数据框,并将内部联接转换为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

答案 8 :(得分:1)

以R为基数的简单行:

df$count = table(interaction(df[, (c("name", "type"))]))[interaction(df[, (c("name", "type"))])]

为了清晰/有效,两行相同:

fact = interaction(df[, (c("name", "type"))])
df$count = table(fact)[fact]

答案 9 :(得分:-1)

另一种概括更多的方式:

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