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

tidyverse中summarise可调用函数疑问及分组处理异常排查

问题:dplyr分组summarise中自定义函数获取全量数据而非分组数据的原因及解决方法

我有一个名为samples的数据框,共50行,对应5个样本,每个样本10行,样本编号由sample_no列标记。我还有一个函数f,接收样本数据并返回单行汇总数据框。执行以下代码时:

samples %>%
group_by(sample_no) %>%
dplyr::summarise( d = f(.) ) %>%
unpack(cols = d)

发现f获取到了全部50行数据,而非每个分组对应的10行。但执行f(samples %>% filter(sample_no == 1))时,f能正确获取10行数据。请问是不是只有特定的「分组感知」函数才能在summarise中使用?还是存在其他问题?


最小可复现示例(MWE)

library(tidyverse)

SAMPLE_SIZE <- 10
NSAMPLES <- 5

fresh_sample <- function() {
  data.frame(F = rnorm(SAMPLE_SIZE, 0, 1))
}

# 我也想知道有没有更简洁的写法...
samples <- do.call(rbind, lapply(1:NSAMPLES, function(k) {
  fresh_sample() %>% mutate(sample_no = k)
}))

# 我实际不需要计算维度,真正要对样本做的计算复杂得多
dims <- function(sample) {
  data.frame(nrow = nrow(sample), ncol = ncol(sample))
}

# 返回1行数据框,nrow = 10,ncol = 2
dims(samples %>% filter(sample_no == 1))

# 返回5行数据框,每行的nrow = 50,ncol = 2
samples %>%
  group_by(sample_no) %>%
  dplyr::summarise(d = dims(.)) %>%
  unpack(cols = d)

问题原因

在dplyr::summarise()中直接传递.给自定义函数时,.代表的是带分组属性的整个分组tibble,而非当前分组的纯数据子集。当你在函数内部调用nrow()这类函数时,它会忽略分组属性,直接读取整个tibble的总行数,因此得到了全量的50行。

解决方法

方法1:用cur_data()提取当前分组的纯数据

cur_data()是dplyr提供的专用函数,用于在分组操作中获取当前分组的纯数据(不带分组属性)。修改summarise调用即可解决问题:

samples %>%
  group_by(sample_no) %>%
  dplyr::summarise(d = dims(cur_data())) %>%
  unpack(cols = d)

此时dims函数收到的是每个分组的10行数据,返回结果会正确显示每个分组的nrow=10。

方法2:将函数适配为分组感知型

如果你的函数逻辑允许,也可以将其改写为支持dplyr分组上下文的形式,但对于需要处理整个分组数据框的场景,cur_data()是最直接高效的方案。


额外优化:更简洁的样本数据生成方式

你提到想知道更简洁的样本生成写法,可以用purrr::map_dfr替代do.call(rbind, lapply(...)),代码更简洁易读:

# 写法1
samples <- map_dfr(1:NSAMPLES, function(k) {
  fresh_sample() %>% mutate(sample_no = k)
})

# 更简洁的匿名函数写法
samples <- map_dfr(1:NSAMPLES, ~fresh_sample() %>% mutate(sample_no = .x))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:11:02