我找不到其他答案,如果可以的话,我很抱歉,请指出正确的方向
我想测试一个大型数据集(因此没有循环),对于匹配一个变量的所有行(例如ID),然后测试第二个变量(例如Time)是否在2小时内。我想通过结合ID和时间来制作一个URN。
如果时间在2小时以内(小于或等于),我想使用与原始第一行相同的ID。
对于时差大于2小时的所有行,我想从此点开始创建新的URN。
使用数据可能更有意义:
ID Time URN URN_whichIwanttomake Index
hawk 09:05 hawk_09 hawk_09 1
hawk 09:10 hawk_09 hawk_09 2
hawk 10:00 hawk_10 hawk_09 3
hawk 11:00 hawk_11 hawk_09 4
hawk 15:00 hawk_15 hawk_15 5
hawk 16:00 hawk_16 hawk_15 6
eagle 12:00 eagle_12 eagle_12 7
eagle 12:20 eagle_12 eagle_12 8
eagle 12:45 eagle_12 eagle_12 9
eagle 13:50 eagle_13 eagle_12 10
eagle 14:00 eagle_14 eagle_12 11
eagle 14:30 eagle_14 eagle_14 12
eagle 15:15 eagle_15 eagle_14 13
我尝试在if语句中将向量与逻辑语句一起使用,我可以使我的逻辑起作用并返回正确的TRUE / FALSE向量,但是我不能用它来覆盖URN
到目前为止,我的代码:
IndexShiftedBy1 <- dt$Index + 1 # ie a vector which starts at 2 and goes up to 14
if ((dt$ID[dt$Index] == dt$ID[IndexShiftedBy1]) # ie if the two IDs are the same
& (dt$URN[dt$Index] != dt$URN[IndexShiftedBy1])) { # URN2 (ie time dependent) is NOT the same
dt$URN[IndexShiftedBy1] <- dt$URN[Index] } # overwrite lower row with upper row's value
现在这首先不起作用,其次,如果这样做了,我将不得不多次运行它,因为它只是将问题向下移动了!
非常感谢任何帮助,我显然缺少一个有用的功能/需要自己编写一个功能,但这超出了我的知识水平
答案 0 :(得分:1)
这是一个整洁的解决方案。关键组成部分是zoo::na.locf
(不是tidyverse),它用先前的非NA
值填充NA
值。
library(dplyr)
# library(zoo)
dat %>%
group_by(ID) %>%
mutate(
URN_new = if_else(c(TRUE, `units<-`(diff(Time), "hours") > 2), URN_original, NA_character_),
URN_new = zoo::na.locf(URN_new)
) %>%
ungroup()
# # A tibble: 13 x 5
# ID Time URN_original URN_whichIwanttomake URN_new
# <chr> <dttm> <chr> <chr> <chr>
# 1 hawk 2018-10-26 09:05:00 hawk_09 hawk_09 hawk_09
# 2 hawk 2018-10-26 09:10:00 hawk_09 hawk_09 hawk_09
# 3 hawk 2018-10-26 10:00:00 hawk_10 hawk_09 hawk_09
# 4 hawk 2018-10-26 11:00:00 hawk_11 hawk_09 hawk_09
# 5 hawk 2018-10-26 15:00:00 hawk_15 hawk_15 hawk_15
# 6 hawk 2018-10-26 16:00:00 hawk_16 hawk_15 hawk_15
# 7 eagle 2018-10-26 12:00:00 eagle_12 eagle_12 eagle_12
# 8 eagle 2018-10-26 12:20:00 eagle_12 eagle_12 eagle_12
# 9 eagle 2018-10-26 12:45:00 eagle_12 eagle_12 eagle_12
# 10 eagle 2018-10-26 13:50:00 eagle_13 eagle_12 eagle_12
# 11 eagle 2018-10-26 14:00:00 eagle_14 eagle_12 eagle_12
# 12 eagle 2018-10-26 14:30:00 eagle_14 eagle_14 eagle_12
# 13 eagle 2018-10-26 15:15:00 eagle_15 eagle_14 eagle_12
data.table
替代:
library(data.table)
datdt <- as.data.table(dat)
datdt[,
URN_newdt := zoo::na.locf(
ifelse(c(TRUE, `units<-`(diff(Time), "hours") > 2), URN_original, NA_character_)
),
by = "ID"]
基本R:
ave(dat, dat$ID, FUN = function(d) {
d$URN_newave <- zoo::na.locf(
ifelse(c(TRUE, `units<-`(diff(d$Time), "hours") > 2), d$URN_original, NA_character_)
)
d
})
简要说明:zoo::na.locf
用最近的非NA
值填充NA
:
zoo::na.locf(c("hawk_09", NA, NA, NA, "hawk_15", NA))
# [1] "hawk_09" "hawk_09" "hawk_09" "hawk_09" "hawk_15" "hawk_15"
知道,下一步是弄清楚当时间差小于两个小时时如何将NA
分配给新的URN。 diff(dat$Time)
足够直接,尽管因为它可以返回不同的单位而不会发出警告,所以我们需要将其封装在units<-(..., "hours")
中,以确保获得所需的东西。
下一步,diff
返回向量长度减去1,因此我们需要确定是否需要添加前缀或追加元素,并且该附加值应为TRUE
或FALSE
。在这种情况下,我们总是希望组中的第一个是原始的,因此在TRUE
前面加注最有意义。
数据:
dat <- read.table(header=TRUE, stringsAsFactors=FALSE, text="
ID Time URN_original URN_whichIwanttomake
hawk 09:05 hawk_09 hawk_09
hawk 09:10 hawk_09 hawk_09
hawk 10:00 hawk_10 hawk_09
hawk 11:00 hawk_11 hawk_09
hawk 15:00 hawk_15 hawk_15
hawk 16:00 hawk_16 hawk_15
eagle 12:00 eagle_12 eagle_12
eagle 12:20 eagle_12 eagle_12
eagle 12:45 eagle_12 eagle_12
eagle 13:50 eagle_13 eagle_12
eagle 14:00 eagle_14 eagle_12
eagle 14:30 eagle_14 eagle_14
eagle 15:15 eagle_15 eagle_14")
dat$Time <- as.POSIXct(paste(Sys.Date(), dat$Time))
为了方便起见,我在POSIXt
中使用“今天”。我建议您使用类似POSIXt
之类的东西,但要由您决定时间的差异。