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

如何在R中实现DataFrame的加减组合聚合运算?

解决带加减规则的DataFrame聚合问题

输入数据

首先明确输入的两个数据集:

input <- structure(list(V1 = c("Team_2022", "Team_2022", "Team_2022"), 
                        V2 = c("Frank", "Mary", "John"), 
                        V3 = c("Sydney", "Sydney", "Sydney"), 
                        V4 = c(55, 76, 14)), 
                   row.names = c(NA, -3L), class = c("data.table", "data.frame"))

teams <- structure(list(V1 = c("team1", "team2", "team3"), 
                        V2 = c("Mary + Frank - John","Mary + John - Frank", "John + Frank - Mary")), 
                   class = "data.frame", row.names = c(NA, -3L))

desired_output <- structure(list(V1.x = c("team1", "team2", "team3"), V1.y = c("Team_2022", "Team_2022", "Team_2022"), V2 = c("Mary + Frank - John", "Mary + John - Frank", "John + Frank - Mary"), V3 = c("Sydney", "Sydney", "Sydney"), V4 = c(117, 35, -7)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -3L))

问题分析

原函数仅能处理加法的核心问题是:拆分表达式时未保留符号信息,导致减法项被当作0处理,最终求和结果错误。要解决带加减的聚合,核心是提取每个项的符号系数,再与对应值加权求和。

方法1:解析符号与项,加权求和(推荐,安全通用)

通过正则表达式拆分带符号的项,提取系数后计算加权和,兼容多分组场景:

library(tidyverse)

result <- teams %>%
  # 为表达式开头补+(确保所有项带符号),按正负号拆分
  mutate(terms = str_replace(V2, "^(?=[A-Za-z])", "+") %>% str_split("(?=[+-])")) %>%
  unnest(terms) %>%
  # 提取系数(1或-1)和对应的姓名
  mutate(
    coeff = ifelse(str_starts(terms, "-"), -1, 1),
    name = str_remove(terms, "^[+-]")
  ) %>%
  # 关联input中的数值
  left_join(input, by = c("name" = "V2")) %>%
  replace_na(list(V4 = 0)) %>%
  # 按team分组计算加权和
  group_by(V1, V2) %>%
  summarize(
    V1.y = first(na.omit(V1)),
    V3 = first(na.omit(V3)),
    V4 = sum(coeff * V4),
    .groups = "drop"
  ) %>%
  rename(V1.x = V1)

# 验证结果
all.equal(result, desired_output) # 返回TRUE

方法2:动态执行表达式(简洁,适合可控场景)

将表达式中的姓名替换为对应数值,通过eval(parse)直接计算,代码更简洁,但注意仅在数据源可控时使用(避免恶意代码风险):

# 把input转换为姓名-数值的命名向量
value_vec <- deframe(input %>% select(V2, V4))

result2 <- teams %>%
  rowwise() %>%
  mutate(
    # 替换表达式中的姓名为数值
    expr_str = str_replace_all(V2, names(value_vec), as.character(value_vec)),
    V4 = eval(parse(text = expr_str)),
    # 补充分组信息(假设input中V1/V3统一)
    V1.y = input$V1[1],
    V3 = input$V3[1]
  ) %>%
  ungroup() %>%
  rename(V1.x = V1) %>%
  select(V1.x, V1.y, V2, V3, V4)

# 验证结果
all.equal(result2, desired_output) # 返回TRUE

方法对比

  • 方法1:安全可靠,支持input中存在多Team、多城市的复杂场景,无代码注入风险。
  • 方法2:代码简洁,执行快,但仅适用于数据源完全可控的场景,且默认input的V1/V3为统一值,若需分组需额外处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:55:24