【问题标题】:Unpacking and merging lists in a column in data.frame在 data.frame 的列中解包和合并列表
【发布时间】:2015-09-20 15:40:25
【问题描述】:

我有以下data.frame

id     name   altNames
1001   Joan   character(0)      
1002   Jane   c("Janie", "Janet", "Jan")
1003   John   Jon
1004   Bill   Will
1005   Tom    character(0)      

altNames 列可以是空的(即字符(0)),只有一个名称,或一个名称列表。我想要的是一个data.frame(或一个列表),其中来自name 和/或altNames 的每个条目与相应的id 一起出现一次,如下所示:

id     name
1001   Joan
1002   Jane
1002   Janie
1002   Janet
1002   Jan
1003   John
1003   Jon
1004   Bill
1004   Will
1005   Tom

最有效的方法是什么?更好的是使用dplyr。 谢谢

编辑:这是数据:

df <- data_frame(
  id = c("1001", "1002","1003", "1004", "1005"), 
  name = c("Joan", "Jane", "John", "Bill", "Tom"), 
  altNames = list(character(0), c("Janie", "Janet", "Jan"), "Jon", "Will", character(0))
)

【问题讨论】:

  • 这是tidyr::unnest 的工作,但目前在这个例子中被破坏了:github.com/hadley/tidyr/issues/91
  • 我在使用您的 dput 时遇到错误,因此我将其更改为 @hadley 的示例。顺便说一下do.call('rbind', lapply(1:nrow(df), function(x) data.frame(id = df[x, 1], name = unlist(df[x, -1]), row.names = NULL))),这是 base r 中的另一种方式

标签: r dataframe dplyr data.table


【解决方案1】:

这是一种可能的data.table 方法

library(data.table)
setDT(dat)[, .(name = c(name, unlist(altNames))), by = id]
#       id  name
#  1: 1001  Joan
#  2: 1002  Jane
#  3: 1002 Janie
#  4: 1002 Janet
#  5: 1002   Jan
#  6: 1003  John
#  7: 1003   Jon
#  8: 1004  Bill
#  9: 1004  Will
# 10: 1005   Tom

【讨论】:

  • 我不确定 OP 是如何获得有效的data.frame 以使其看起来像他那样的。在某些时候它必须是data.table(或者从一个非常糟糕的函数返回)。
  • @hrbrmstr 这是jsonlite的输出
  • 呃。这就像在data.frames 中有NULLs 一样糟糕。如果您的源数据会大量生成,那么您绝对应该尽早将jsonlite 输出移动到data.table
  • 这行得通。仅使用dplyrdata.frame 有什么方法可以做到这一点?不太了解data.table 并试图避免它
【解决方案2】:

基础 R 版本(使用 @rawr 添加的 df

with(df, {
    ns <- mapply(c, name, altNames)
    data.frame(id = rep(id, times=lengths(ns)), name=unlist(ns), row.names=NULL)
})
#     id  name
#1  1001  Joan
#2  1002  Jane
#3  1002 Janie
#4  1002 Janet
#5  1002   Jan
#6  1003  John
#7  1003   Jon
#8  1004  Bill
#9  1004  Will
#10 1005   Tom

【讨论】:

  • 对我不起作用。给我错误的 ID 和重复。很奇怪。
  • @Amin 我不知道,lengths 适用于 R 3.2+,但这只会抛出错误而不会给出错误的结果。
【解决方案3】:

使用tidyr,用data.table清理数据后:

首先,修复数据:

library(data.table)
dat<-setDT(dat)
dat$altNames[sapply(dat$altNames, length) == 0] <- NA

现在unnest 来自tidyr 和一些dplyr

library(dplyr)
library(tidyr)
dat %>% unnest(altNames) %>%
        group_by(id) %>%
        do(unique(c(.[["name"]],.[["altNames"]])))

     id    V1
1  1001  Joan
2  1001    NA
3  1002  Jane
4  1002 Janie
5  1002 Janet
6  1002   Jan
7  1003  John
8  1003   Jon
9  1004  Bill
10 1004  Will
11 1005   Tom
12 1005    NA

它有 NA,但它们很容易用 %&gt;% na.omit 删除。

我认为 data.table 是这个的赢家。

【讨论】:

    【解决方案4】:

    这是一个完整的 dplyr + tidyr 解决方案,我的解决方法:

    library(dplyr)
    library(tidyr)
    
    df <- data_frame(
      id = c("1001", "1002","1003", "1004", "1005"), 
      name = c("Joan", "Jane", "John", "Bill", "Tom"), 
      altNames = list(character(0), c("Janie", "Janet", "Jan"), "Jon", "Will", character(0))
    )
    
    # Need some way to concatenate a list of vectors with a vectors
    # in a "rowwise" way
    vector_c <- function(...) {
      Map(c, ...)
    }
    
    df %>% 
      mutate(
        names = vector_c(name, altNames),
        altNames = NULL,
        name = NULL
      ) %>% 
      unnest(names)
    #> Source: local data frame [10 x 2]
    #> 
    #>      id names
    #> 1  1001  Joan
    #> 2  1002  Jane
    #> 3  1002 Janie
    #> 4  1002 Janet
    #> 5  1002   Jan
    #> 6  1003  John
    #> 7  1003   Jon
    #> 8  1004  Bill
    #> 9  1004  Will
    #> 10 1005   Tom
    

    大部分繁重的工作由tidyr::unnest() 完成:它旨在获取带有列表列的数据框并将其取消嵌套,并根据需要重复其他列。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-08
      • 2012-12-22
      • 2020-05-29
      • 1970-01-01
      • 1970-01-01
      • 2013-09-26
      相关资源
      最近更新 更多