Home > Enterprise >  Pivot wider a column containing lists
Pivot wider a column containing lists

Time:07-07

I have this dataset:

col1   col2
 a    c(1,2)
 b       5

I want this dataset:

col1    col2_1  col2_2   col2_5
 a       TRUE    TRUE    FALSE
 b      FALSE   FALSE    TRUE

I know I have to use pivot wider. But I don't know how! Would you please help?

CodePudding user response:

You could unnest col2 and then reshape data to wide.

library(tidyr)

df %>%
  unnest(col2) %>%
  pivot_wider(col1, names_from = col2, names_prefix = "col2_",
              values_from = col2, values_fn = Negate(is.na), values_fill = FALSE)

# # A tibble: 2 × 4
#   col1  col2_1 col2_2 col2_5
#   <chr> <lgl>  <lgl>  <lgl> 
# 1 a     TRUE   TRUE   FALSE 
# 2 b     FALSE  FALSE  TRUE 

Data
df <- data.frame(col1 = c('a', 'b'))
df$col2 <- list(1:2, 5)

#   col1 col2
# 1    a 1, 2
# 2    b    5

CodePudding user response:

Using tabulate.

f <- \(x) {
  m <- max(unlist(x))
  t <- t(sapply(x, tabulate, m))
  `mode<-`(t, 'logical')
}

cbind(dat[1], col2=f(dat$col2))
#   col1 col2.1 col2.2 col2.3 col2.4 col2.5
# 1    a   TRUE   TRUE  FALSE  FALSE  FALSE
# 2    b  FALSE  FALSE  FALSE  FALSE   TRUE

To get the subset:

cbind(dat[1], col2=f(dat$col2)) |>
  {\(.) subset(., select=c(1, which(apply(.[-1], 2, any))   1))}()
#   col1 col2.1 col2.2 col2.5
# 1    a   TRUE   TRUE  FALSE
# 2    b  FALSE  FALSE   TRUE

--

Data:

dat <- list2DF(list(c('a', 'b'), list(c(1, 2), 5))) |> setNames(paste0('col', 1:2))

CodePudding user response:

We could use mtabulate

library(qdapTools)
out <- cbind(df1,  mtabulate(df1$col2) > 0)
names(out)[-(1:2)] <- paste0('col2_', names(out)[-(1:2)])

-output

> out
  col1 col2 col2_1 col2_2 col2_5
1    a 1, 2   TRUE   TRUE  FALSE
2    b    5  FALSE  FALSE   TRUE

data

df1 <- structure(list(col1 = c("a", "b"), col2 = list(1:2, 5)), 
row.names = c(NA, 
-2L), class = "data.frame")
  • Related