【问题标题】:Find the most recent value associated with multiple date columns查找与多个日期列关联的最新值
【发布时间】:2016-11-02 19:36:14
【问题描述】:

我有一个如下所示的数据框:

    id      date1 value1      date2 value2      date3 value3
1 1113 2012-01-14     29 2012-09-29     22 2013-10-28     21
2 1622 2012-12-05     93 2012-12-05     82 2013-01-22     26
3 1609 2014-08-30     30 2013-04-07     53 2013-03-20    100
4 1624 2014-01-20     84 2013-03-17     92 2014-01-10     81
5 1861 2014-10-08     29 2012-08-19     84 2012-09-21     56
6 1640 2014-03-05     27 2012-02-28      5 2015-01-11     65

我想创建一个新列,其中包含“value1”、“value2”和“value3”三列中的最新值。我不需要知道它与哪个日期相关联。

    id      date1 value1      date2 value2      date3 value3 value_recent
1 1113 2012-01-14     29 2012-09-29     22 2013-10-28     21           21
2 1622 2012-12-05     93 2012-12-05     82 2013-01-22     26           26
3 1609 2014-08-30     30 2013-04-07     53 2013-03-20    100           30
4 1624 2014-01-20     84 2013-03-17     92 2014-01-10     81           84
5 1861 2014-10-08     29 2012-08-19     84 2012-09-21     56           29
6 1640 2014-03-05     27 2012-02-28      5 2015-01-11     65           65

创建工作示例的代码:

set.seed(1234)
id <- sample(1000:2000, 6, replace=TRUE)
date1 <- sample(seq(as.Date('2012-01-01'), as.Date('2016-01-01'), by="day"), 6)
value1 <- sample(1:100, 6, replace=TRUE)
date2 <- sample(seq(as.Date('2012-01-01'), as.Date('2016-01-01'), by="day"), 6)
value2 <- sample(1:100, 6, replace=TRUE)
date3 <- sample(seq(as.Date('2012-01-01'), as.Date('2016-01-01'), by="day"), 6)
value3 <- sample(1:100, 6, replace=TRUE)

df <- data.frame(id, date1, value1, date2, value2, date3, value3)

【问题讨论】:

  • 使用set.seed,这样可以重现随机过程
  • @PierreLafortune,谢谢,我已经编辑过了。

标签: r date


【解决方案1】:

编辑:根据@Pierre Lafortune 的回答,您实际上可以将其合并为一个语句。

编辑 2: 添加了带有 NA 的数据,还更改了处理 NA 的代码。

这应该可以很好地解决问题。它确实需要一个循环,我很想看看是否有人能想出一个简洁的 vecotrized 解决方案。

date_cols <- colnames(df)[grep("date",colnames(df))]
df$value_recent<-df[cbind(1:nrow(df),grep("date",colnames(df))[apply(sapply(df[,date_cols],as.numeric),1,which.max)]+1)]
df

  id      date1   value1    date2   value2   date3    value3  value_recent
1 1113       <NA>     29 2012-09-29     22 2013-10-28     21           21
2 1622 2012-12-05     93 2012-12-05     82 2013-01-22     26           26
3 1609       <NA>     30 2013-04-07     53 2013-03-20    100           53
4 1624 2014-01-20     84 2013-03-17     92 2014-01-10     81           84
5 1861 2014-10-08     29 2012-08-19     84 2012-09-21     56           29
6 1640 2014-03-05     27 2012-02-28      5 2015-01-11     65           65

数据:

df<-structure(list(id = c(1113L, 1622L, 1609L, 1624L, 1861L, 1640L
), date1 = structure(c(NA, 15679, NA, 16090, 16351, 16134), class = "Date"), 
    value1 = c(29L, 93L, 30L, 84L, 29L, 27L), date2 = structure(c(15612, 
    15679, 15802, 15781, 15571, 15398), class = "Date"), value2 = c(22L, 
    82L, 53L, 92L, 84L, 5L), date3 = structure(c(16006, 15727, 
    15784, 16080, 15604, 16446), class = "Date"), value3 = c(21L, 
    26L, 100L, 81L, 56L, 65L)), .Names = c("id", "date1", "value1", 
"date2", "value2", "date3", "value3"), row.names = c(NA, -6L), class = "data.frame")

【讨论】:

  • 啊,我想我明白你在说什么了。所以像你在答案中那样使用它吗?也就是说,我们可以简单地计算出我们想要的列:df$value_recent&lt;-df[cbind(1:nrow(df),grep("date",colnames(df))[max.col(sapply(df[,date_cols],as.numeric))]+1)]
  • 后续问题,如果后面列中的某些日期和值是 NA,我应该在第二行的哪个位置添加 na.rm=TRUE?它似乎在我尝试添加它的任何地方都不起作用。
  • 我更新了我的代码。您通常应该尝试准确地表达您的数据,以便我们能够最好地回答您的问题。
【解决方案2】:

我正在使用apply 遍历行以查找最近的日期。然后使用该索引查找对应的值。我们使用矩阵子集方法来保持简洁:

indx <- apply(df[grep("date", names(df))], 1, function(x) which(x == max(x))[1])
df$value_recent <- df[grep("val", names(df))][cbind(1:nrow(df), indx)]
#     id      date1 value1      date2 value2      date3 value3 value_recent
# 1 1113 2012-01-14     29 2012-09-29     22 2013-10-28     21           21
# 2 1622 2012-12-05     93 2012-12-05     82 2013-01-22     26           26
# 3 1609 2014-08-30     30 2013-04-07     53 2013-03-20    100           30
# 4 1624 2014-01-20     84 2013-03-17     92 2014-01-10     81           84
# 5 1861 2014-10-08     29 2012-08-19     84 2012-09-21     56           29
# 6 1640 2014-03-05     27 2012-02-28      5 2015-01-11     65           65

(注意:以这种方式排列数据会带来更多的麻烦。)

【讨论】:

    【解决方案3】:

    执行此操作的方法可能不那么冗长,但这里有一种选择。首先将其移动为“长”格式,然后按 id 拆分、排序并提取最新记录,然后将其与原始数据框合并。

    ld <- reshape(df, 
            idvar = "id", 
            varying = list(paste0("date", 1:3),
                           paste0("value", 1:3)),
            v.names = c("date", "value"),
            direction = "long")
    
    recent <- split(ld, ld$id)
    recent <- lapply(recent, function(x) {
        d <- x[order(x$date), ]
        d <- d[nrow(d), c(1, 4)]
        names(d)[2] <- "value_recent"
    d
    })
    
    recent <- do.call(rbind, recent)
    merge(df, recent, by = "id")
    
    #     id      date1 value1      date2 value2      date3 value3 value_recent
    # 1 1204 2014-10-25     73 2012-12-22     39 2015-07-18     62           62
    # 2 1667 2012-01-16     97 2014-02-28     30 2014-12-31     83           83
    # 3 1673 2015-01-16     96 2014-12-16     50 2014-08-05     31           96
    # 4 1722 2015-02-07     10 2013-12-25      4 2012-08-18     93           10
    # 5 1882 2012-10-20     91 2014-12-28     71 2015-09-03     18           18
    # 6 1883 2012-03-30     73 2015-04-26      4 2014-12-23     74            4
    

    【讨论】:

      【解决方案4】:

      这是一个类似的解决方案,它也以reshape 开头,然后在一系列管道中完成其余部分:

      library(dplyr)
      library(reshape)
      
      df2 <- reshape(df,
                     varying = list(names(df)[grep("date", names(df))],
                                    names(df)[grep("value", names(df))]),
                     v.names = c("date", "value"),
                     direction = "long") %>%
        # order data for step to come
        arrange(id, date) %>%
        # next two steps cut down to last (ordered) obs for each id
        group_by(id) %>%
        slice(n()) %>%
        # keep only the columns we need and rename the value column for merging
        select(id, most.recent = value) %>%
        # merge the values back into the original data frame, matching on id
        left_join(df, .)
      

      【讨论】:

        猜你喜欢
        • 2021-11-30
        • 1970-01-01
        • 1970-01-01
        • 2019-10-04
        • 1970-01-01
        • 1970-01-01
        • 2020-08-29
        • 2019-06-21
        • 1970-01-01
        相关资源
        最近更新 更多