You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用dplyr::summarise()按组聚合时处理依赖其他列的常量列

问题描述

我想用dplyr::summarise()对数据框做聚合,其中某列是依赖其他列值的常量。以下是模拟数据框的代码:

# 辅助函数可忽略
simulate_df <- function() {
  person_ids    <- sample(1:10, size = 2)
  product_ids   <- sample(1:999, size = 2)
  product_score <- sample(1:9, size = 2)
  
  get_weights <- function() {
    first_num <- sample(1:9, 1)
    c(first_num, 10 - first_num)
  } 
  
  data.frame(
    person_id = rep(person_ids, times = get_weights()),
    product_id = sample(product_ids, 5, replace = TRUE)
  ) |> 
    transform(product_score = ifelse(product_id == product_ids[1], product_score[1], product_score[2]))
}

set.seed(12345)

my_df <- simulate_df()
my_df
#>    person_id product_id product_score
#> 1          3        826             8
#> 2          3        605             2
#> 3          3        826             8
#> 4          3        605             2
#> 5          3        605             2
#> 6          3        826             8
#> 7          8        605             2
#> 8          8        826             8
#> 9          8        605             2
#> 10         8        605             2

在my_df中,每条记录对应一位用户(person_id)的购买记录,每位用户买两种产品之一,每种产品有固定的product_score。

我需要按person_id聚合,得到以下列:

  • product_a的购买次数
  • product_b的购买次数
  • product_a购买次数与product_a的product_score的差值
  • product_b购买次数与product_b的product_score的差值

预期输出:

## # A tibble: 2 × 5
##   person_id n_product_a n_product_b diff_nproduct_a_product_score diff_nproduct_b_product_score
##       <int>       <int>       <int>                         <int>                         <int>
## 1         3           3           3                            -5                             1
## 2         8           1           3                            -7                             1

目前我已经实现了前两列的统计:

library(dplyr, warn.conflicts = FALSE)

my_df |> 
  group_by(person_id) |> 
  summarise(n_product_a = sum(product_id == 826),
            n_product_b = sum(product_id == 605))
#> # A tibble: 2 × 3
#>   person_id n_product_a n_product_b
#>       <int>       <int>       <int>
#> 1         3           3           3
#> 2         8           1           3

现在的问题是:如何在product_score依赖product_id的情况下,计算出上述差值列?


解决方案

核心思路是先在分组内提取每种产品对应的固定product_score,再用购买次数减去该分数即可。因为每个product_id对应的product_score是常量,所以用first()或unique()就能获取该值。

完整代码如下:

library(dplyr, warn.conflicts = FALSE)

my_df |> 
  group_by(person_id) |> 
  summarise(
    # 统计购买次数
    n_product_a = sum(product_id == 826),
    n_product_b = sum(product_id == 605),
    # 获取product_a对应的固定分数
    score_a = first(product_score[product_id == 826]),
    # 获取product_b对应的固定分数
    score_b = first(product_score[product_id == 605]),
    # 计算差值
    diff_nproduct_a_product_score = n_product_a - score_a,
    diff_nproduct_b_product_score = n_product_b - score_b
  ) |> 
  # 移除中间用到的临时分数列
  select(-score_a, -score_b)

运行后输出:

#> # A tibble: 2 × 5
#>   person_id n_product_a n_product_b diff_nproduct_a_product_score diff_nproduct_b_product_score
#>       <int>       <int>       <int>                         <int>                         <int>
#> 1         3           3           3                            -5                             1
#> 2         8           1           3                            -7                             1

补充说明

  • first()和unique()效果一致,因为同一product_id对应的product_score完全相同,取任意一个匹配值都能得到正确的固定分数。
  • 如果需要兼容用户未购买某类产品的边界情况,可以给first()加上default = NA,再用ifelse处理差值计算,不过根据你的模拟数据,暂时不需要额外处理。

内容的提问来源于stack exchange,提问作者Emman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 05:06:37