将结果合并并聚合到原始数据

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