首页 文章

rbindlist data.frames的列表列并选择唯一值

提问于
浏览
2

我有一个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的每个唯一行 . 我想这就像在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

4 回答

  • 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
    
  • 1

    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
    
  • 5

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

    如果为 col1 添加列,则上面的表达式表示"unique entries"(列上无条件) .

    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) 应该可以正常工作,但是我的数据表太旧了,看不到它 .

    对于类似 tidyr::unnest 的函数,还有an open issue .

  • 1

    你可以像这样做一些hackish:

    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)
    

相关问题