基于时间范围标记距NA值12小时内的温度数据行
问题描述
我有一个来自数据记录仪的温度数据tibble,希望使用dplyr::mutate()或其他{tidyverse}工具生成新列,标记出所有位于温度NA值12小时范围内的数据行。该时间序列存在完全缺失的间隙(并非仅记录为NA),因此基于行索引的方法无效,必须通过时间范围实现。
如何设置mutate命令,使距缺失温度12小时内的行返回TRUE,否则返回FALSE?
示例代码
library(tibble) library(lubridate) # 需加载lubridate处理时间 temp.dat <- tibble( temperature = c(4,4.3,4.4,4.4,4.5,4.6,NA,NA,4.4,4.3), date.time = c( as_datetime("2012-09-29 18:00:00"), as_datetime("2012-09-30 00:00:00"), as_datetime("2012-09-30 06:00:00"), as_datetime("2012-09-30 12:00:00"), as_datetime("2012-09-30 18:00:00"), as_datetime("2012-10-01 00:00:00"), as_datetime("2012-10-01 06:00:00"), as_datetime("2012-10-01 12:00:00"), as_datetime("2012-10-01 18:00:00"), as_datetime("2012-10-02 00:00:00") ) )
示例数据
# A tibble: 10 × 2 temperature date.time <dbl> <dttm> 1 4 2012-09-29 18:00:00 2 4.3 2012-09-30 00:00:00 3 4.4 2012-09-30 06:00:00 4 4.4 2012-09-30 12:00:00 5 4.5 2012-09-30 18:00:00 6 4.6 2012-10-01 00:00:00 7 NA 2012-10-01 06:00:00 8 NA 2012-10-01 12:00:00 9 4.4 2012-10-01 18:00:00 10 4.3 2012-10-02 00:00:00
期望输出
# A tibble: 10 × 3 temperature date.time censor <dbl> <dttm> <chr> 1 4 2012-09-29 18:00:00 F 2 4.3 2012-09-30 00:00:00 F 3 4.4 2012-09-30 06:00:00 F 4 4.4 2012-09-30 12:00:00 F 5 4.5 2012-09-30 18:00:00 T 6 4.6 2012-10-01 00:00:00 T 7 NA 2012-10-01 06:00:00 T 8 NA 2012-10-01 12:00:00 T 9 4.4 2012-10-01 18:00:00 T 10 4.3 2012-10-02 00:00:00 T
尝试过的代码及问题
temp.dat%>%mutate(censor=if_else(NA %in% temp.dat[match(c(date.time, date.time-hours(12), date.time+hours(12)), temp.dat$date.time),]$temperature,"T","F"))
该代码会将所有行的censor值设为TRUE,原因是match()只能匹配数据中精确存在的时间点,而时间序列存在缺失间隙,大部分±12小时的时间点不在数据中,match()返回NA,导致判断逻辑失效。我们需要的是基于时间范围重叠的判断,而非精确时间匹配。
解决方案
利用lubridate的时间区间功能,结合dplyr的行级判断即可实现需求:
步骤1:提取所有温度为NA的时间点
library(dplyr) library(lubridate) library(purrr) # 用于map_lgl # 获取所有NA对应的时间点 na_time_points <- temp.dat %>% filter(is.na(temperature)) %>% pull(date.time)
步骤2:生成标记列
通过map_lgl()对每行的时间点,判断其是否落在任何一个NA时间点的±12小时区间内:
result <- temp.dat %>% mutate( # 判断当前时间是否在任意NA时间的±12小时范围内 censor = map_lgl(date.time, ~ any(.x %within% interval(na_time_points - hours(12), na_time_points + hours(12)))), # 转成期望的"T"/"F"字符格式 censor = if_else(censor, "T", "F") ) print(result)
替代方案(使用rowwise)
如果不习惯purrr,也可以用rowwise()实现行级判断:
result <- temp.dat %>% rowwise() %>% mutate( censor = any(date.time %within% interval(na_time_points - hours(12), na_time_points + hours(12))), censor = if_else(censor, "T", "F") ) %>% ungroup()
输出验证
运行上述代码后,得到的结果与期望输出完全一致:
# A tibble: 10 × 3 temperature date.time censor <dbl> <dttm> <chr> 1 4 2012-09-29 18:00:00 F 2 4.3 2012-09-30 00:00:00 F 3 4.4 2012-09-30 06:00:00 F 4 4.4 2012-09-30 12:00:00 F 5 4.5 2012-09-30 18:00:00 T 6 4.6 2012-10-01 00:00:00 T 7 NA 2012-10-01 06:00:00 T 8 NA 2012-10-01 12:00:00 T 9 4.4 2012-10-01 18:00:00 T 10 4.3 2012-10-02 00:00:00 T
内容的提问来源于stack exchange,提问作者ghaines
相关产品推荐
相关产品推荐

