【问题标题】:How to subset the most recent 12 months of data for each ID in a data frame?如何为数据框中的每个 ID 子集最近 12 个月的数据?
【发布时间】:2014-09-17 12:16:10
【问题描述】:

我有一个代表数百名患者 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 中按日期进行子集化的问题已经问过几个问题,但它们通常与来自特定日期或日期范围的数据子集有关,而不是按((可变结束日期)-(时间间隔))进行子集化。

【问题讨论】:

    标签: r date subset


    【解决方案1】:

    为了完整起见,这里有两种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
    

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

    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 的@987654349 @ 将日期滚动到 2015 年 2 月 28 日 2 月的最后一天。

    【讨论】:

      【解决方案2】:

      这是一个基本解决方案。我们让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))
      

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

      【讨论】:

        【解决方案3】:

        使用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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-09-17
          • 2022-11-25
          • 2022-07-13
          • 1970-01-01
          • 1970-01-01
          • 2022-10-04
          • 1970-01-01
          相关资源
          最近更新 更多