【问题标题】:Cartesian Rolling Join using Data.table使用 Data.table 的笛卡尔滚动连接
【发布时间】:2018-11-27 22:20:24
【问题描述】:

我有两张桌子:

  • dat:包含数据

  • dates:包含日期表


library(data.table)

dates = structure(list(date = structure(c(17562, 17590, 17621, 17651, 
                              17682, 17712, 17743, 17774, 17804, 17835, 17865, 17896), class = "Date")), 
      row.names = c(NA, -12L), class = "data.frame")


dat = structure(list(date = structure(c(17546, 17743, 17778, 17901, 
                              17536, 17806, 17901, 17981, 17532, 17722, 17969, 18234), class = "Date"), 
           country = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 
                                 3L, 3L, 3L), .Label = c("AAA", "BBB", "CCC"), class = "factor"), 
           state = structure(c(1L, 1L, 2L, 3L, 4L, 1L, 2L, 5L, 6L, 1L, 
                               2L, 2L), .Label = c("S1", "S2", "S3", "S4", "S5", "S6"), class = "factor"), 
           item = structure(c(1L, 2L, 4L, 6L, 3L, 5L, 3L, 2L, 2L, 4L, 
                              5L, 7L), .Label = c("M1", "M2", "M3", "M4", "M5", "M6", "M7"
                              ), class = "factor"), value = c(67L, 10L, 50L, 52L, 93L, 
                                                              50L, 62L, 46L, 6L, 30L, 30L, 14L)), row.names = c(NA, -12L
                                                              ), class = "data.frame")


dates = data.table(dates)
dat = data.table(dat)


setkey(dates, date)
setkey(dat, date)

我追求的结果如下。即对每一行 dat 进行滚动连接,然后组合结果。

rbind(
dat[1,][dates, roll = 90],
dat[2,][dates, roll = 90],
dat[3,][dates, roll = 90],
...
dat[12,][dates, roll = 90]
)

我的实际数据集要大得多,因此列出每一行 dat 是不切实际的。有没有一种简单的方法可以在没有循环的情况下做同样的事情?

【问题讨论】:

    标签: r join data.table


    【解决方案1】:

    这不一定是最好的方法,但您可以简单地在此处编写一个循环来遍历您的数据:

    df <- data.frame()
    
    for (i in 1:nrow(dat)){
        df <- rbind(df, dat[i,][dates, roll = 90])
    }
    
    head(df)
    
              date country state item value
      1: 2018-01-31     CCC    S6   M2     6
      2: 2018-02-28     CCC    S6   M2     6
      3: 2018-03-31     CCC    S6   M2     6
      4: 2018-04-30    <NA>  <NA> <NA>    NA
      5: 2018-05-31    <NA>  <NA> <NA>    NA
    

    编辑:刚刚看到你说“没有循环”,这是漫长的一天。这是解决问题的一种方法。

    【讨论】:

    • 通过 rbind 或类似方法在 R 中动态增长对象通常效率很低(我猜你知道)。我不认为循环一定很糟糕,尽管我只是将 df 初始化为具有正确的行数和正确的列集,例如 iris[rep(NA_integer_, 10), ],然后分配给每一行而不是增长它。
    【解决方案2】:

    如果我正确理解您的意图,您希望将记录滚动 90 天。 我使用了交叉连接,然后使用翻转条件来设置子集

    您的原始表格:

    library(data.table)
    
    dates = structure(list(date = structure(c(17562, 17590, 17621, 17651, 
                                              17682, 17712, 17743, 17774, 17804, 17835, 17865, 17896), class = "Date")), 
                      row.names = c(NA, -12L), class = "data.frame")
    
    
    dat = structure(list(date = structure(c(17546, 17743, 17778, 17901, 
                                            17536, 17806, 17901, 17981, 17532, 17722, 17969, 18234), class = "Date"), 
                         country = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 
                                               3L, 3L, 3L), .Label = c("AAA", "BBB", "CCC"), class = "factor"), 
                         state = structure(c(1L, 1L, 2L, 3L, 4L, 1L, 2L, 5L, 6L, 1L, 
                                             2L, 2L), .Label = c("S1", "S2", "S3", "S4", "S5", "S6"), class = "factor"), 
                         item = structure(c(1L, 2L, 4L, 6L, 3L, 5L, 3L, 2L, 2L, 4L, 
                                            5L, 7L), .Label = c("M1", "M2", "M3", "M4", "M5", "M6", "M7"
                                            ), class = "factor"), value = c(67L, 10L, 50L, 52L, 93L, 
                                                                            50L, 62L, 46L, 6L, 30L, 30L, 14L)), row.names = c(NA, -12L
                                                                            ), class = "data.frame")
    
    
    dates = data.table(dates)
    dat = data.table(dat)
    

    注意,我没有设置密钥。

    我正在使用参考中的交叉连接函数:How to do cross join in R?

    CJ.table.1 <- function(X,Y)
      setkey(X[,c(k=1,.SD)],k)[Y[,c(k=1,.SD)],allow.cartesian=TRUE][,k:=NULL]
    

    然后我交叉连接、滚动连接的子集、重命名列和排序

    dsn1<-CJ.table.1(dat,dates)[i.date-date<=90 & i.date-date>=0][,.(date=i.date,country, state, item, value)][order(country, state, item, value,date),]
    

    【讨论】:

    • 同样的想法,我认为:dat[dates[, .(k = seq(1L, nrow(dat))), by=date], roll=90, allow.cartesian=TRUE][order(k)][, k := NULL][]
    • 这样更整洁! @弗兰克
    • 这正是我所追求的。谢谢 SatZ 和 Frank。
    猜你喜欢
    • 2019-12-02
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多