oercim
oercim

Reputation: 1848

reshaping a list( list into list form) into a data frame - R

Let I have the below list(list2) where the elements of the list is also a list:

> dput(list2)
list(x = list(a = c(0.18, 0.7, 0.57, 0.17, 0.94), b = c(0.18, 
0.7, 0.57, 0.17, 0.94)), y = list(a = c(0.18, 0.7, 0.57, 0.17, 
0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)), z = list(a = c(0.18, 
0.7, 0.57, 0.17, 0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)))

where I generated the list as below:

names1<-c("a","b")
names2<-c("x","y","z")
list1<-list()
list2<-list()
for(i in names1)
  for(j in names2){{
    set.seed(2)
  list1[[i]]<-round(runif(5),2)
  list2[[j]]<-list1
}}

I want to reshape this list as below data frame:

   n1 n2   n3
1   x  a 0.18
2   x  a 0.70
3   x  a 0.57
4   x  a 0.17
5   x  a 0.94
6   x  b 0.18
7   x  b 0.70
8   x  b 0.57
9   x  b 0.17
10  x  b 0.94
11  y  a 0.18
12  y  a 0.70
13  y  a 0.57
14  y  a 0.17
15  y  a 0.94
16  y  b 0.18
17  y  b 0.70
18  y  b 0.57
19  y  b 0.17
20  y  b 0.94
21  z  a 0.18
22  z  a 0.70
23  z  a 0.57
24  z  a 0.17
25  z  a 0.94
26  z  b 0.18
27  z  b 0.70
28  z  b 0.57
29  z  b 0.17
30  z  b 0.94

How caı I reshape the list? My original list is much bigger than the above example.

Thanks a lot.

Upvotes: 1

Views: 181

Answers (4)

ThomasIsCoding
ThomasIsCoding

Reputation: 101343

A base R option

setNames(
  `row.names<-`(rev(
    do.call(
      rbind,
      Map(cbind,
        Map(stack, list2),
        n = names(list2)
      )
    )
  ), NULL),
  paste0("n", 1:3)
)

gives

   n1 n2   n3
1   x  a 0.18
2   x  a 0.70
3   x  a 0.57
4   x  a 0.17
5   x  a 0.94
6   x  b 0.18
7   x  b 0.70
8   x  b 0.57
9   x  b 0.17
10  x  b 0.94
11  y  a 0.18
12  y  a 0.70
13  y  a 0.57
14  y  a 0.17
15  y  a 0.94
16  y  b 0.18
17  y  b 0.70
18  y  b 0.57
19  y  b 0.17
20  y  b 0.94
21  z  a 0.18
22  z  a 0.70
23  z  a 0.57
24  z  a 0.17
25  z  a 0.94
26  z  b 0.18
27  z  b 0.70
28  z  b 0.57
29  z  b 0.17
30  z  b 0.94

Upvotes: 2

elielink
elielink

Reputation: 1202

Why don't you create directly the dataframe?

names1<-c("a","b")
names2<-c("x","y","z")
b= matrix(ncol=3)[-1,]
for(i in names1)
  for(j in names2){{
    
    a<-as.data.frame(round(runif(5),2))
    a$n1 = j
    a$n2 = i
    b = rbind(b,a)
  }}
b = b[,c(2,3,1)]
colnames(b)[3]='n3'

the result looks like this:

   n1 n2 n3
1   x  a               0.85
2   x  a               0.98
3   x  a               0.23
4   x  a               0.44
5   x  a               0.07
6   y  a               0.66
7   y  a               0.39
8   y  a               0.84
9   y  a               0.15
10  y  a               0.35
11  z  a               0.49
12  z  a               0.15
13  z  a               0.36
14  z  a               0.96
15  z  a               0.13
16  x  b               0.01
17  x  b               0.16
18  x  b               0.81
19  x  b               0.87
20  x  b               0.51
21  y  b               0.63
22  y  b               0.84
23  y  b               0.28
24  y  b               0.67
25  y  b               0.15
26  z  b               0.98
27  z  b               0.30
28  z  b               0.12
29  z  b               0.16
30  z  b               0.94

Upvotes: 0

Ronak Shah
Ronak Shah

Reputation: 388982

You can use stack with lapply and combine the data with bind_rows -

dplyr::bind_rows(lapply(list2, stack), .id = 'n1')

#   n1 values ind
#1   x   0.18   a
#2   x   0.70   a
#3   x   0.57   a
#4   x   0.17   a
#5   x   0.94   a
#6   x   0.18   b
#7   x   0.70   b
#8   x   0.57   b
#9   x   0.17   b
#10  x   0.94   b
#11  y   0.18   a
#12  y   0.70   a
#13  y   0.57   a
#14  y   0.17   a
#15  y   0.94   a
#16  y   0.18   b
#17  y   0.70   b
#18  y   0.57   b
#19  y   0.17   b
#20  y   0.94   b
#21  z   0.18   a
#22  z   0.70   a
#23  z   0.57   a
#24  z   0.17   a
#25  z   0.94   a
#26  z   0.18   b
#27  z   0.70   b
#28  z   0.57   b
#29  z   0.17   b
#30  z   0.94   b

If you want to keep this in base R :

data <- lapply(list2, stack)
do.call(rbind, Map(cbind, data, n1 = names(data)))

Upvotes: 2

AnilGoyal
AnilGoyal

Reputation: 26218

purrr::imap_dfr based solution

list2 <- list(x = list(a = c(0.18, 0.7, 0.57, 0.17, 0.94), b = c(0.18, 
                                                                 0.7, 0.57, 0.17, 0.94)), y = list(a = c(0.18, 0.7, 0.57, 0.17, 
                                                                                                         0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)), z = list(a = c(0.18, 
                                                                                                                                                                    0.7, 0.57, 0.17, 0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)))

library(tidyverse)
imap_dfr(list2, ~.x %>% as.data.frame() %>%
           mutate(n1 = .y) %>%
           pivot_longer(!n1, names_to = 'n2', values_to = 'n3'))
#> # A tibble: 30 x 3
#>    n1    n2       n3
#>    <chr> <chr> <dbl>
#>  1 x     a      0.18
#>  2 x     b      0.18
#>  3 x     a      0.7 
#>  4 x     b      0.7 
#>  5 x     a      0.57
#>  6 x     b      0.57
#>  7 x     a      0.17
#>  8 x     b      0.17
#>  9 x     a      0.94
#> 10 x     b      0.94
#> # ... with 20 more rows

Created on 2021-05-26 by the reprex package (v2.0.0)

Upvotes: 2

Related Questions