Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R - Turn List Into DataFrame

There is a list like this, starting from 1.

[[7158]]
[1] 81 72

[[7159]]
[1] 81 69

[[7160]]
[1] 81 79

[[7161]]
[1] 81 84

This needs to be changed to a data frame where the first number in each element is aligned in one data frame column, and the second number in each element is placed in the second column of a data frame. So it should end up like this

> data.frame("col1" = c(81, 81, 81, 81), "col2" = c(72, 69, 79, 84))
  col1 col2
1   81   72
2   81   69
3   81   79
4   81   84

I tried doing do.call(rbind.data.frame, my_list) but it seems to place the numbers in a huge number of columns, not coerce it down to the two columns needed. It would be pretty straight forward to do this with a loop but what is the R way to do it? Thanks.

like image 863
appleLover Avatar asked Feb 15 '15 14:02

appleLover


People also ask

How do I turn a list into a vector in R?

Converting a List to Vector in R Language – unlist() Function. unlist() function in R Language is used to convert a list to vector. It simplifies to produce a vector by preserving all components.


4 Answers

Just set the names:

mylist <- list(c(81,72), c(81,63), c(81,79))
setNames(do.call(rbind.data.frame, mylist), c("col1", "col2"))
#  col1 col2
#1   81   72
#2   81   63
#3   81   79

In contrast to some of the other solutions, this would also work for mixed data types:

mylist <- list(list("a", 72), list("b", 63), list("c", 79))
res <- setNames(do.call(rbind.data.frame, mylist), c("col1", "col2"))
str(res)
#'data.frame':  3 obs. of  2 variables:
# $ col1: Factor w/ 3 levels "a","b","c": 1 2 3
# $ col2: num  72 63 79
like image 112
Roland Avatar answered Sep 25 '22 18:09

Roland


You can try any of the following:

do.call(rbind, my_list)

t(simplify2array(my_list))

library(stringi)
stri_list2matrix(my_list, byrow = TRUE)

All of the above would produce a two column matrix with the data that you describe, so you can then use as.data.frame to get a data.frame.

Timings for the above alternatives and @Roland's suggestion can be found at this Gist. To summarize, the "stringi" approach would be the fastest of the options presented so far. If I'm not mistaken, rbindlist in "data.table" should also support converting list of vectors--but I have not tested with the development version on GitHub to verify, so I haven't included that option here.

like image 34
A5C1D2H2I1M1N2O1R2T1 Avatar answered Sep 22 '22 18:09

A5C1D2H2I1M1N2O1R2T1


You can try with

Reduce( rbind, lapply(t1, t) )
like image 25
bergant Avatar answered Sep 22 '22 18:09

bergant


Another idea:

mylist = list(c(81, 72), c(81, 69), c(81, 79), c(81, 84))

f4 = function(x) 
{
    tlist = lapply(seq_along(x[[1]]), 
                   function(i) unlist(lapply(x, "[[", i)))
    structure(tlist, class = "data.frame", 
              row.names = .set_row_names(as.integer(length(tlist[[1]]))), 
              names = paste("col", seq_along(tlist), sep = ""))
}

f4(mylist)
#  col1 col2
#1   81   72
#2   81   69
#3   81   79
#4   81   84

And a benchmark with the other options:

library(stringi)              
f1 = function(x)
  setNames(as.data.frame(type.convert(stri_list2matrix(x, byrow = TRUE))), 
           paste("col", seq_along(x[[1]]), sep = ""))

f2 = function(x)
  setNames(do.call(rbind.data.frame, x), 
           paste("col", seq_along(x[[1]]), sep = ""))

f3 = function(x)
  setNames(as.data.frame(Reduce(rbind, lapply(x, t))), 
           paste("col", seq_along(x[[1]]), sep = "")) 

myls = replicate(1e3, sample(1e2), simplify = F)
identical(f1(myls), f2(myls))
#[1] TRUE
identical(f1(myls), f3(myls))
#[1] TRUE
identical(f1(myls), f4(myls))
#[1] TRUE
microbenchmark::microbenchmark(f1(myls), f2(myls), f3(myls), f4(myls), times = 10)
#Unit: milliseconds
#     expr       min        lq    median        uq       max neval
# f1(myls)  57.66834  58.46979  59.39131  61.43861 102.27333    10
# f2(myls) 393.81459 404.29019 418.03128 422.87740 494.79857    10
# f3(myls) 288.39078 299.51680 305.21727 314.75482 374.48683    10
# f4(myls)  52.54991  53.26575  55.34472  59.25559  75.19658    10
like image 42
alexis_laz Avatar answered Sep 23 '22 18:09

alexis_laz