按plot和location分组统计两有效值间的NA数量
问题
需求为按plot和location两个变量分组,统计每个有效值与上一个有效值之间出现的NA数量。
数据示例
df <- data.frame(year = seq(from = 2001, to = 2009, by = 1), plot = rep(c('p_1','p_2'), each = 18, times = 1), location = c(rep(c('A', 'B'), each = 9, times = 2)), n = c(c(4,6,NA,8,9,NA,NA,NA,10), c(2,4,5,6,7,4,3,NA,NA)))
预期结果
data.frame(year = seq(from = 2001, to = 2009, by = 1), plot = rep(c('p_1','p_2'), each = 9, times = 2), location = c(rep(c('A', 'B'), each = 9, times = 2)), n = c(c(4,6,NA,8,9,NA,NA,NA,10), c(2,4,5,6,7,4,3,NA,NA)), count = c(c(0,0,0,1,0,0,0,0,3), c(0,0,0,0,0,0,0,0,0)))
现有尝试及问题
通过创建哑变量miss(有效值赋值为0,NA赋值为1)并计算累积和的方式,仅在分组内首次遇到NA时结果正确,后续会持续累加该分组内所有NA,无法得到预期结果:
library(tidyverse) df %>% mutate(miss = ifelse(is.na(n), 1, 0)) %>% group_by(plot, location) %>% summarize(plot = plot, location = location, year = year, n = n, count = dplyr::lag(cumsum(miss))+1) %>% mutate(count = ifelse(is.na(count), -1, ifelse(is.na(n), 0, count)))
解决方案
可以通过分组后标记有效值区间的方式实现需求,具体代码如下:
library(tidyverse) df_result <- df %>% group_by(plot, location) %>% # 标记有效值(非NA为1,NA为0) mutate(valid = as.integer(!is.na(n))) %>% # 生成有效值区间分组ID,每个有效值开启一个新分组 mutate(group_id = cumsum(valid)) %>% # 按区间分组统计该组内的NA数量 group_by(plot, location, group_id) %>% mutate(na_count = sum(is.na(n))) %>% # 整理count列:NA行设为0,首个有效值设为0,其余有效值对应区间内的NA数 mutate(count = ifelse(is.na(n), 0, ifelse(group_id == 0, 0, na_count))) %>% # 移除辅助列 select(-valid, -group_id, -na_count) %>% ungroup() # 输出结果 print(df_result)
逻辑说明
- 标记有效值:用
valid列区分有效值与NA,为后续分组做准备; - 生成区间ID:通过
cumsum(valid)让每个有效值成为新分组的起点,相邻有效值之间的NA会被归为同一组; - 统计区间NA数:在每个区间内统计NA的总数,这个数量就是当前有效值与上一个有效值之间的NA数量;
- 整理结果列:将NA行的
count设为0,首个有效值没有前置NA,所以count为0,其余有效值直接匹配对应区间的NA数。
内容的提问来源于stack exchange,提问作者Héctor Miranda
相关产品推荐
相关产品推荐

