计算每组的行数并将结果添加到原始数据框
Posted
技术标签:
【中文标题】计算每组的行数并将结果添加到原始数据框【英文标题】:Count number of rows per group and add result to original data frame 【发布时间】:2011-11-19 00:27:48 【问题描述】:假设我有一个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))
现在我想计算name
和type
的每个组合的行数(观察值)。可以这样做:
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 来完成。
【问题讨论】:
【参考方案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]
【讨论】:
【参考方案2】:使用data.table
:
library(data.table)
dt = as.data.table(df)
# or coerce to data.table by reference:
# setDT(df)
dt[ , count := .N, by = .(name, type)]
对于data.table 1.8.2
之前的替代方案,请参阅编辑历史记录。
使用dplyr
:
library(dplyr)
df %>%
group_by(name, type) %>%
mutate(count = n())
或者简单地说:
add_count(df, name, type)
使用plyr
:
plyr::ddply(df, .(name, type), transform, count = length(num))
【讨论】:
你需要“setkeyv(dt, c('name', 'type'))”吗?【参考方案3】:使用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
【讨论】:
【参考方案4】:这应该做你的工作:
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)
【讨论】:
【参考方案5】:您距离将行数合并到基础数据集中仅一步之遥。
使用broom
包中的tidy()
函数,将频率表转换为数据框并与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
【讨论】:
【参考方案6】:两行替代方法是生成一个 0 的变量,然后用 split<-
、split
和 lengths
填充它,如下所示:
# 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 的命名向量,其中“red.chair”和“black.plate”为 0。这通过split <-
被馈送到 LHS,它接受向量并在给定的位置适当地添加值。这基本上就是ave
所做的,正如您所见,ave
的倒数第二行是
split(x, g) <- lapply(split(x, g), FUN)
不过,lengths
是sapply(list, length)
的优化版本。
【讨论】:
【参考方案7】:基本的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
【讨论】:
【参考方案8】:另一种概括更多的方式:
df$count <- unsplit(lapply(split(df, df[c("name","type")]), nrow), df[c("name","type")])
【讨论】:
请解释一下这如何概括更多?【参考方案9】:你可以这样做:
> 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
【讨论】:
【参考方案10】:你可以使用ave
:
df$count <- ave(df$num, df[,c("name","type")], FUN=length)
【讨论】:
也可以使用transform(df, count = ave(num, name, type, FUN = length))
或with
来做的更简洁
如果你有大量数据,这个命令是SUPERSLOW以上是关于计算每组的行数并将结果添加到原始数据框的主要内容,如果未能解决你的问题,请参考以下文章
R语言计算每个分组的行数并将结果添加到dataframe中实战