使用data.table根据特定日期条件过滤观察值

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)

Fra*_*ank 6

这是@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每个定义的行,并将iddates向前推进六个月,然后查找找到的下一行(如果有)。连接的参数为:

  • 具有连接语法的表 x[i, ...]
    • x = dataIhave
    • i = 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的答案那样使用)。