【问题标题】:Apply seq.Date using two dataframe columns [duplicate]使用两个数据框列应用 seq.Date [重复]
【发布时间】:2016-02-03 08:48:27
【问题描述】:

我尝试使用不同的答案 Expanding a sequence in a data frame 到我的数据框,但我没有尝试过。

样本数据

library(dplyr)    
p1 <- c(1:5)
p2 <- as.Date(c("2013-01-01","2013-01-22","2014-02-01","2014-05-12","2015-02-22"))
p3 <- as.Date(c("2013-01-11","2013-01-30","2014-02-20","2014-05-22","2015-02-28"))
p4 <- c(11,9,20,11,7)
df2 <- data_frame(p1,p2,p3,p4)
names(df2) <- c("ID", "StartDate", "EndDate", "NoDays")
df2

想要的结果

ID  datelist    NoDays
1   2013-01-01   1
1   2013-01-02   1 
1   2013-01-03   1
etc..
1   2013-01-10   1
1   2013-01-11   1
2   2013-01-22   1
2   2013-01-23   1
etc.
2   2013-01-28   1
2   2013-01-29   1
2   2013-01-30   1

这里有三个代码试验——我在许多变体中都进行了尝试(例如,apply 系列的非常多的成员),但都失败了(即给出不同的错误消息):

代码示例1

datelist <- seq.Date(from = df2$StartDate, to=df2$StartDate, by="days")

代码示例 2

datelist <- seq.Date(from = df2$StartDate, by="days", length.out = df2$NoDays)

代码示例 2

datelist <- apply(df2, 1, seq.Date(from = df2$StartDate, to=df2$StartDate, by="days"))

【问题讨论】:

    标签: r date sequence


    【解决方案1】:

    你的问题是你给seq.Date一个向量,它的唯一值是fromto

    与您的应用调用相同的想法应该是:

    apply(df2,1,function(x) { seq.Date( as.Date(x['StartDate']), as.Date(x['EndDate']), by='days') } )
    

    它为您提供了每个行序列的列表:

    [[1]]
     [1] "2013-01-01" "2013-01-02" "2013-01-03" "2013-01-04" "2013-01-05" "2013-01-06" "2013-01-07" "2013-01-08" "2013-01-09"
    [10] "2013-01-10" "2013-01-11"
    
    [[2]]
    [1] "2013-01-22" "2013-01-23" "2013-01-24" "2013-01-25" "2013-01-26" "2013-01-27" "2013-01-28" "2013-01-29" "2013-01-30"
    
    [[3]]
     [1] "2014-02-01" "2014-02-02" "2014-02-03" "2014-02-04" "2014-02-05" "2014-02-06" "2014-02-07" "2014-02-08" "2014-02-09"
    [10] "2014-02-10" "2014-02-11" "2014-02-12" "2014-02-13" "2014-02-14" "2014-02-15" "2014-02-16" "2014-02-17" "2014-02-18"
    [19] "2014-02-19" "2014-02-20"
    
    [[4]]
     [1] "2014-05-12" "2014-05-13" "2014-05-14" "2014-05-15" "2014-05-16" "2014-05-17" "2014-05-18" "2014-05-19" "2014-05-20"
    [10] "2014-05-21" "2014-05-22"
    
    [[5]]
    [1] "2015-02-22" "2015-02-23" "2015-02-24" "2015-02-25" "2015-02-26" "2015-02-27" "2015-02-28"
    

    为了得到你想要的输出,我们也应该返回 id 和 NoDays 列。

    在基础 R 中,我会这样做:

    getDfForDates <- function(row) {
      dseq <- seq.Date( as.Date(row['StartDate']), as.Date(row['EndDate']), by='days')
      data.frame( ID=row['ID'], datelist=dseq, NoDays=1)
    }
    
    rbindlist(
      apply(df2,1,function(x) { 
        getDfForDates(x)
      } )
    )
    

    data.table 包的另一个解决方案是:

    setDT(df2)
    df2[, list(datelist=seq.Date( StartDate, EndDate, by='days'), NoDays=1), by=ID]
    

    如果我没有错过任何一点,两者都会给出预期的结果。

    我会看看我是否可以制作一个正确的 dplyr 答案,因为你似乎正在使用这个包。在寻找 dplyr 示例时终于发现了一个骗子,投票关闭。

    【讨论】:

    • 您好,感谢您的回答。我使用 dplyr 是因为我最了解它,但我总是乐于学习新的软件包。再次感谢您的帮助!
    • @user2006697 不客气,请参阅 akrun 答案和 dplyr 语法的副本。他比我好得多:p
    • @Tensibai 我想你对其他语言了解得更多。所以,我可能落后于你。
    【解决方案2】:

    我们可以通过data.table 轻松做到这一点。将'data.frame'转换为'data.table'(setDT(df2),如果'ID's是唯一的,则按'ID'分组,并得到'StartDate'的seq到'EndDate'by'身份证”。

    library(data.table)
    res <- setDT(df2)[,list(datelist=seq(StartDate, EndDate, by='1 day'), 
                          NoDays = 1) , by = ID]
    
    head(res)
    #   ID   datelist NoDays
    #1:  1 2013-01-01      1
    #2:  1 2013-01-02      1
    #3:  1 2013-01-03      1
    #4:  1 2013-01-04      1
    #5:  1 2013-01-05      1
    #6:  1 2013-01-06      1
    

    如果我们需要在dplyr 中执行此操作,我们可能需要do,因为mutate 不支持这种操作

    library(dplyr)
    df2 %>% 
       rowwise() %>%
       do(data.frame(ID= .$ID, datelist = seq(.$StartDate, 
                 .$EndDate, by = '1 day'), NoDays= 1))
    

    【讨论】:

    • 嗨,非常感谢!如果 NoDays 无法固定但必须计算怎么办?例如。像“NoDays / datdiff(StartDate,EndDate)”?这可以通过 data.table 方法完成吗?
    • @user2006697 可以,可以计算。只需通过'ID'区分StartDate和'EndDate`
    • 超级 - 立即工作。谢谢百万!
    猜你喜欢
    • 1970-01-01
    • 2019-02-17
    • 2018-02-04
    • 1970-01-01
    • 2022-08-11
    • 1970-01-01
    • 2011-04-03
    • 2011-11-18
    • 1970-01-01
    相关资源
    最近更新 更多