2017-07-17 67 views
6

Próbuję uzyskać cbind lub unnest lub as.data.table listę częściowo zagnieżdżoną.cbind z częściowo zagnieżdżoną listą

id <- c(1,2) 
A <- c("A1","A2","A3") 
B <- c("B1") 
AB <- list(A=A,B=B) 
ABAB <- list(AB,AB) 
nested_list <- list(id=id,ABAB=ABAB) 

length id jest taka sama jak ABAB 2 (w tym przypadku). Nie wiem, jak to zrobić: unlist część tej listy (ABAB) i cbind inna część (id). Oto mój pożądany rezultat jako data.table:

data.table(id=c(1,1,1,2,2,2),A=c("A1","A2","A3","A1","A2","A3"),B=rep("B1",6)) 
    id A B 
1: 1 A1 B1 
2: 1 A2 B1 
3: 1 A3 B1 
4: 2 A1 B1 
5: 2 A2 B1 
6: 2 A3 B1 
+0

Zakładam y potrzebujesz rozwiązania, które rozwiązuje ten przypadek w ogólny sposób ... – CPak

+0

@ChiPak Zrobiłem to proste z przykładowymi danymi z ABAB zawierającym tę samą listę dwa razy (AB, AB). Mój prawdziwy przykład życia zawiera różne listy ('ABAB <- lista (AB, CD)') –

Odpowiedz

5

nie testowałem dla bardziej ogólnych przypadków, ale to działa na przykładzie PO:

library(data.table) 

as.data.table(nested_list)[, lapply(ABAB, as.data.table)[[1]], id] 
# id A B 
#1: 1 A1 B1 
#2: 1 A2 B1 
#3: 1 A3 B1 
#4: 2 A1 B1 
#5: 2 A2 B1 
#6: 2 A3 B1 

lub innej opcji (co jest zapewne szybciej, ale jest bardziej szczegółowy):

rbindlist(lapply(nested_list$ABAB, as.data.table), 
      idcol = 'id')[, id := nested_list$id[id]] 
5

Jest kilka bardzo brzydki baza R, ale daje pożądany wynik.

Reduce(rbind, Map(function(x, y) setNames(data.frame(x, y), c("id", "A", "B")), 
        as.list(nested_list[[1]]), 
        lapply(unlist(nested_list[-1], recursive=FALSE), 
         function(x) Reduce(cbind, x)))) 
    id A B 
1 1 A1 B1 
2 1 A2 B1 
3 1 A3 B1 
4 2 A1 B1 
5 2 A2 B1 
6 2 A3 B1 

lapply wykonuje listę dwóch elementów (każda zawierająca zmienne A i B), pochodzących z unlist i recursive=FALSE. Zwraca listę macierzy znaków ze zmienną B wypełnioną przez recykling. Lista indywidualnych zmiennych identyfikacyjnych z as.list(nested_list[[1]]) i podświetlona matryca są przesyłane do Map, która konwertuje odpowiednie pary do data.frame i nadaje kolumnom pożądane nazwy i zwraca listę danych.frame. Wreszcie, ta lista danych.frames jest podawana do Reduce, która daje wyniki do pojedynczego data.frame.

Ostateczny Reduce(rbind, może zostać zastąpiony przez data.table s rbindlist w razie potrzeby.

3

Oto kolejny ohydne roztworowi

max_length = max(unlist(lapply(nested_list, function(x) lapply(x, lengths)))) 
data.frame(id = do.call(c, lapply(nested_list$id, rep, max_length)), 
      do.call(rbind, lapply(nested_list$ABAB, function(x) 
       do.call(cbind, lapply(x, function(y) { 
        if(length(y) < max_length) { 
         rep(y, max_length) 
        } else { 
         y 
        } 
       }))))) 
# id A B 
#1 1 A1 B1 
#2 1 A2 B1 
#3 1 A3 B1 
#4 2 A1 B1 
#5 2 A2 B1 
#6 2 A3 B1 
2

I jeszcze jedna, ale także inelegant- `d poszedł zbyt daleko w momencie ujrzałem inne odpowiedzi.

restructure <- function(nested_l) { 
    ids <- as.numeric(max(unlist(lapply(unlist(nested_l, recursive = FALSE), function(x){ 
    lapply(x, length) 
    })))) 

    temp = data.frame(rep(nested_l$id, each = ids), 
      sapply(1:length(nested_l$id), function(x){ 
       out <-unlist(lapply(nested_l[[2]], function(y){ 
       return(y[x]) 
       })) 
      })) 
    names(temp) <- c("id", unique(substring(unlist(nested_l[2]), first = 1, last = 1))) 
    return(temp) 
} 

> restructure(nested_list) 
    id A B 
1 1 A1 B1 
2 1 A2 B1 
3 1 A3 B1 
4 2 A1 B1 
5 2 A2 B1 
6 2 A3 B1 
1

Łączenie partii:

library(tidyverse) 
temp <- map(nested_list,~map(.x,~expand.grid(.x))) 
df <- map_df(1:2,~cbind(temp$id[[.x]],temp$ABAB[[.x]])) 

    Var1 A B 
1 1 A1 B1 
2 1 A2 B1 
3 1 A3 B1 
4 2 A1 B1 
5 2 A2 B1 
6 2 A3 B1