将列表列拆分为多列

问题描述 投票:0回答:5

我有一个数据框,其中最后一列是一列列表。下面是它的样子:

Col1 | Col2 | ListCol
--------------------------
 na  |  na  | [obj1, obj2]
 na  |  na  | [obj1, obj2]
 na  |  na  | [obj1, obj2]

我想要的是

Col1 | Col2 | Col3  | Col4
--------------------------
 na  |  na  | obj1  | obj2
 na  |  na  | obj1  | obj2
 na  |  na  | obj1  | obj2

我知道所有列表都有相同数量的元素。

编辑:

ListCol 中的每个元素都是一个包含两个元素的列表。

r multiple-columns
5个回答
26
投票

目前,tidyverse 的答案是:

library(dplyr)
library(tidyr)
data %>% unnest_wider(ListCol)

11
投票

这是一种方法,使用

unnest
tidyr::spread
...

library(dplyr)
library(tidyr)

#example df
df <- tibble(a=c(1, 2, 3), b=list(c(2, 3), c(4, 5), c(6, 7)))

df %>% unnest(b) %>% 
       group_by(a) %>% 
       mutate(col=seq_along(a)) %>% #add a column indicator
       spread(key=col, value=b)

      a   `1`   `2`
  <dbl> <dbl> <dbl>
1    1.    2.    3.
2    2.    4.    5.
3    3.    6.    7.

6
投票

两个精彩答案的比较

此线程中有两个很棒的单衬建议:

(1)
cbind(df[1], t(data.frame(df$b)))

这是来自

@Onyambu
使用
base
R。要得到这个答案,需要知道
dataframe
是一个列表,需要一点创造力。

(2)
df %>% unnest_wider(b)

这是来自

@iago
使用
tidyverse
。您需要额外的软件包并了解所有
nest
动词,但人们可以认为它更具可读性。

现在让我们比较一下性能

library(dplyr)
library(tidyr)
library(purrr)
library(microbenchmark)

N <- 100
df <- tibble(a = 1:N, b = map2(1:N, 1:N, c))

tidy_foo <- function() suppressMessages(df %>% unnest_wider(b, names_sep = "-"))
base_foo <- function() cbind(df[1],t(data.frame(df$b))) %>% as_tibble # To be fair
  
microbenchmark(tidy_foo(), base_foo(), times = 1000)

Unit: milliseconds
       expr      min       lq     mean   median       uq     max neval
 tidy_foo() 6.538002 7.142651 7.935855 7.434001 7.945101 70.0057  1000
 base_foo() 6.000001 6.423951 7.110651 6.636401 6.991952 13.8205  1000

结论

如果考虑到

tidyr
,解决方案会慢 1.1 倍,但生成的最坏情况会慢 5 倍。
    


1
投票
mean

data.table
的选项。

base::unlist

这需要在每一行上都有一个 for 循环...不理想并且
非常

library(data.table) DT <- data.table(a = list(1, 2, 3), b = list(list(1, 2), list(2, 1), list(1, 1))) for (i in 1:nrow(DT)) { set( DT, i = i, j = c('b1', 'b2'), value = unlist(DT[i][['b']], recursive = FALSE) ) } DT 。 我想知道是否有某种方法可以避免首先创建列表列...

    


1
投票
data.table

提供

data.table
功能将一列拆分为多列。
tstrsplit

DT = data.table(x=c("A/B", "A", "B"), y=1:3)
DT[]

#     x y
#1: A/B 1
#2:   A 2
#3:   B 3
© www.soinside.com 2019 - 2024. All rights reserved.