问题
Can I unnest a list column directly into n columns?
The list can be assumed to regular, with all elements being of equal length.
If instead of a list column I would have a character vector, I could tidyr::separate
. I can tidyr::unnest
, but we need another helper variable to be able to tidyr::spread
. Am I missing an obvious method?
Example data:
library(tibble)
df1 <- data_frame(
gr = c('a', 'b', 'c'),
values = list(1:2, 3:4, 5:6)
)
# A tibble: 3 x 2 gr values <chr> <list> 1 a <int [2]> 2 b <int [2]> 3 c <int [2]>
Goal:
df2 <- data_frame(
gr = c('a', 'b', 'c'),
V1 = c(1, 3, 5),
V2 = c(2, 4, 6)
)
# A tibble: 3 x 3 gr V1 V2 <chr> <dbl> <dbl> 1 a 1. 2. 2 b 3. 4. 3 c 5. 6.
Current method:
unnest(df1) %>%
group_by(gr) %>%
mutate(r = paste0('V', row_number())) %>%
spread(r, values)
回答1:
with tidyr 1.0.0 you only need :
library(tidyr)
df1 <- tibble(
gr = c('a', 'b', 'c'),
values = list(1:2, 3:4, 5:6)
)
unnest_wider(df1, values)
#> New names:
#> * `` -> ...1
#> * `` -> ...2
#> New names:
#> * `` -> ...1
#> * `` -> ...2
#> New names:
#> * `` -> ...1
#> * `` -> ...2
#> # A tibble: 3 x 3
#> gr ...1 ...2
#> <chr> <int> <int>
#> 1 a 1 2
#> 2 b 3 4
#> 3 c 5 6
Created on 2019-09-14 by the reprex package (v0.3.0)
The output is verbose here because the elements that were unnested horizontally (the vector elements) were not named, and unnest_wider
doesn't want to guess silently.
We can name them beforehand to avoid it :
df1 %>%
dplyr::mutate(values = purrr::map(values, setNames, c("V1","V2"))) %>%
unnest_wider(values)
#> # A tibble: 3 x 3
#> gr V1 V2
#> <chr> <int> <int>
#> 1 a 1 2
#> 2 b 3 4
#> 3 c 5 6
Or just use suppressMessages()
or purrr::quietly()
回答2:
library(tibble)
df1 <- data_frame(
gr = c('a', 'b', 'c'),
values = list(1:2, 3:4, 5:6)
)
library(tidyverse)
df1 %>%
mutate(r = map(values, ~ data.frame(t(.)))) %>%
unnest(r) %>%
select(-values)
# # A tibble: 3 x 3
# gr X1 X2
# <chr> <int> <int>
# 1 a 1 2
# 2 b 3 4
# 3 c 5 6
回答3:
With data.table
it's pretty simple:
library("data.table")
setDT(df1)
df1[, c("V1", "V2") := transpose(values)]
df1
# gr values V1 V2
# 1: a 1,2 1 2
# 2: b 3,4 3 4
# 3: c 5,6 5 6
回答4:
Maybe this:
cbind(df1[, "gr"], do.call(rbind, df1$values))
回答5:
Another one:
library(tibble)
library(dplyr)
df1 <- data_frame(
gr = c('a', 'b', 'c'),
values = list(1:2, 3:4, 5:6)
)
df %>% mutate(V1 = sapply(values, "[[", 1), V2 = sapply(values, "[[", 2))
# A tibble: 3 x 4
gr values V1 V2
<chr> <list> <int> <int>
1 a <int [2]> 1 2
2 b <int [2]> 3 4
3 c <int [2]> 5 6
Edit:
When the listed vectors are very long, and writing by hand V1 = sapply(values, "[[", index)
is not convenient, then you can combine it with f_interp
from lazyeval
:
library(tibble)
library(dplyr)
library(lazyeval)
df <- data_frame(gr = c('a', 'b', 'c'), values = list(1:11, 3:13, 5:15))
nums <- c(1:11)
ll <- lapply(nums, function(nr) f_interp(~sapply(values, "[[", uq(nr))))
mutate_(df, .dots=setNames(ll, paste("V", nums, sep="")))
# A tibble: 3 x 12
gr values V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
<chr> <list> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 a <int [11]> 1 2 3 4 5 6 7 8 9 10
2 b <int [11]> 3 4 5 6 7 8 9 10 11 12
3 c <int [11]> 5 6 7 8 9 10 11 12 13 14
回答6:
I have had a similar problem several times. My solution is admittedly clunky compared to the other answers, but reporting it for completeness sake.
library(tibble)
df1 <- data_frame(
gr = c('a', 'b', 'c'),
values = list(1:2, 3:4, 5:6)
)
matrix(unlist(df1[1])) -> grs
matrix(unlist(df1[2]), byrow=T, ncol=2) -> vals
Result:
> data.frame(grs, vals)
grs X1 X2
1 a 1 2
2 b 3 4
3 c 5 6
来源:https://stackoverflow.com/questions/49689927/unnest-a-list-column-directly-into-several-columns