2017-10-24 6 views
0

Ich habe eine große list in folgendem Format:Melt große Liste in langen Format [effizient]

example <- list("12908430751", "12908453145", c("12908453145","12908472085","453145472085"), c("12908453145", "12908472085", "453145472085"), "12908453145", c("12908453145", "12908472085", "453145472085")) 

example 
[[1]] 
[1] "12908430751" 

[[2]] 
[1] "12908453145" 

[[3]] 
[1] "12908453145" "12908472085" "453145472085" 

[[4]] 
[1] "12908453145" "12908472085" "453145472085" 

[[5]] 
[1] "12908453145" 

[[6]] 
[1] "12908453145" "12908472085" "453145472085" 

Während library(reshape2); melt(example) Werke für kleinere Datenmengen verwendet wird, dauert es eine sehr lange Zeit für meine eigentlichen Daten (~ 6 Millionen Elemente). Ich frage mich, ob es einen effizienteren Weg gibt, dies zu realisieren.

Output 
     value  L1 
1 12908430751 1 
2 12908453145 2 
3 12908453145 3 
4 12908472085 3 
5 453145472085 3 
6 12908453145 4 
7 12908472085 4 
8 453145472085 4 
9 12908453145 5 
10 12908453145 6 
11 12908472085 6 
12 453145472085 6 

fand ich etwas ähnlichen Melt data.frame containing list to long format (efficiently) aber nicht, dies zu meinem Fall anzupassen.

RESULT

Danke Jungs, habe gerade eine schnelle Überprüfung auf meiner Liste example1 mit 1 Million Elemente

system.time({foo <- unlist(lapply(example1, function(x) length(x))) 
result <- data.frame(value = unlist(example1), 
L1 = unlist(sapply(1:length(foo), function(x) rep(x, foo[x]))))}) 

Benutzersystem verstrichene 9,63 0,10 9,73

system.time({ 
df <- structure(list(value = example1 , id = 1:length(example1)), .Names = 
c("value", "L1"), row.names = 1:length(example), class = "data.frame") 
result1 <- setDT(df)[, .(value = unlist(value)), by = .(L1)]}) 

Benutzersystem verstrichen 1,25 0,00 1,26

system.time({result3 <- tibble(L1 = 1:length(example1), value = example1) %>% unnest()}) 

Benutzersystem verstrichene 5,99 0,00 5,98

system.time({ stack(setNames(example1, seq_along(example)))}) 

Benutzersystem verstrichene 1,08 0,00 1,08

kann nicht die parallele Version mit einem Ergebnis zu Ende bekommen, aber vielleicht auf meiner Seite sein. Obwohl ich Effizienz nicht definiert habe, gehe ich mit dem schnellsten Ansatz.

+1

Es wird weit von der schnellsten sein, aber 'stack (setNames (Beispiel, seq_along (Beispiel)))' wird eine Größenordnung schneller als 'schmelzen 'durch meine Tests. – thelatemail

+0

Antworten hier scheinen angemessen und sehr schnell zu sein - https://stackoverflow.com/questions/31551036/unlisting-columns-by-groups – thelatemail

+0

Und für mich zumindest @ thelatemail Vorschlag ist prägnanter und lesbarer als jeder der andere Lösungen geschrieben (einschließlich meiner eigenen) – markdly

Antwort

2

wahrscheinlich Es schnellere Methoden sind, wenn Sie graben um, aber Basis R hat stack was ziemlich schnell funktioniert:

stack(setNames(example, seq_along(example))) 

#   values ind 
#1 12908430751 1 
#2 12908453145 2 
#3 12908453145 3 
#4 12908472085 3 
#5 453145472085 3 
#6 12908453145 4 
#7 12908472085 4 
#8 453145472085 4 
#9 12908453145 5 
#10 12908453145 6 
#11 12908472085 6 
#12 453145472085 6 

Es Interna sind grundsätzlich ein unlist und dann jeden Wert von names(x), die entsprechenden lengths(x) mal wiederholen. Siehe utils:::stack.default, um den Code zu lesen.

+1

Wahrscheinlich schneller wäre 'data.frame (Werte = unlist (Beispiel), ind = rep (seq_along (Beispiel), Längen (Beispiel))) ' – akrun

0

Sie eine Verbesserung sehen kann parallel ohne allzu großen Aufwand

library(parallel) 
library(dplyr) 
library(reshape2) 
library(data.table) # for rleid 

cl <- makeCluster(detectCores()) # automatically detect number of cores 
clusterEvalQ(cl, { library(reshape2) }) # need to export package to workers 

# Split your data into chunks 
nchunks <- 2 # does not need to equal number of cores (can be > # of cores but should be close to number of cores) 
chunks <- split(example, cut(seq_along(example), nchunks)) 
result <- parLapply(cl, chunks, function(i) { melt(i) }) 
stopCluster(cl) 

# combine back into data.frame 
df <- Reduce("rbind", result) 
answer <- df %>% 
     mutate(L1 = rleid(L1)) 

Ausgabe

  value L1 
1 12908430751 1 
2 12908453145 2 
3 12908453145 3 
4 12908472085 3 
5 453145472085 3 
6 12908453145 4 
7 12908472085 4 
8 453145472085 4 
9 12908453145 5 
10 12908453145 6 
11 12908472085 6 
12 453145472085 6 
0

Wenn Sie gerne einen tidyverse Ansatz verwenden verwenden, wie etwa eine tibble machen, die Sie dann unnest (Ich bin mir nicht sicher, wie effizient das für Ihren Anwendungsfall sein wird):

library(tidyverse) 

tibble(L1 = 1:length(example), value = example) %>% unnest() 

#> # A tibble: 12 x 2 
#>  L1  value 
#> <int>  <chr> 
#> 1  1 12908430751 
#> 2  2 12908453145 
#> 3  3 12908453145 
#> 4  3 12908472085 
#> 5  3 453145472085 
#> 6  4 12908453145 
#> 7  4 12908472085 
#> 8  4 453145472085 
#> 9  5 12908453145 
#> 10  6 12908453145 
#> 11  6 12908472085 
#> 12  6 453145472085 
0

Sie können wollen versuchen, diese:

df <- structure(list(value = example , id = 1:length(example)), .Names = c("value", "L1"), 
      row.names = 1:length(example), class = "data.frame") 

library(data.table) 
setDT(df)[, .(value = unlist(value)), by = .(L1)] 

##  L1  value 
## 1: 1 12908430751 
## 2: 2 12908453145 
## 3: 3 12908453145 
## 4: 3 12908472085 
## 5: 3 453145472085 
## 6: 4 12908453145 
## 7: 4 12908472085 
## 8: 4 453145472085 
## 9: 5 12908453145 
## 10: 6 12908453145 
## 11: 6 12908472085 
## 12: 6 453145472085 
Verwandte Themen