【问题标题】:rbindlist a list column of data.frames and select unique valuesrbindlist data.frames 的列表列并选择唯一值
【发布时间】:2018-12-04 21:39:50
【问题描述】:

我有一个 data.table 'DT',其中有一列 ('col2'),它是一个数据框列表:

require(data.table)
DT <- data.table(col1 = c('A','A','B'),
                 col2 = list(data.frame(colA = c(1,3,54, 23), 
                                        colB = c("aa", "bb", "cc", "hh")),
                             data.frame(colA =c(23, 1),
                                       colB = c("hh", "aa")), 
                             data.frame(colA = 1,
                                       colB = "aa")))

> DT
   col1         col2
1:    A <data.frame>
2:    A <data.frame>
3:    B <data.frame>

>> DT$col2
[[1]]
  colA colB
1    1   aa
2    3   bb
3   54   cc
4   23   hh

[[2]]
  colA colB
1   23   hh
2    1   aa

[[3]]
  colA colB
1    1   aa

col2 中的每个 data.frame 都有两列 colA 和 colB。 我想要一个 data.table 输出,它根据 DT 的 col1 绑定这些 data.frames 的每个 unique 行。 我想这就像在 data.table 的聚合函数中使用rbindlist

这是所需的输出:

> #desired output
> output
   colA colB col1
1:    1   aa    A
2:    3   bb    A
3:   54   cc    A
4:   23   hh    A
5:    1   aa    B

第二行 DT (DT[2, col2]) 的数据框有重复的条目,每个唯一的 col1 只需要唯一的条目。

我尝试了以下操作,但出现错误。

desired_output <- DT[, lapply(col2, function(x) unique(rbindlist(x))), by = col1]
# Error in rbindlist(x) : 
#   Item 1 of list input is not a data.frame, data.table or list

这个“有效”,虽然不是想要的输出:

unique(rbindlist(DT$col2))
   colA colB
1:    1   aa
2:    3   bb
3:   54   cc
4:   23   hh

有没有在 data.table 的聚合函数中使用rbindlist

【问题讨论】:

  • unique(tidyr::unnest(DT[, c("col1","col2")]))
  • 甚至可以缩短为:unique(tidyr::unnest(DT))
  • 我没有仔细阅读 q 但你想要的输出是unique(DT[, rbindlist(setNames(col2, col1), id="col1")])

标签: r list data.table aggregate rbindlist


【解决方案1】:

你可以像这样做一些骇人听闻的事情:

nDT <- cbind(rbindlist(DT[[2]]), col1 = rep(DT[[1]], sapply(DT[[2]], nrow)))
nDT[!duplicated(nDT)]
   colA colB col1
1:    1   aa    A
2:    3   bb    A
3:   54   cc    A
4:   23   hh    A
5:    1   aa    B

或者使用 tidyr(灵感来自 Pkumar 的评论):

unique(tidyr::unnest(DT))

或更通用的基础 R:

names(DT[[2]]) <- DT[[1]]
ndf <- do.call(rbind, DT[[2]])
ndf$col1 <- substr(row.names(ndf), 1, 1)
unique(ndf)

【讨论】:

    【解决方案2】:

    这行得通:

    DT1<-apply(DT, 1, function(x){cbind(col1=x$col1,x$col2)})
    unique(rbindlist(DT1))
    #   col1 colA colB
    #1:    A    1   aa
    #2:    A    3   bb
    #3:    A   54   cc
    #4:    A   23   hh
    #5:    B    1   aa
    

    【讨论】:

      【解决方案3】:

      by'col1',在'col2'上运行rbindlist

      unique(DT[ , rbindlist(col2), by = col1]) # trimmed thanks to @snoram
      #    col1 colA colB
      # 1:    A    1   aa
      # 2:    A    3   bb
      # 3:    A   54   cc
      # 4:    A   23   hh
      # 5:    B    1   aa
      

      【讨论】:

      • 整洁!并且还可以缩短:DT[ , rbindlist(col2), by = col1]
      • 也许DT[, unique(rbindlist(col2)), by = col1]
      【解决方案4】:

      每个唯一的col1只需要唯一的条目

      如果您为col1 添加列,则上面的表达式表示“唯一条目”(对列无条件)。

      Henrik 的回答是保留col1 的一种方式。另一个是:

      unique(DT[, rbindlist(setNames(col2, col1), id="col1")])
      

      我想这应该比

      更有效率
      bycols = "col1"
      unique(DT[, rbindlist(col2), by=bycols])   # Henrik's
      

      尽管 (1) col1 不是字符列(因此适用于 setNames)或 (2) 具有多个 by= 列的扩展并不那么明显。对于这两种情况中的任何一种,我都会创建一个 .id 列等于 DT 的行号,然后将它们复制过来:

      bycols = "col1"
      res = unique(DT[, rbindlist(col2, id="DT_row")])
      res[, (bycols) := DT[DT_row, ..bycols]]
      

      要将这些列放在最前面/最左边,我认为 setcolorder(res, bycols) 应该可以工作,但我的 data.table 版本太旧,看不到这样做。

      还有an open issue 用于类似tidyr::unnest 的功能。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-05-08
        • 2012-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-25
        相关资源
        最近更新 更多