如何按ID和Date筛选各站点水深最下方4米的Oxygen测量数据
问题
我正在研究丹麦近海水域过去40年间,不同深度底拖网作业与氧气浓度的关联。现有数据框Oxy包含四列:ID(站点ID)、Date(采样日期)、Depth(采样深度)和Oxygen(氧气浓度),Oxygen值在不同年份、不同站点、0-50米的不同深度处测得。
需要构建一个新数据框,提取每个站点(ID)和对应日期(Date)下,水深最下方4米(从该站点当日最深深度向上4米范围)的Oxygen测量数据。但Depth的测量间隔不固定,不同ID的采样深度存在差异(如有的采样于0.2、0.4米,有的采样于0.67、1.3米),且各站点的最深测量深度也不同(如有的最深为30米,有的为46米)。
数据规模约400万行,数据示例如下:
ID Date Depth Oxygen ------ ---------- ----- ------ 957001 2002-01-14 1.20 12.10 967503 2002-01-28 2.00 11.60 957001 2002-01-22 25.00 7.80 965206 2002-01-28 5.40 11.70 953001 2002-01-31 23.60 10.30 941101 2002-01-22 8.67 12.00 940201 2002-01-17 5.00 11.70 965404 2002-01-30 38.80 9.40 952003 2002-01-08 23.40 6.30 957101 2002-01-15 6.00 11.60
此前尝试用arrange()、group_by()和slice()提取最高值或前N个最深值,但因深度间隔不统一,无法满足各ID和Date的统一筛选需求。期望逻辑:取每个ID和Date下的最深Depth值,保留该值减4范围内的所有数据。目标数据示例如下:
ID Date Depth Oxygen ------ ---------- ----- ------ 957001 2002-01-14 30.20 2.10 967503 2002-01-28 28.00 1.60 957001 2002-01-22 29.00 7.80 965206 2002-01-28 30.40 5.70 953001 2002-01-31 23.60 10.30 941101 2002-01-22 28.67 7.00 940201 2002-01-17 30.00 8.70 965404 2002-01-30 38.80 9.40 952003 2002-01-08 23.40 6.30 957101 2002-01-15 46.00 1.60
解决方案
方法1:使用dplyr(适配tidyverse工作流)
核心逻辑是按ID和Date分组,计算每组最深深度,再筛选出深度在最深深度-4到最深深度之间的行:
library(dplyr) Oxy_filtered <- Oxy %>% group_by(ID, Date) %>% mutate(max_depth = max(Depth, na.rm = TRUE)) %>% filter(Depth >= max_depth - 4) %>% select(-max_depth) %>% ungroup()
方法2:使用data.table(适配大数据量,效率更优)
针对400万行的大规模数据,data.table的运算速度更快,代码更简洁:
library(data.table) setDT(Oxy) Oxy_filtered <- Oxy[, .SD[Depth >= max(Depth, na.rm = TRUE) - 4], by = .(ID, Date)]
注意事项
- 若数据存在
Depth缺失值,na.rm = TRUE可确保计算最大深度时忽略缺失值,避免逻辑错误。 - 两种方法均保留目标深度范围内的所有测量数据,而非仅最深的单个值,完全匹配需求。
内容的提问来源于stack exchange,提问作者Erik Christensen
相关产品推荐
相关产品推荐

