如何为数据框中每个ID的最近12个月的数据进行子集化?

And*_*w T 5 r date subset

我有一个数据框,代表了数百名患者的15年随访数据.我想创建数据框的子集,包括每个患者最近12个月的数据.

以下是我的数据的代表性示例(包括一个缺失值,因为在我的实际数据集中遗漏了大量数据):

# Create example dataset.
example.dat <- data.frame(
  ID = c(1,1,1,1,2,2,2,3,3,3), # patient ID numbers
  Date = as.Date(c("2000-02-01", "2004-10-21", "2005-02-06", # follow-up dates
                   "2005-06-14", "2002-11-24", "2009-03-05",
                   "2009-07-20", "2005-09-02", "2006-01-15",
                   "2006-05-18")),
  Cat = c("Yes", "Yes", "No", "Yes", "No", # responses to a categorical variable
          "Yes", "Yes", NA,   "No", "No")
  )

example.dat
Run Code Online (Sandbox Code Playgroud)

产生以下输出:

   ID       Date  Cat
1   1 2000-02-01  Yes
2   1 2004-10-21  Yes
3   1 2005-02-06   No
4   1 2005-06-14  Yes
5   2 2002-11-24   No
6   2 2009-03-05  Yes
7   2 2009-07-20  Yes
8   3 2005-09-02 <NA>
9   3 2006-01-15   No
10  3 2006-05-18   No
Run Code Online (Sandbox Code Playgroud)

我需要弄清楚如何为每个ID号分配最近的记录以及过去12个月的所有记录.

   ID       Date  Cat
2   1 2004-10-21  Yes
3   1 2005-02-06   No
4   1 2005-06-14  Yes
6   2 2009-03-05  Yes
7   2 2009-07-20  Yes
8   3 2005-09-02 <NA>
9   3 2006-01-15   No
10  3 2006-05-18   No
Run Code Online (Sandbox Code Playgroud)

关于按日期在R中进行子集化的问题已经有几个问题,但它们通常涉及从特定日期或日期范围中对数据进行子集化,而不是按((变量结束日期) - (时间间隔))进行子集化.

Uwe*_*Uwe 5

为了完整起见,这里有两种data.table使用按组子集或非等值连接的方法。此外,lubridate用于确保即使在闰年的情况下也选择 12 个月的时间段。

按组子集化

这本质上是docendo discimus答案data.table的版本。然而,函数用于日期算术,因为如果过去的一年包含闰日,简单地减去 365 天将无法涵盖 OP 所要求的 12 个月的时间dplyrlubridate

library(data.table)
library(lubridate)
setDT(example.dat)[, .SD[Date >= max(Date) %m-% years(1)], by = ID]
Run Code Online (Sandbox Code Playgroud)
   ID       Date Cat
1:  1 2004-10-21 Yes
2:  1 2005-02-06  No
3:  1 2005-06-14 Yes
4:  2 2009-03-05 Yes
5:  2 2009-07-20 Yes
6:  3 2005-09-02  NA
7:  3 2006-01-15  No
8:  3 2006-05-18  No
Run Code Online (Sandbox Code Playgroud)

非等值连接

使用v1.9.8 版本(2016 年 11 月 25 日在 CRAN 上)data.table已获得执行非等值连接的能力:

library(data.table)
library(lubridate)
mDT <- setDT(example.dat)[, max(Date) %m-% years(1), by = ID]
example.dat[example.dat[mDT, on = .(ID, Date >= V1), which = TRUE]]
Run Code Online (Sandbox Code Playgroud)
   ID       Date Cat
1:  1 2004-10-21 Yes
2:  1 2005-02-06  No
3:  1 2005-06-14 Yes
4:  2 2009-03-05 Yes
5:  2 2009-07-20 Yes
6:  3 2005-09-02  NA
7:  3 2006-01-15  No
8:  3 2006-05-18  No
Run Code Online (Sandbox Code Playgroud)

mDT包含每个 12 个月期间的开始日期ID

   ID         V1
1:  1 2004-06-14
2:  2 2008-07-20
3:  3 2005-05-18
Run Code Online (Sandbox Code Playgroud)

非等值连接返回满足条件的行的索引

example.dat[mDT, on = .(ID, Date >= V1), which = TRUE]
Run Code Online (Sandbox Code Playgroud)
[1]  2  3  4  6  7  8  9 10
Run Code Online (Sandbox Code Playgroud)

然后用于最终子集example.dat

日期运算方法比较

迄今为止发布的答案采用了三种不同的方法来查找 12 个月前的日期:

如果期间包含闰日,这三种方法会有所不同:

library(data.table)
library(lubridate)
mseq <- Vectorize(function(x) seq(x, length = 2L, by = "-1 year")[2L])
data.table(Date = as.Date("2016-02-28") + 0:2)[
  , minus_365d := Date -365][
    , minus_1yr := Date - years()][
      , minus_1yr_m := Date %m-% years()][
        , seq.Date := as_date(mseq(Date))][]
Run Code Online (Sandbox Code Playgroud)
         Date minus_365d  minus_1yr minus_1yr_m   seq.Date
1: 2016-02-28 2015-02-28 2015-02-28  2015-02-28 2015-02-28
2: 2016-02-29 2015-03-01       <NA>  2015-02-28 2015-03-01
3: 2016-03-01 2015-03-02 2015-03-01  2015-03-01 2015-03-01
Run Code Online (Sandbox Code Playgroud)
  • 如果过去的时间段中有no闰日,则所有三种方法都会返回相同的结果(第 1 行)。
  • 如果过去期间包含闰日,则减去 365 天并不能完全涵盖 12 个月(第 3 行),因为闰年​​有 366 天。
  • 如果参考日期闰日,则该seq.Date()方法会选择第二天,即 2015 年 3 月 1 日,因为 2015 年没有 2 月 29 日。使用lubridate's%m-%将日期滚动到 2 月的最后一天,即 2015 年 2 月 28 日。


G. *_*eck 3

这是一个基本解决方案。我们将ave日期作为数字进行操作,因为如果我们要使用原始"Date"ave,则会尝试返回"Date"值。相反,ave返回 0/1 值并将!!它们转换为 FALSE/TRUE。

 in_last_yr <- function(x) {
    max_date <- as.Date(max(x), "1970-01-01")
    x > seq(max_date, length = 2, by = "-1 year")[2]
 }
 subset(example.dat, !!ave(as.numeric(Date), ID, FUN = in_last_yr))
Run Code Online (Sandbox Code Playgroud)

更新 改进了确定去年的日期的方法。