【问题标题】:Flatten list column in data frame with ID column使用 ID 列展平数据框中的列表列
【发布时间】:2015-07-26 10:25:09
【问题描述】:

我的数据框包含选择多个问题类型的调查的输出。有些单元格有多个值。

df <- data.frame(a=1:3,b=I(list(1,1:2,1:3)))
df
  a       b
1 1       1
2 2    1, 2
3 3 1, 2, 3

我想展平列表以获得以下输出:

df
  a       b
1 1       1
2 2       1
3 2       2
4 3       1
5 3       2
6 3       3

应该很容易,但不知何故我找不到搜索词。谢谢。

【问题讨论】:

    标签: r dataframe reshape


    【解决方案1】:

    你可以只使用来自“tidyr”的unnest

    library(tidyr)
    unnest(df, b)
    #   a b
    # 1 1 1
    # 2 2 1
    # 3 2 2
    # 4 3 1
    # 5 3 2
    # 6 3 3
    

    【讨论】:

    • 谢谢!完美,我看过 tidyr 但没有找到这个特殊情况
    • OP 说它应该很容易,你已经证明它确实是那么容易!干得好!
    【解决方案2】:

    使用base R,在将'b' 列的list 元素命名为'a' 的元素之后,一个选项是stack。我们可以使用setNames 来更改名称。

    stack(setNames(df$b, df$a))
    

    或者另一种选择是使用unstack 自动将'b' 的列表元素命名为'a' 元素,然后执行stack 以获得data.frame 输出。

    stack(unstack(df, b~a))
    

    或者我们可以使用方便的函数listCol_lsplitstackshapelist 转换为data.frame

    library(splitstackshape)
    listCol_l(df, 'b')
    

    【讨论】:

    • 干得好。我总是喜欢看到简单、优雅的基础解决方案。
    【解决方案3】:

    这是一种方法,data.table:

    require(data.table)
    data.table(df)[,as.integer(unlist(b)),by=a]
    

    如果b 存储一致,则可以跳过as.integer。你可以检查

    unique(sapply(df$b,class))
    # [1] "numeric" "integer"
    

    【讨论】:

    • df$b[1] &lt;- list(1L) 如果 OP 有很多这样的条目,我们太手动且不切实际。我认为data.table(df)[,as.integer(unlist(b)),by=a] 应该这样做
    • @DavidArenburg 是的,或者“正确”地将数据摄取到 R 中(在前面存储为整数的意义上)。我会切换到你写的。
    【解决方案4】:

    这是另一个基本解决方案,远不如迄今为止发布的任何其他解决方案优雅。为了完整起见发布,但我个人会推荐 akrun 的基本解决方案。

    with(df, cbind(a = rep(a, sapply(b, length)), b = do.call(c, b)))
    

    这会将第一列构造为a 的元素,其中每个元素都被重复以匹配来自b 的相应列表项的长度。第二列是b“扁平化”,使用do.call()c()

    正如 Ananda Mahto 在评论中指出的那样,在最新版本的 R(3.2,如果我没记错的话)中,sapply(b, length) 可以替换为 lengths(b)

    【讨论】:

    • 在最新版本的 R 中,您可以将 sapply(b, length) 替换为 lengths(b)
    • @AnandaMahto:太棒了,感谢提醒!
    • 要取回一个data.frame,你最好使用:with(df, data.frame(a = rep(a, lengths(b)), b = unlist(b)))
    【解决方案5】:

    基本的 R 方法也可能是为每一行创建一个新的 data.frame,然后再创建一个 rbind

    df <- data.frame(a=1:3,b=I(list(1,1:2,1:3)))
    df
    
    df <- lapply(seq_along(df$a), function(x){data.frame(a = df$a[[x]], b = df$b[[x]])})
    df <- do.call("rbind", df)
    df
    

    【讨论】:

      猜你喜欢
      • 2020-05-31
      • 2019-03-08
      • 1970-01-01
      • 2021-07-13
      • 1970-01-01
      • 2014-12-04
      • 2018-11-09
      • 1970-01-01
      • 2020-04-24
      相关资源
      最近更新 更多