以多列值和日期和时间计算为条件过滤 R 数据框
Filter R data frame conditioned on multiple column values and date & time calculation
我有一个包含超过 50 000 行的相机陷阱检测数据的数据框,我想识别 and/or 删除一个物种在指定时间段内对另一个物种同时发生的观察相机站.
下面是我的数据框示例:
Species StationID DateTime
1 Human A 2013-05-20 10:00:00
2 Dog A 2013-05-20 10:09:00
3 Dog A 2013-05-21 10:40:00
4 Puma B 2013-05-21 15:59:00
5 Dog B 2013-05-23 10:05:00
6 Human B 2013-05-23 10:10:00
如果我想 identify/remove 在同一摄像头站的人类检测两侧的 10 分钟内检测到所有狗,那么我希望 return 编辑以下数据:
Species StationID DateTime
1 Human A 2013-05-20 10:00:00
2 Dog A 2013-05-21 10:40:00
3 Puma B 2013-05-21 15:59:00
4 Human B 2013-05-23 10:10:00
除其他外,我尝试将人类和狗的检测拆分为单独的数据帧,并根据所需的 + 或 - 10 分钟的时间容差为狗的观察结果创建上下日期时间列。然后我使用了如下所示的 fuzzy_left_join,它在 StationID 上的调节效果很好,但它没有 return 基于指定的 DateTime 操作的正确检测。
Dog_HumanDF <- fuzzy_left_join(DogDF, HumanDF,
by = c("StationID" = "StationID",
"DateTimeDogLower" = "DateTimeHuman",
"DateTimeDogUpper" = "DateTimeHuman"),
match_fun = list(`==`, `<=` , `>=`))
我广泛搜索了类似的问题和解决方案,但找不到适合我目的的内容。我更喜欢不需要像 fuzzy_join 那样生成单独数据帧的解决方案。非常感谢任何帮助!
以下解决方案由 Barrett Wolfe 在另一个平台上提供,效果完美!我希望这对其他用户也有用。
no_bad_dogs <- function(df){
output <- list()
for(i in 1:length(unique(df$StationID))){
stat_df <- df[df$StationID==unique(df$StationID)[i],]
if("Human" %in% stat_df$Species & "Dog" %in% stat_df$Species){
HumanDF <- stat_df[stat_df$Species == "Human",]
dog_index <- which(stat_df$Species=="Dog")
DogDF <- stat_df[dog_index,]
bad_in_dog_index <- sapply(DogDF$DateTime, FUN = function(x, human_times){return(any( x >= human_times-600 & x <= human_times+600))},human_times = HumanDF$DateTime)
if(any(bad_in_dog_index)){
output[[i]] <- stat_df[-dog_index[bad_in_dog_index],]} else {output[[i]] <- stat_df }
} else { output[[i]] <- stat_df }
}
do.call("rbind", output)
}
我有一个包含超过 50 000 行的相机陷阱检测数据的数据框,我想识别 and/or 删除一个物种在指定时间段内对另一个物种同时发生的观察相机站.
下面是我的数据框示例:
Species StationID DateTime
1 Human A 2013-05-20 10:00:00
2 Dog A 2013-05-20 10:09:00
3 Dog A 2013-05-21 10:40:00
4 Puma B 2013-05-21 15:59:00
5 Dog B 2013-05-23 10:05:00
6 Human B 2013-05-23 10:10:00
如果我想 identify/remove 在同一摄像头站的人类检测两侧的 10 分钟内检测到所有狗,那么我希望 return 编辑以下数据:
Species StationID DateTime
1 Human A 2013-05-20 10:00:00
2 Dog A 2013-05-21 10:40:00
3 Puma B 2013-05-21 15:59:00
4 Human B 2013-05-23 10:10:00
除其他外,我尝试将人类和狗的检测拆分为单独的数据帧,并根据所需的 + 或 - 10 分钟的时间容差为狗的观察结果创建上下日期时间列。然后我使用了如下所示的 fuzzy_left_join,它在 StationID 上的调节效果很好,但它没有 return 基于指定的 DateTime 操作的正确检测。
Dog_HumanDF <- fuzzy_left_join(DogDF, HumanDF,
by = c("StationID" = "StationID",
"DateTimeDogLower" = "DateTimeHuman",
"DateTimeDogUpper" = "DateTimeHuman"),
match_fun = list(`==`, `<=` , `>=`))
我广泛搜索了类似的问题和解决方案,但找不到适合我目的的内容。我更喜欢不需要像 fuzzy_join 那样生成单独数据帧的解决方案。非常感谢任何帮助!
以下解决方案由 Barrett Wolfe 在另一个平台上提供,效果完美!我希望这对其他用户也有用。
no_bad_dogs <- function(df){
output <- list()
for(i in 1:length(unique(df$StationID))){
stat_df <- df[df$StationID==unique(df$StationID)[i],]
if("Human" %in% stat_df$Species & "Dog" %in% stat_df$Species){
HumanDF <- stat_df[stat_df$Species == "Human",]
dog_index <- which(stat_df$Species=="Dog")
DogDF <- stat_df[dog_index,]
bad_in_dog_index <- sapply(DogDF$DateTime, FUN = function(x, human_times){return(any( x >= human_times-600 & x <= human_times+600))},human_times = HumanDF$DateTime)
if(any(bad_in_dog_index)){
output[[i]] <- stat_df[-dog_index[bad_in_dog_index],]} else {output[[i]] <- stat_df }
} else { output[[i]] <- stat_df }
}
do.call("rbind", output)
}