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

dplyr管道中summarise内多个across的求值时序问题

dplyr summarise中多个across的求值逻辑与解决方案

问题背景

你遇到的核心问题是:在dplyr的summarise()中,多个across()调用的执行顺序会影响结果——调换两个across的顺序后输出不同。

两段对比代码:
第一段代码:

data(iris)

iris_summary <- iris %>%
  group_by(Species) %>%
  summarise(
    across(
      .cols = starts_with("Sepal"), 
      .fns = mean
    ),
    across(
      .cols = starts_with("Petal"),
      .fns = ~ .x[which.max(Sepal.Length)]
    )
  )

第二段代码:

iris_summary_2 <- iris %>%
  group_by(Species) %>%
  summarise(
    across(
      .cols = starts_with("Petal"),
      .fns = ~ .x[which.max(Sepal.Length)]
    ),
    across(
      .cols = starts_with("Sepal"), 
      .fns = mean
    )
  )

你的疑问:这是否是求值时序问题?原本期望两个across都基于管道上一步的原始数据求值,但结果显示第二个across似乎用了第一个across生成的Sepal.Length而非原始数据。如何在不改变代码结构的前提下强制使用原始分组数据?


原因分析

是的,这完全是求值顺序导致的问题。在dplyr的summarise()中:

  • 所有表达式(包括across()调用)按书写顺序依次执行
  • 每执行完一个表达式,生成的新列会立即加入到当前的临时结果数据框中
  • 后续的表达式默认从这个更新后的临时数据框中读取列,而非始终引用分组前的原始数据

具体到你的例子:

  • 第一段代码中,第一个across先执行,生成了Sepal.Length(分组均值,单值);第二个across里的which.max(Sepal.Length)会读取这个单值,which.max()对单值返回1,因此取的是每组Petal列的第一个值,而非原始数据中Sepal.Length最大值对应的Petal值。
  • 第二段代码中,第一个across先执行时,临时数据框里还没有新的Sepal.Length列,所以which.max(Sepal.Length)读取的是原始分组后的Sepal.Length向量,能正确找到最大值对应的位置,结果符合预期。

解决方案(不改变代码结构)

要强制后续across引用分组后的原始数据,可以使用cur_data()函数——它会返回当前分组的原始数据(不受前面summarise步骤生成的新列影响)。

修改第一段代码如下:

data(iris)

iris_summary <- iris %>%
  group_by(Species) %>%
  summarise(
    across(
      .cols = starts_with("Sepal"), 
      .fns = mean
    ),
    across(
      .cols = starts_with("Petal"),
      .fns = ~ .x[which.max(cur_data()$Sepal.Length)]
    )
  )

这样无论两个across的顺序如何,第二个across都会从原始分组数据中读取Sepal.Length向量,结果会和第二段代码完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 22:30:49