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

时间:2014-07-25 15:23:36

标签: 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

产生以下输出:

   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

我需要弄清楚如何为每个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

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

3 个答案:

答案 0 :(得分:4)

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

按组进行子集

这绝对是docendo discimus' dplyr answerdata.table版本。但是,lubridate函数用于日期算术,因为如果过去的一年包含闰日,简单地减去365天将不会覆盖OP请求的12个月期间:

library(data.table)
library(lubridate)
setDT(example.dat)[, .SD[Date >= max(Date) %m-% years(1)], by = ID]
   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

非平等加入

使用版本v1.9.8 (on CRAN 25 Nov 2016)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]]
   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

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

   ID         V1
1:  1 2004-06-14
2:  2 2008-07-20
3:  3 2005-05-18

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

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

然后用于最终子集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))][]
         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
  • 如果过去一段时间内有no个闰日,则所有三种方法都会返回相同的结果(第1行)。
  • 如果过去一段时间内包含闰日,则减去365天并不完全涵盖12个月(第3行),因为闰年​​有366天。
  • 如果参考日期 是闰日,则seq.Date()方法会选择2015年3月1日的第二天,因为2015年2月29日没有。使用lubridate '%m-%将日期推迟到2015年2月28日的最后一天,而不是。

答案 1 :(得分:3)

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

!!

更新确定去年哪些天数的改进方法。

答案 2 :(得分:2)

使用dplyr

的可行方法
library(dplyr)

example.dat %>% group_by(ID) %>% filter(Date >= max(Date)-365)

#Source: local data frame [8 x 3]
#Groups: ID
#
#  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