R语言按ID分组计算各分组前10%数值均值的实现方法
R按分组计算前10%数值均值实现方案
slice_head分组场景报错的核心原因是没有基于分组维度动态计算截取行数,固定传参的写法在各组样本量不一致时会触发索引越界或截取逻辑错误,以下是两种可直接复用的实现方式:
示例数据
先复现你给出的测试数据:
df <- data.frame( ID = c("A","A","A","A","B","B","C","C"), Time = c(0,1,2,3,0,1,0,1), Value = c(84,90,76,98,64,81,89,76) )
对应结构如下:
| ID | Time | Value |
|---|---|---|
| A | 0 | 84 |
| A | 1 | 90 |
| A | 2 | 76 |
| A | 3 | 98 |
| B | 0 | 64 |
| B | 1 | 81 |
| C | 0 | 89 |
| C | 1 | 76 |
方法1:dplyr实现(适配你之前的slice+aggregate编码习惯)
如果你的需求是计算每个ID分组下,Value值最高的前10%数据的均值,代码如下:
library(dplyr) res <- df %>% group_by(ID) %>% # 按Value降序排序,同组内大值在前;如果要按Time顺序取前10%行,把这行改成arrange(Time, .by_group = TRUE) arrange(desc(Value), .by_group = TRUE) %>% # 动态计算每组截取行数:ceiling为向上取整,避免小样本组截取行数为0;要严格向下取整换floor即可 slice_head(n = ceiling(n() * 0.1)) %>% summarise(top10_pct_mean = mean(Value, na.rm = TRUE))
运行测试数据得到的结果:
- ID=A:共4行,前10%向上取整保留1行(Value=98),均值为98
- ID=B:共2行,前10%向上取整保留1行(Value=81),均值为81
- ID=C:共2行,前10%向上取整保留1行(Value=89),均值为89
方法2:data.table实现(百万级以上大数据量场景性能更优)
library(data.table) setDT(df) res <- df[ order(ID, -Value), .(top10_pct_mean = mean(head(Value, ceiling(.N * 0.1)), na.rm = TRUE)), by = ID ]
注意:之前用
lapply/map2实现失败,基本都是因为拆分分组后没有正确获取单组样本量,或者排序、索引逻辑错位,直接用分组计算函数内置的分组计数符号(dplyr里的n()、data.table里的.N)可以避免这类问题。
内容的提问来源于stack exchange,提问作者kbf
相关产品推荐
相关产品推荐

