【问题标题】:Merge a data.table and a list合并一个 data.table 和一个列表
【发布时间】:2020-05-08 11:35:50
【问题描述】:

我想在我的 data.table 中添加一个列表。让我们考虑一下这个data.table:

dt = data.table(id = 1:3)

lst <- list()
lst[[2]] <- cbind(a=10:12, b=5:7)

dt[-nrow(dt), lst:=lst]

dt
#   id               lst
#1:  1                  
#2:  2 10,11,12, 5, 6, 7
#3:  3    

是否可以“取消列出”第一个,使 data.table 看起来像这样?

      id  a  b       
1.0:  1                  
2.0:  2 
2.1:  2   10 5
2.2:  2   11 6
2.3:  2   12 7
3.0:  3                  

还有一个速度问题,因为我正在处理的数据包含数十亿行。

【问题讨论】:

  • 为什么不使用 rbindlist(lst, idcol='id')[dt, on=.(id)]。虽然不是在电脑前测试。您可能会收到有关 use.names 的警告。可能需要根据您的需要设置为 TRUE 或 FALSE
  • 得到这个:错误:“rbindlist(lst, idcol=‘"中的意外输入
  • 如何决定将值附加到哪些行?为什么第 2 行是空的?
  • 我想保留原来的dt,所以第2.0行只有id=2。第 2.1 到 2.3 行应包含列表中的数据。
  • rbind(dt, data.table(id=2, a=10:12, b=5:7), fill = TRUE)[order(id)] 呢?

标签: r list data.table


【解决方案1】:

评论中提到的一个选项:

rbindlist(list(dt, 
        rbindlist(lapply(lst, as.data.table), idcol='id')), 
    use.names=TRUE, fill=TRUE)[order(id)]

输出:

   id  a  b
1:  1 NA NA
2:  2 NA NA
3:  2 10  5
4:  2 11  6
5:  2 12  7
6:  3 NA NA

【讨论】:

    【解决方案2】:

    需要重新格式化,但您可以使用rbindlist

    # create all entries in lst
    length(lst) <- nrow(dt)
    
    # identify table sizes
    lens     = sapply(lst, NROW)
    
    # use data.tables instead of matrices
    # fill empty tables with a blank template
    template = data.table(a=NA_real_, b=NA_real_)
    dtlist   = replace(lapply(lst, as.data.table), lens == 0, list(template))
    
    # expand dt to match tables
    replens  = pmax(lens, 1L)    
    cbind(dt[rep(1:.N, replens)], rbindlist(dtlist))
    
       id  a  b
    1:  1 NA NA
    2:  2 10  5
    3:  2 11  6
    4:  2 12  7
    5:  3 NA NA
    

    【讨论】:

    • 我们都错过了第 2 行的空行。
    【解决方案3】:
    library(data.table)
    
    dt = data.table(id = 1:3)
    
    lst <- list()
    lst[[2]] <- cbind(a=10:12, b=5:7)
    
    unique(rbindlist(lapply(1:length(lst), function(i) {
      data.table(id = i, lst[[i]])[dt, on = .(id)]
    }
      ), fill=TRUE))[order(id)]
    
       id  a  b
    1:  1 NA NA
    2:  2 NA NA
    3:  2 10  5
    4:  2 11  6
    5:  2 12  7
    6:  3 NA NA
    

    【讨论】:

      【解决方案4】:

      您可以在列表中运行lapply,如果列表中的项目非空,则将行添加到空行:

      dt <- data.table(id = 1:3)
      
      lst <- list()
      lst[[2]] <- cbind(a=10:12, b=5:7)
      
      create_table <- function(x, lst) {
        if (!is.null(lst[[x]])) {
          # Empty row plus items in list
          rbindlist(
            list(data.table(id = x), data.table(id = x, lst[[x]])), 
            use.names = TRUE, fill = TRUE
          )
        } else {
          data.table(id = x)
        }
      }
      
      aux_lst <- rbindlist(
        lapply(seq(lst), create_table, lst = lst), 
        use.names = TRUE, fill = TRUE
      )
      
      aux_lst[dt, on = .(id)] # Keeps all IDs in dt
      

      如果列表已命名且 id 列与这些名称相关,则将 seq 替换为 names

      【讨论】:

        猜你喜欢
        • 2019-04-17
        • 2020-12-31
        • 1970-01-01
        • 1970-01-01
        • 2020-06-20
        • 1970-01-01
        • 2021-04-19
        • 2014-01-27
        相关资源
        最近更新 更多