如何在R中按条件筛选每周从首次降雨至周末的时段?
问题
我开展了多次为期约一周的实验,希望保留每周中从首次出现precipitation(降雨)开始至周末的行/时段。已掌握如何剔除完全无雨的周,但不清楚如何筛选有雨周中从首次降雨到周末的时段。
数据规则说明:
- 在
week 15中,仅需保留第144至150行,其余行剔除; - 完全无雨的
week 16需整周剔除。
注意:允许周内存在多次干湿交替时段,核心是忽略每周首次降雨前的无雨时段。
可复现代码:
df <- structure( list( week = structure( c( 1L,1L,1L,1L,1L,1L,1L,1L,1L,1L, 2L,2L,2L,2L,2L,2L,2L,2L,2L,2L, 3L,3L,3L,3L,3L,3L,3L,3L,3L,3L, 4L,4L,4L,4L,4L,4L,4L,4L,4L,4L, 5L,5L,5L,5L,5L,5L,5L,5L,5L,5L, 6L,6L,6L,6L,6L,6L,6L,6L,6L,6L, 7L,7L,7L,7L,7L,7L,7L,7L,7L,7L, 8L,8L,8L,8L,8L,8L,8L,8L,8L,8L, 9L,9L,9L,9L,9L,9L,9L,9L,9L,9L, 10L,10L,10L,10L,10L,10L,10L,10L,10L,10L, 11L,11L,11L,11L,11L,11L,11L,11L,11L,11L, 12L,12L,12L,12L,12L,12L,12L,12L,12L,12L, 13L,13L,13L,13L,13L,13L,13L,13L,13L,13L, 14L,14L,14L,14L,14L,14L,14L,14L,14L,14L, 15L,15L,15L,15L,15L,15L,15L,15L,15L,15L, 16L,16L,16L,16L,16L,16L,16L,16L,16L,16L, 17L,17L,17L,17L,17L,17L,17L,17L,17L,17L, 18L,18L,18L,18L,18L,18L,18L,18L,18L,18L, 19L,19L,19L,19L,19L,19L,19L,19L,19L,19L, 20L,20L,20L,20L,20L,20L,20L,20L,20L,20L, 21L,21L,21L,21L,21L,21L,21L,21L,21L,21L, 22L,22L,22L,22L,22L,22L,22L,22L,22L,22L, 23L,23L,23L,23L,23L,23L,23L,23L,23L,23L, 24L,24L,24L,24L,24L,24L,24L,24L,24L,24L, 25L,25L,25L,25L,25L,25L,25L,25L,25L,25L, 26L,26L,26L,26L,26L,26L,26L,26L,26L,26L ), .Label = c( "1","2","3","4","5","6","7","8","9","10", "11","12","13","14","15","16","17","18","19","20", "21","22","23","24","25","26" ), class = "factor" ), precipitation = c( rep(0,110), 1.59999999999997,0.800000000000011,0.600000000000023,0.199999999999989, 0.399999999999977,0.400000000000034,1,0.799999999999955,0.400000000000034, 0.800000000000011,rep(0,30),9.60000000000002,rep(0,19),1,rep(0,9), 0.200000000000045,rep(0,29),0.200000002980232,rep(0,9) ) ), class = c("tbl_df","tbl","data.frame"), row.names = c(NA,-260L) )
解决方案
方法一:使用dplyr(tidyverse)
按周分组处理,先剔除无雨周,再保留首次降雨及之后的所有行:
library(dplyr) result <- df %>% group_by(week) %>% # 过滤掉整周无降雨的组 filter(any(precipitation > 0)) %>% # 筛选首次降雨及之后的行:累计降雨次数≥1即代表已过首次降雨节点 filter(cumsum(precipitation > 0) >= 1) %>% ungroup() # 验证week15结果(应保留第144-150行) result %>% filter(week == "15")
逻辑说明:
group_by(week):将数据按周拆分分组filter(any(precipitation > 0)):直接剔除无降雨的周(如week16)filter(cumsum(precipitation > 0) >= 1):通过累计统计降雨事件,首次降雨前累计值为0,首次降雨及之后累计值≥1,以此精准筛选目标时段
方法二:使用Base R
无需加载额外包,通过基础函数实现:
# 先标记每个周是否存在降雨 has_rain <- tapply(df$precipitation, df$week, function(x) any(x > 0)) # 筛选出有降雨的周的数据 df_filtered <- df[df$week %in% names(has_rain)[has_rain], ] # 对每个有降雨的周,提取首次降雨至周末的行 result_base <- do.call(rbind, lapply(split(df_filtered, df_filtered$week), function(week_data) { first_rain_idx <- which(week_data$precipitation > 0)[1] week_data[first_rain_idx:nrow(week_data), ] })) # 验证week15结果 result_base[result_base$week == "15", ]
逻辑说明:
tapply(...):统计每个周是否存在降雨记录- 先筛选出所有有降雨的周的数据
split(...)按周拆分数据,lapply(...)找到每个周首次降雨的索引,保留从该索引到末尾的行do.call(rbind, ...)将各周处理后的结果合并为最终数据框
内容的提问来源于stack exchange,提问作者Ahsk
相关产品推荐
相关产品推荐

