分组计算不含当前观测值的累积均值(忽略NA值)
解决分组计算前序非NA值累积均值的问题
我明白你想实现的需求:给每个类别的每条记录计算截至前一个观测值的非NA值累积均值(不含当前值),而且当前值是NA时新列也要是NA。你之前的代码因为cummean无法正确跳过NA,而且分组逻辑有问题,所以没得到正确结果,我来给你一个可行的方案。
首先先确认我们的输入数据:
df <- data.frame( category = c("cat1","cat1","cat2","cat1","cat2","cat2","cat1","cat2"), value = c(NA,2,3,4,5,NA,7,8) )
解决方案代码
我们可以通过手动计算累积和与累积计数的方式,精准控制NA的处理逻辑:
library(dplyr) df_final <- df %>% group_by(category) %>% mutate( # 计算当前行及之前所有非NA值的累积和 cum_sum_non_na = cumsum(ifelse(is.na(value), 0, value)), # 计算当前行及之前所有非NA值的数量 cum_count_non_na = cumsum(ifelse(is.na(value), 0, 1)), # 取前一行的累积和与计数,计算均值;如果前面没有非NA值或当前值是NA,返回NA new_col = case_when( is.na(value) ~ NA_real_, lag(cum_count_non_na) == 0 ~ NA_real_, TRUE ~ lag(cum_sum_non_na) / lag(cum_count_non_na) ) ) %>% ungroup() %>% select(-cum_sum_non_na, -cum_count_non_na) # 移除中间计算列
代码解释
- 分组逻辑:只按
category分组,确保每个类别独立计算累积值,而不是把NA和非NA拆分开。 - 累积统计:
cum_sum_non_na:遍历每个分组时,遇到NA就加0,遇到有效值就累加,这样得到的是到当前行为止的所有非NA值总和。cum_count_non_na:同理,统计到当前行为止的非NA值数量。
- 计算前序均值:
- 用
lag()取前一行的累积和与计数,相除得到前序非NA值的均值。 - 通过
case_when处理两种特殊情况:当前值是NA时,新列设为NA;如果前面没有任何非NA值(比如分组的前几个观测都是NA),也返回NA。
- 用
最终结果
运行代码后得到的df_final如下:
# A tibble: 8 × 3 category value new_col <chr> <dbl> <dbl> 1 cat1 NA NA 2 cat1 2 NA 3 cat2 3 NA 4 cat1 4 2 5 cat2 5 3 6 cat2 NA NA 7 cat1 7 3 8 cat2 8 4
这个结果完全符合需求:每个有效值对应的新列是该类别之前所有非NA值的平均,NA值对应的新列也是NA。
内容的提问来源于stack exchange,提问作者John F
相关产品推荐
相关产品推荐

