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

tidyr::crossing能否在函数中配合curly-curly语法使用?

问题解决与分析

修复代码让它正常运行

原代码的核心问题是未正确处理分组内的数据生成笛卡尔积,且未适配summarise的返回规则。以下是修复后的可运行代码:

library(dplyr)
library(tidyr)

f <- function(db, entity, trait) {
  db %>%
    summarise(
      # 先提取分组内的trait唯一值,将交叉结果包装为列表适配summarise
      i = list(crossing({{ trait }}, {{ trait }})),
      .by = {{ entity }}
    ) %>%
    unnest(i) # 展开列表列得到扁平化结果
}

db <- data.frame(
  entity = c("A", "A", "B", "B"),
  beta = c("X", "Y", "X", "Z")
)

f(db, entity, beta)

运行后会输出每个entity对应的trait笛卡尔积组合:

entity beta beta1
1      A    X     X
2      A    X     Y
3      A    Y     X
4      A    Y     Y
5      B    X     X
6      B    X     Z
7      B    Z     X
8      B    Z     Z

原代码的问题点

  • summarise默认要求每个分组返回单个值(或长度为1的对象),直接返回crossing生成的数据框会报错,需要用list()包装后再通过unnest展开。
  • 未针对分组内的trait值生成交叉,原写法会使用整个列的所有值,而非当前分组内的唯一值。

关于crossing和expand_grid的选择

两者都是生成笛卡尔积的工具,核心差异仅在于:

  • crossing会自动对输入去重并排序;expand_grid保留原始顺序和重复值。
  • 函数式编程中两者表现无本质差异,问题不在工具本身,而在于使用逻辑是否适配场景。如果需要保留原始顺序或重复值,可以直接替换crossing为expand_grid,示例如下:
f <- function(db, entity, trait) {
  db %>%
    summarise(
      i = list(expand_grid({{ trait }}, {{ trait }})),
      .by = {{ entity }}
    ) %>%
    unnest(i)
}

总结

tidyr在函数式编程中的表现不存在固有问题,只需正确理解分组逻辑和summarise的返回规则即可。crossing和expand_grid可根据需求灵活选择,无需刻意替换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:16:15