iHa*_*ing 3 r dplyr data.table
我有一组观察结果,这些观察结果在用户每次执行操作时都会记录下来。我只想过滤用户相隔六个月或更长时间的观察结果。
因此,如果用户对“ 2018-01-01”,“ 2018-03-01”和“ 2018-07-01”采取了此操作,我只希望仅保留“ 2018-01-01”和“ 2018” -07-01”。
同样,如果用户对“ 2018-01-01”,“ 2018-03-01”,“ 2018-07-01”和“ 2019-03-01”采取了措施,我只想保留“ 2018-01” -01“,” 2018-07-01“,” 2019-03-01“。
到目前为止,我已经编写了很长且不可行的代码。
# What I want to achieve
library(data.table)
dataIhave <- data.table(id = c(1, 1, 1, 1, 2, 2, 3, 4),
dates = c("2018-01-01",
"2018-03-01",
"2018-07-01",
"2019-01-01",
"2018-01-03",
"2018-07-02",
"2018-02-01",
"2018-02-01"))
dataIwant <- data.table(id = c(1, 1, 1, 2, 3, 4),
dates = c("2018-01-01",
"2018-07-01",
"2019-01-01",
"2018-01-01",
"2018-02-01",
"2018-02-01"))
Run Code Online (Sandbox Code Playgroud)
这是@Uwe答案的滚动联接变体:
library(lubridate)
dataIhave[, dates := as.IDate(dates)]
ids = unique(dataIhave$id)
dataIhave[, seq := NA_integer_]
s = 1L
w = dataIhave[.(ids), on=.(id), mult="first", which = TRUE]
dataIhave[w, seq := s]
while (TRUE){
w = dataIhave[
dataIhave[w, .(id, dates = dates %m+% months(6))],
on = .(id, dates), roll = -Inf, nomatch = 0, which = TRUE
]
if (!length(w)) break
s = s + 1L
dataIhave[w, seq := s]
}
dataIhave[!is.na(seq)]
id dates seq
1: 1 2018-01-01 1
2: 1 2018-07-01 2
3: 1 2019-01-01 3
4: 2 2018-01-03 1
5: 3 2018-02-01 1
6: 4 2018-02-01 1
Run Code Online (Sandbox Code Playgroud)
循环将获取w每个定义的行,并将id其dates向前推进六个月,然后查找找到的下一行(如果有)。连接的参数为:
x[i, ...]
x = dataIhavei = dataIhave[w, .(id, dates = dates %m+% months(6))]on = .(id, date):要匹配的列roll = -Inf:在中的最后一列找到下一个匹配项 on=nomatch = 0:如果找不到匹配项,请跳过which = TRUE:返回匹配的行号此外,如果有重复的日期(请参阅@Uwe帖子中的第二个示例):
mult = "first":仅对第一行进行第一场比赛 i在选择id循环之前的第一行时,我假设数据是按dates内部排序的id(所以我不像order@Uwe的答案那样使用)。