2013-03-05 9 views
7

Bei dem Versuch, a question früher zu beantworten, stieß ich auf ein Problem, das schien wie es sollte einfach sein, aber ich konnte nicht herausfinden.Verwenden Sie Objektnamen in einer Liste in lapply/ldply

Wenn ich eine Liste von Datenrahmen haben:

df1 <- data.frame(a=1:3, x=rnorm(3)) 
df2 <- data.frame(a=1:3, x=rnorm(3)) 
df3 <- data.frame(a=1:3, x=rnorm(3)) 

df.list <- list(df1, df2, df3) 

Dass ich zusammen rbind wollen, kann ich folgendes tun:

df.all <- ldply(df.list, rbind) 

Allerdings möchte ich eine weitere Spalte, die jede der data.frame identifiziert Reihe kam von. Ich erwartete, in der Lage zu sein, die deparse(substitute(x)) Methode (here und anderswo) zu verwenden, um den Namen des relevanten data.frame zu erhalten und eine Spalte hinzuzufügen. Dies ist, wie ich es angesprochen:

fun <- function(x) { 
    name <- deparse(substitute(x)) 
    x$id <- name 
    return(x) 
} 
df.all <- ldply(df.list, fun) 

Welche kehrt

a   x  id 
1 1 1.1138062 X[[1L]] 
2 2 -0.5742069 X[[1L]] 
3 3 0.7546323 X[[1L]] 
4 1 1.8358605 X[[2L]] 
5 2 0.9107199 X[[2L]] 
6 3 0.8313439 X[[2L]] 
7 1 0.5827148 X[[3L]] 
8 2 -0.9896495 X[[3L]] 
9 3 -0.9451503 X[[3L]] 

So offensichtlich jedes Element der Liste enthält nicht den Namen, den ich denke, es tut. Kann jemand einen Weg vorschlagen, um das zu bekommen, was ich erwartet habe (siehe unten)? nur

a   x id 
1 1 1.1138062 df1 
2 2 -0.5742069 df1 
3 3 0.7546323 df1 
4 1 1.8358605 df2 
5 2 0.9107199 df2 
6 3 0.8313439 df2 
7 1 0.5827148 df3 
8 2 -0.9896495 df3 
9 3 -0.9451503 df3 
+1

Nicht gerade eine Antwort, aber Sie könnten [hier] in den verschiedenen Methoden interessiert sein (http://stackoverflow.com/q/15162197/324364). – joran

+1

Schießen Sie sich in den Fuß, indem Sie keine benannte Liste verwenden. –

Antwort

9

mit Namen Definieren Sie Ihre Liste und es sollten Sie eine .id Spalte mit dem data.frame Namen geben

df.list <- list(df1=df1, df2=df2, df3=df3) 
df.all <- ldply(df.list, rbind) 

Ausgang:

.id a   x 
1 df1 1 1.84658809 
2 df1 2 -0.01177462 
3 df1 3 0.58579469 
4 df2 1 -0.64748756 
5 df2 2 0.24384614 
6 df2 3 0.59012676 
7 df3 1 -0.63037679 
8 df3 2 -1.17416295 
9 df3 3 1.09349618 

Dann können Sie kennen den data.frame Namen aus der Spalte df.all$.id

Bearbeiten: Wie pro Kommentar @Gary Weissman, wenn Sie die Namen generieren möchten automatisch können Sie

names(df.list) <- paste0('df',seq_along(df.list) 
+0

Ich schrieb die gleiche Sache außer mit 'do.call (rbind, df.list)' anstelle von 'ldply', das auch die ursprüngliche Zeile enthält – N8TRO

+2

Der einzige Nachteil bei diesem Ansatz ist, dass Sie die Namen all Ihrer Datenframes manuell eingeben müssen.Können Sie etwas wie' names (df.list) <- paste0 ('df', seq_along (df.list)) ' –

+0

+1 Das ist wirklich hilfreich - im Wesentlichen die Antwort auf meine Frage ist" Machen Sie es zu einer benannten Liste "- aber ich weiß es zu schätzen, dass Sie weiter gegangen! – alexwhan

3

Base, könnte man versuchen, so etwas wie:

dd <- lapply(seq_along(df.list), function(x) cbind(df_name = paste0('df',x),df.list[[x]])) 

do.call(rbind,dd) 
+0

@joran hast du es versucht? es scheint auf meiner Maschine gut zu funktionieren. –

+0

Heh. Ich habe es versucht, aber das war bevor du es fertig bearbeitest.Für eine Weile hatten Sie nur die "lapply" -Linie dort oben (und eine andere Version davon zu booten), die definitiv nicht funktioniert hat. – joran

+0

ah Entschuldigung, mein Browser war eiskalt und meine Bearbeitungen wurden verstümmelt ;-( –

2

In Ihrer Definition, df.list keine Namen haben, aber selbst dann ist die Deparse Ersatz Idiom nicht zur Arbeit easilty erscheint (wie lapply ruft .Internal(lapply(X, FUN)) - Sie würden an der Quelle zu suchen, um zu sehen, ob die Objektnamen vorhanden war und wie es

So etwas wie

erhalten
names(df.list) <- paste('df', 1:3, sep = '') 

foo <- function(n, .list){ 
     .list[[n]]$id <- n 
     .list[[n]] 
     } 

    a   x id 
1 1 0.8204213 a 
2 2 -0.8881671 a 
3 3 1.2880816 a 
4 1 -2.2766111 b 
5 2 0.3912521 b 
6 3 -1.3963381 b 
7 1 -1.8057246 c 
8 2 0.5862760 c 
9 3 0.5605867 c 
2

tun, wenn Sie Ihre function verwenden möchten, statt deparse(substitute(x)) Verwendung match.call(), und das zweite Argument wollen, um sicherzustellen, zu konvertieren es character

name <- as.character(match.call()[[2]]) 
Verwandte Themen