如何为国家-年份维度自然灾害数据框创建自上次事件以来的年份计数变量(R语言一行高效实现)
一行代码实现
years_since变量计算 当然有办法用一行(链式)代码高效搞定这个需求!我来给你分享一个基于dplyr的简洁实现,完全匹配你的要求:
library(dplyr) test <- test %>% group_by(country) %>% mutate(years_since = replace(cumsum(ifelse(!is.na(incident), 0, 1)) * NA^(cumsum(!is.na(incident)) == 0), !is.na(incident), 0)) %>% ungroup()
代码逻辑拆解:
- 先通过
group_by(country)按国家分组,保证每个国家的计算独立进行 - 核心计算部分分几步:
ifelse(!is.na(incident), 0, 1):把有灾害的行标记为0,无灾害的标记为1cumsum(...):对标记值累加,这样每次遇到灾害行时累加值不会增加(加0),之后的行依次递增1NA^(cumsum(!is.na(incident)) == 0):生成一个“掩码”——首次灾害发生前的所有行,cumsum(!is.na(incident))结果为0,NA^0等于NA;灾害发生后的行则会乘以1,保留累加值- 最后用
replace(..., !is.na(incident), 0)把所有有灾害的行强制设为0,完美处理连续灾害的情况(比如bbb的1993和1994年)
ungroup()取消分组,恢复数据框的常规状态
运行结果验证
执行后你会得到完全符合预期的输出:
# A tibble: 18 × 4 year country incident years_since <int> <chr> <chr> <dbl> 1 1990 aaa NA NA 2 1991 aaa Drought 0 3 1992 aaa NA 1 4 1993 aaa NA 2 5 1994 aaa NA 3 6 1995 aaa NA 4 7 1990 bbb NA NA 8 1991 bbb NA NA 9 1992 bbb NA NA 10 1993 bbb Flood 0 11 1994 bbb Flood 0 12 1995 bbb NA 1 13 1990 ccc NA NA 14 1991 ccc NA NA 15 1992 ccc NA NA 16 1993 ccc NA NA 17 1994 ccc NA NA 18 1995 ccc NA NA
如果不想依赖dplyr,也可以用基础R写一行(虽然可读性稍差):
test$years_since <- unlist(tapply(seq(nrow(test)), test$country, function(x) { inc_flag <- !is.na(test$incident[x]) res <- cumsum(!inc_flag) res[!cumsum(inc_flag)] <- NA res[inc_flag] <- 0 res }))
不过显然dplyr的链式写法更简洁直观,也更贴合现代R数据分析的习惯。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

