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.
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.
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
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.
You can try with
Reduce( rbind, lapply(t1, t) )
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With