【问题标题】:How to manipulate data.frame in the data.table如何操作 data.table 中的 data.frame
【发布时间】:2019-07-11 05:07:29
【问题描述】:

我有data.table,其中一些观察列包含data.frame。例如:

data.table(colA=   c('A1','A2','A3'), 
                  colB=list(data.frame(), 
                            data.frame(colsubB1=c('B2a','B2b'),colsubB2=c('B2c', 'B2d')), 
                            data.frame(colsubB1=c('A3a','A3b'),colsubB2=c('A3c', 'A3d'))),
                  colC=   c('C1','C2','C3'), 
                  colD=   c('D1','D2','D3')
                  )

返回,

   colA         colB colC colD
1:   A1 <data.frame>   C1   D1
2:   A2 <data.frame>   C2   D2
3:   A3 <data.frame>   C3   D3

我希望得到以下结果:

    colA colsubB1 colsubB2 colC colD
1:   A1     <NA>     <NA>   C1   D1
2:   A2      B2a      B2c   C2   D2
3:   A2      B2b      B2d   C2   D2
4:   A3      A3a      A3c   C3   D3
5:   A3      A3b      A3d   C3   D3

你能不能给点建议?

【问题讨论】:

  • 您可能应该做的是修复创建 data.table 的代码。我不会创建 data.frames 的列表列。

标签: r dataframe data.table


【解决方案1】:

使用by

DT[, if(nrow(colB[[1L]]) > 0) 
        colB[[1L]] 
    else 
        data.frame(colsubB1=NA_character_, colsubB2=NA_character_), 
    by=setdiff(names(DT), "colB")]

输出:

   colA colC colD colsubB1 colsubB2
1:   A1   C1   D1     <NA>     <NA>
2:   A2   C2   D2      B2a      B2c
3:   A2   C2   D2      B2b      B2d
4:   A3   C3   D3      A3a      A3c
5:   A3   C3   D3      A3b      A3d

数据:

library(data.table)
DT <- data.table(colA=   c('A1','A2','A3'), 
    colB=list(data.frame(), 
        data.frame(colsubB1=c('B2a','B2b'),colsubB2=c('B2c', 'B2d')), 
        data.frame(colsubB1=c('A3a','A3b'),colsubB2=c('A3c', 'A3d'))),
    colC=   c('C1','C2','C3'), 
    colD=   c('D1','D2','D3')

【讨论】:

    【解决方案2】:

    一种方式:

    DT[, {
      lens  = sapply(colB, nrow)
      empty = data.table(colB[[which.max(lens > 0)]])[NA_integer_]
      unnested = rbindlist(replace(colB, lens == 0, list(empty)))
      repped   = .SD[rep(.I, pmax(lens, 1L))]
    
      # figure out column positions
      s = order(c(
        match(names(repped), names(DT)), 
        rep(match("colB", names(DT)), ncol(unnested))
      ))
    
      setcolorder(cbind(repped, unnested), s)
    }, .SDcols=!"colB"]
    
       colA colsubB1 colsubB2 colC colD
    1:   A1     <NA>     <NA>   C1   D1
    2:   A2      B2a      B2c   C2   D2
    3:   A2      B2b      B2d   C2   D2
    4:   A3      A3a      A3c   C3   D3
    5:   A3      A3b      A3d   C3   D3
    

    如果 colB 的任何元素都没有任何内容,则所需的输出不清楚。我猜你应该手动写入empty 的值,就像在这种情况下@chinsoon 的回答中一样,如果已知的话。

    【讨论】:

    • 我可以在一个单独的问题中提出这个问题,但也许你在这里回答很简单,你知道如果我删除 which ,为什么我的解决方案不起作用吗?通常逻辑 i 索引似乎处理得很好。
    • @Moody_Mudskipper 显然这是故意的,但自从我很久以前第一次阅读?data.table 以来,我一直没有考虑或使用它。我认为与基本 R 的不一致并没有多大意义,所以在这里发布了一个问题/FR 链接:github.com/Rdatatable/data.table/issues/3699
    【解决方案3】:

    你实际上可以使用tidyr::unnest()

    library(data.table)
    library(tidyr)
    # data edited to avoid warnings
    DT <- data.table(colA=   c('A1','A2','A3'), 
               colB=list(data.frame(row.names = 1), 
                         data.frame(colsubB1=c('B2a','B2b'),colsubB2=c('B2c', 'B2d'),
                                    stringsAsFactors = FALSE), 
                         data.frame(colsubB1=c('A3a','A3b'),colsubB2=c('A3c', 'A3d'),
                                    stringsAsFactors = FALSE)),
               colC=   c('C1','C2','C3'), 
               colD=   c('D1','D2','D3')
    )
    # with current version of tidyr, unnest can remove rows, should be fixed in next
    # version, but for now we need to add a row to our empty data.frames
    # no idea why the which was needed
    DT[which(!lengths(colB)), colB := list(list(data.frame(row.names = 1)))]
    # then just unnest
    DT[, unnest(.SD,colB)]
    #>    colA colC colD colsubB1 colsubB2
    #> 1:   A1   C1   D1     <NA>     <NA>
    #> 2:   A2   C2   D2      B2a      B2c
    #> 3:   A2   C2   D2      B2b      B2d
    #> 4:   A3   C3   D3      A3a      A3c
    #> 5:   A3   C3   D3      A3b      A3d
    # or 
    unnest(DT, colB)
    #>    colA colC colD colsubB1 colsubB2
    #> 1:   A1   C1   D1     <NA>     <NA>
    #> 2:   A2   C2   D2      B2a      B2c
    #> 3:   A2   C2   D2      B2b      B2d
    #> 4:   A3   C3   D3      A3a      A3c
    #> 5:   A3   C3   D3      A3b      A3d
    

    reprex package (v0.3.0) 于 2019 年 7 月 11 日创建

    【讨论】:

    • 可能删除但保留括号
    • iirc 有一个关于逻辑 i 的常见问题解答。我怀疑它解释了!首先在解析代码时。但很可能我的知识很少。最好等待专家解答
    • 没有找到它,如果我先做L &lt;- lengths(DT$colB) 然后DT[!L, colB := list(list(data.frame(row.names = 1)))] 它可以工作,看起来像一个错误,但感觉我没有做任何花哨的事情。如果我在这里没有得到解释,我会提出问题
    • 它返回[1] 0 2 2
    • 当我有时间找出一个最低限度的工作示例时,我会在这里提出一个单独的问题,然后在出现意外行为时提出问题。
    猜你喜欢
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多