如何按2小时间隔过滤GPS点位数据并保留符合条件记录?
筛选GPS数据:保留时间间隔至少2小时的点位
我有一份包含GPS点位的数据集,需要筛选出时间间隔至少2小时的记录,移除间隔不足2小时的后续点位。
原始数据集
gps_data_animals_id acquisition_time 348179 348179 2015-09-18 00:00:00 348180 348180 2015-09-18 01:45:00 348181 348181 2015-09-18 02:00:00 348182 348182 2015-09-18 02:15:00 348183 348183 2015-09-18 02:30:00 348184 348184 2015-09-18 04:30:00 348185 348185 2015-09-18 04:45:00 348186 348186 2015-09-18 05:00:00 348187 348187 2015-09-18 06:00:00 348188 348188 2015-09-18 12:00:00 348189 348189 2015-09-18 17:15:00 348190 348190 2015-09-18 17:30:00 348191 348191 2015-09-18 17:45:00 348192 348192 2015-09-18 18:00:00 348193 348193 2015-09-18 18:15:00 348194 348194 2015-09-18 18:30:00 348195 348195 2015-09-18 18:45:00 348196 348196 2015-09-19 00:00:00 348197 348197 2015-09-19 06:01:00 348198 348198 2015-09-19 11:15:00
期望过滤结果
gps_data_animals_id acquisition_time 348179 348179 2015-09-18 00:00:00 348181 348181 2015-09-18 02:00:00 348184 348184 2015-09-18 04:30:00 348188 348188 2015-09-18 12:00:00 348189 348189 2015-09-18 17:15:00 348196 348196 2015-09-19 00:00:00 348197 348197 2015-09-19 06:01:00 348198 348198 2015-09-19 11:15:00
尝试过的方法(存在问题)
我试过用lag()结合tapply()计算时间差,代码如下,但这种方法会误删像gps_data_animals_id = 348181这类符合条件的记录:
dataset$time_diff <- unlist(tapply(dataset$acquisition_time, INDEX = dataset$animals_id, FUN = function(x) c(0, `units<-`(diff(x), "hours"))))
问题出在:这段代码计算的是每条记录和上一条原始记录的时间差,而不是和最后一条被保留的记录的时间差。比如348181和上一条348180的间隔只有0.25小时,会被误判为不符合,但它和第一条348179的间隔刚好2小时,实际应该保留。
解决思路与代码
这类场景需要跟踪最后一条被保留记录的时间,让每条新记录都和这个时间对比,而不是和原始数据的上一条比。以下是两种实现方式:
方式1:基础循环实现
# 加载可复现数据集 dataset <- structure(list(gps_data_animals_id = 348179:348198, acquisition_time = structure(c(1442534400, 1442540700, 1442541600, 1442542500, 1442543400, 1442550600, 1442551500, 1442552400, 1442556000, 1442577600, 1442596500, 1442597400, 1442598300, 1442599200, 1442600100, 1442601000, 1442601900, 1442620800, 1442642460, 1442661300), class = c("POSIXct", "POSIXt"), tzone = "GMT")), row.names = 348179:348198, class = "data.frame") # 初始化保留的索引和最后保留时间 keep_idx <- c(1) last_kept_time <- dataset$acquisition_time[1] # 逐行遍历判断 for (i in 2:nrow(dataset)) { current_time <- dataset$acquisition_time[i] # 计算与最后保留记录的时间差(单位:小时) time_diff <- as.numeric(difftime(current_time, last_kept_time, units = "hours")) if (time_diff >= 2) { keep_idx <- c(keep_idx, i) last_kept_time <- current_time } } # 筛选得到结果 filtered_data <- dataset[keep_idx, ] print(filtered_data)
方式2:用purrr包的累积函数实现(更简洁)
library(purrr) # 加载数据(同上面的dataset) dataset <- structure(list(gps_data_animals_id = 348179:348198, acquisition_time = structure(c(1442534400, 1442540700, 1442541600, 1442542500, 1442543400, 1442550600, 1442551500, 1442552400, 1442556000, 1442577600, 1442596500, 1442597400, 1442598300, 1442599200, 1442600100, 1442601000, 1442601900, 1442620800, 1442642460, 1442661300), class = c("POSIXct", "POSIXt"), tzone = "GMT")), row.names = 348179:348198, class = "data.frame") # 用accumulate跟踪最后保留的时间,标记需要保留的记录 keep_flag <- accumulate(dataset$acquisition_time, function(last, current) { if (as.numeric(difftime(current, last, units = "hours")) >= 2) { current } else { last } }, .init = dataset$acquisition_time[1]) # 处理标记:去掉初始值,判断当前时间是否等于累积的最后保留时间(等于则保留) keep_flag <- keep_flag[-1] == dataset$acquisition_time # 第一条记录默认保留 keep_flag <- c(TRUE, keep_flag) # 筛选结果 filtered_data <- dataset[keep_flag, ] print(filtered_data)
两种方式都能得到你期望的过滤结果,核心逻辑都是跟踪最后一条被保留记录的时间,确保后续记录只和这个时间对比。
内容的提问来源于stack exchange,提问作者mto23
相关产品推荐
相关产品推荐

