Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tidyverse approach to binding unnamed list of unnamed vectors by row - do.call(rbind,x) equivalent

I often find questions where people have somehow ended up with an unnamed list of unnamed character vectors and they want to bind them row-wise into a data.frame. Here is an example:

library(magrittr) data <- cbind(LETTERS[1:3],1:3,4:6,7:9,c(12,15,18)) %>%   split(1:3) %>% unname data #[[1]] #[1] "A"  "1"  "4"  "7"  "12" # #[[2]] #[1] "B"  "2"  "5"  "8"  "15" # #[[3]] #[1] "C"  "3"  "6"  "9"  "18" 

One typical approach is with do.call from base R.

do.call(rbind, data) %>% as.data.frame #  V1 V2 V3 V4 V5 #1  A  1  4  7 12 #2  B  2  5  8 15 #3  C  3  6  9 18 

Perhaps a less efficient approach is with Reduce from base R.

Reduce(rbind,data, init = NULL) %>% as.data.frame #  V1 V2 V3 V4 V5 #1  A  1  4  7 12 #2  B  2  5  8 15 #3  C  3  6  9 18 

However, when we consider more modern packages such as dplyr or data.table, some of the approaches that might immediately come to mind don't work because the vectors are unnamed or aren't a list.

library(dplyr) bind_rows(data) #Error: Argument 1 must have names 
library(data.table) rbindlist(data) #Error in rbindlist(data) :  #  Item 1 of input is not a data.frame, data.table or list 

One approach might be to set_names on the vectors.

library(purrr) map_df(data, ~set_names(.x, seq_along(.x))) # A tibble: 3 x 5 #  `1`   `2`   `3`   `4`   `5`   #  <chr> <chr> <chr> <chr> <chr> #1 A     1     4     7     12    #2 B     2     5     8     15    #3 C     3     6     9     18   

However, this seems like more steps than it needs to be.

Therefore, my question is what is an efficient tidyverse or data.table approach to binding an unnamed list of unnamed character vectors into a data.frame row-wise?

like image 632
Ian Campbell Avatar asked May 05 '20 13:05

Ian Campbell


2 Answers

Not entirely sure about efficiency, but a compact option using purrr and tibble could be:

map_dfc(purrr::transpose(data), ~ unlist(tibble(.)))    V1    V2    V3    V4    V5      <chr> <chr> <chr> <chr> <chr> 1 A     1     4     7     12    2 B     2     5     8     15    3 C     3     6     9     18   
like image 179
tmfmnk Avatar answered Sep 19 '22 22:09

tmfmnk


Edit

Use @sindri_baldur's approach: https://stackoverflow.com/a/61660119/8583393


A way with data.table, similar to what @tmfmnk showed

library(data.table) as.data.table(transpose(data)) #   V1 V2 V3 V4 V5 #1:  A  1  4  7 12 #2:  B  2  5  8 15 #3:  C  3  6  9 18 
like image 42
markus Avatar answered Sep 20 '22 22:09

markus