将结果合并并聚合到原始数据
Merge and aggregate result to original data
我有一个数据框 df,有 3 个变量:id、类别和数量:
id category quantity
01 AB 235
02 BC 987
03 AB 366
04 CD 287
我想添加第四个变量,它是整个类别的总和。现在,我喜欢这样做:
df <- merge(df,aggregate(df$quantity,list(df$category),sum),
by.x="category",
by.y="Group.1")
names(df)[4] <- "sum.category"
有效,但我觉得不是很满意,可能有更好的方法吗?
您可以使用 tapply
获取总和,然后我们进行查找 table 以创建新列
# use tapply to get the sums. using with() makes the code nicer, IMO.
cat_sums <- with(df, tapply(quantity, category, sum))
# use lookup table to create new column
df$sum.category <- cat_sums[df$category]
# id category quantity sum.category
#1 1 AB 235 601
#2 2 BC 987 987
#3 3 AB 366 601
#4 4 CD 287 287
这是一个dplyr
解决方案
df %>%
group_by(category) %>% # Group by category
mutate(sum.category = sum(quantity)) %>% # Sum by category
ungroup # Remove grouping
#Source: local data frame [4 x 4]
#
# id category quantity sum.category
# (int) (chr) (int) (int)
#1 1 AB 235 601
#2 2 BC 987 987
#3 3 AB 366 601
#4 4 CD 287 287
ungroup
并非绝对必要。
这是 data.table
的另一个选项。我们将 'data.frame' 转换为 'data.table' (setDT(df1)
),按 'category' 分组,我们分配 (:=
) 'quantity' 的 sum
] 作为新列 ('sum.category').
library(data.table)
setDT(df1)[,sum.category:= sum(quantity) , category]
df1
# id category quantity sum.category
#1: 1 AB 235 601
#2: 2 BC 987 987
#3: 3 AB 366 601
#4: 4 CD 287 287
或使用 base R
df1$sum.category <- with(df1, ave(quantity, category, FUN=sum))
您可以以更具可读性的方式使用相同的合并和聚合。将实际的 df 与左外连接 all.x = TRUE
上的聚合结果合并将完成这项工作。我希望这能更好地理解。
df <- data.frame(id=c(01,02,03,04),category=c("AB","BC","AB","CD"),
quantity=c(235,987,366,287))
df <- merge(df,aggregate(quantity ~ category, data=df, sum),"category",all.x = TRUE)
names(df)[4] <- "sum.category"
df
# category id quantity.x sum.category
# AB 1 235 601
# AB 3 366 601
# BC 2 987 987
# CD 4 287 287
如果您还想要更easy-to-understand的方式,那么sql是最好的选择。为此,您可能需要 sqldf
库。我们正在做同样的聚合,并以 sql 的方式合并回实际的 df。它更像是 self-join 的东西。 sql 代码更容易理解
library (sqldf)
dfnew<-sqldf("select a.*,b.sum_quantity
from df a left join
(select category, sum(quantity) sum_category
from df group by 1) b
on a.category=b.category")
dfnew
# category id quantity sum_category
# AB 1 235 601
# BC 2 987 987
# AB 3 366 601
# CD 4 287 287
我有一个数据框 df,有 3 个变量:id、类别和数量:
id category quantity
01 AB 235
02 BC 987
03 AB 366
04 CD 287
我想添加第四个变量,它是整个类别的总和。现在,我喜欢这样做:
df <- merge(df,aggregate(df$quantity,list(df$category),sum),
by.x="category",
by.y="Group.1")
names(df)[4] <- "sum.category"
有效,但我觉得不是很满意,可能有更好的方法吗?
您可以使用 tapply
获取总和,然后我们进行查找 table 以创建新列
# use tapply to get the sums. using with() makes the code nicer, IMO.
cat_sums <- with(df, tapply(quantity, category, sum))
# use lookup table to create new column
df$sum.category <- cat_sums[df$category]
# id category quantity sum.category
#1 1 AB 235 601
#2 2 BC 987 987
#3 3 AB 366 601
#4 4 CD 287 287
这是一个dplyr
解决方案
df %>%
group_by(category) %>% # Group by category
mutate(sum.category = sum(quantity)) %>% # Sum by category
ungroup # Remove grouping
#Source: local data frame [4 x 4]
#
# id category quantity sum.category
# (int) (chr) (int) (int)
#1 1 AB 235 601
#2 2 BC 987 987
#3 3 AB 366 601
#4 4 CD 287 287
ungroup
并非绝对必要。
这是 data.table
的另一个选项。我们将 'data.frame' 转换为 'data.table' (setDT(df1)
),按 'category' 分组,我们分配 (:=
) 'quantity' 的 sum
] 作为新列 ('sum.category').
library(data.table)
setDT(df1)[,sum.category:= sum(quantity) , category]
df1
# id category quantity sum.category
#1: 1 AB 235 601
#2: 2 BC 987 987
#3: 3 AB 366 601
#4: 4 CD 287 287
或使用 base R
df1$sum.category <- with(df1, ave(quantity, category, FUN=sum))
您可以以更具可读性的方式使用相同的合并和聚合。将实际的 df 与左外连接 all.x = TRUE
上的聚合结果合并将完成这项工作。我希望这能更好地理解。
df <- data.frame(id=c(01,02,03,04),category=c("AB","BC","AB","CD"),
quantity=c(235,987,366,287))
df <- merge(df,aggregate(quantity ~ category, data=df, sum),"category",all.x = TRUE)
names(df)[4] <- "sum.category"
df
# category id quantity.x sum.category
# AB 1 235 601
# AB 3 366 601
# BC 2 987 987
# CD 4 287 287
如果您还想要更easy-to-understand的方式,那么sql是最好的选择。为此,您可能需要 sqldf
库。我们正在做同样的聚合,并以 sql 的方式合并回实际的 df。它更像是 self-join 的东西。 sql 代码更容易理解
library (sqldf)
dfnew<-sqldf("select a.*,b.sum_quantity
from df a left join
(select category, sum(quantity) sum_category
from df group by 1) b
on a.category=b.category")
dfnew
# category id quantity sum_category
# AB 1 235 601
# BC 2 987 987
# AB 3 366 601
# CD 4 287 287