【问题标题】:Matching multiple date values in R匹配R中的多个日期值
【发布时间】:2013-04-21 19:15:52
【问题描述】:

我有以下数据框 DF,描述了在特定日期从事项目工作的人:

ID    ProjectName    StartDate 
1       Health        3/1/06 18:20
2       Education     2/1/07 15:30
1       Education     5/3/09 9:00
3       Wellness      4/1/10 12:00
2       Health        6/1/11 14:20

目标是找到每个ID对应的第一个项目。例如,预期的输出如下:

ID    ProjectName    StartDate 
1       Health        3/1/06 18:20
2       Education     2/1/07 15:30
3       Wellness      4/1/10 12:00

到目前为止,我已完成以下操作来获取每个 ID 的第一个 StartDate:

sub <- ddply(DF, .(ID), summarise, st = min(as.POSIXct(StartDate)));

在此之后,我需要将 sub 中的每一行与原始 DF 匹配,并提取与该 ID 和 StartDate 对应的项目。这可以在 sub 中的每一行循环中完成。但是,我的数据集非常大,我想知道是否有一种有效的方法来进行这种匹配并从 DF 中提取这个子集。

【问题讨论】:

  • plyr 已被 dplyr 封存,但 DF %&gt;% group_by(ID) %&gt;% first() 有效

标签: r matching plyr


【解决方案1】:

这是一个基本的 R 解决方案

dat <- data.frame(
    ID=c(1,2,1,3,2), 
    PRJ=c("H","E","E", "W", "H"), 
    START=strptime(
      c(
        "3/1/06 18:20", "2/1/07 15:30", "5/3/09 9:00",
        "4/1/10 12:00","6/1/11 14:20"), 
      "%d/%m/%y %H:%M")
    )
min_date <- function(x) {x[which.min(x$START), ]}
s <- split(dat, dat$ID) # split
a <- lapply(s, FUN=min_date) # apply
do.call("rbind", a) # combine

结果

  ID PRJ               START
1  1   H 2006-01-03 18:20:00
2  2   E 2007-01-02 15:30:00
3  3   W 2010-01-04 12:00:00

不过,@SimonO101 的订单匹配解决方案比这快得多。

只是为了好玩,这里还有另一个使用sqldf的解决方案:

sqldf("select * from dat group by ID having START=min(START)")

【讨论】:

    【解决方案2】:

    这是一个data.table 解决方案,应该非常有效。

    DF <- data.frame(ID=c(1,2,1,3,2,1), ProjectName=c('Health', 'Education', 'Education', 'Wellness', 'Health', 'Health'),
                 StartDate=c('3/1/06 18:20', '2/1/07 15:30', '5/3/09 9:00', '4/1/10 12:00', '6/1/11 14:20', '1/1/06 11:10'))
    

    请注意,我已经修改了您的数据,在末尾添加了另一个元素,因此不再对日期进行排序。因此输出不同。

    d <- as.data.table(DF)
    
    # Order by StartDate and take the first ID.
    # Assumes that your dates are month/day/year.
    
    d[order(as.POSIXct(StartDate, format="%m/%d/%y %H:%M"))][,.SD[1,],by=ID]
    ##    ID ProjectName    StartDate
    ## 1:  1      Health 1/1/06 11:10
    ## 2:  2   Education 2/1/07 15:30
    ## 3:  3    Wellness 4/1/10 12:00
    

    如果您的日期已经排序(如您的示例中所示),这就足够了:

    d[,.SD[1,],by=ID]
    

    【讨论】:

    • +1 用于 OP 数据和 data.table 解决方案的可重现示例
    【解决方案3】:

    使用match 相当简单,因为match 返回:

    first 位置的向量匹配其第一个参数 第二个

    所以您需要做的就是按日期排序,然后使用unique 获取每个ID 的一个实例,并使用match 查找第一个位置。感谢@MatthewLunberg 提供了可重现的数据示例:

    DF <- DF[ order(as.POSIXct(DF$StartDate, format="%m/%d/%y %H:%M")) , ]
    DF[ match( unique( DF$ID ) , DF$ID ) , ]
    #  ID ProjectName    StartDate
    #6  1      Health 1/1/06 11:10
    #2  2   Education 2/1/07 15:30
    #4  3    Wellness 4/1/10 12:00
    

    一个优点是它在使用之前保留了原始数据帧的行号。我不知道这对你是否有用。

    【讨论】:

    • 这似乎是最快的解决方案。
    【解决方案4】:

    为了完善它,这里有一个基于plyr 包的解决方案。我添加了一个额外的列,以便textConnection 更容易读取数据。

    dfProjects = as.data.frame(read.table(textConnection("ID    ProjectName    Date Time 
      1       Health        3/1/06 18:20
      2       Education     2/1/07 15:30
      1       Education     5/3/09 9:00
      3       Wellness      4/1/10 12:00
      2       Health        6/1/11 14:20"), header = TRUE))
    ddply(within(dfProjects, dfProjects[order(
      as.POSIXct(paste(Date, Time), format = "%m/%d/%y %H:%M")), ]), 
          .(ID), function(dataFrame) dataFrame[1, ])
    

    【讨论】:

      猜你喜欢
      • 2018-02-25
      • 2016-01-08
      • 1970-01-01
      • 2020-07-07
      • 2016-05-10
      • 2021-09-24
      • 2023-02-26
      • 1970-01-01
      • 2021-07-04
      相关资源
      最近更新 更多