2013-03-05 2 views
7

Nel tentativo di rispondere allo a question in precedenza, mi sono imbattuto in un problema che sembrava essere semplice, ma non riuscivo a capirlo.Usa nomi oggetto in un elenco in lapply/ldply

Se ho un elenco di dataframes:

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) 

Che voglio rbind insieme, posso effettuare le seguenti operazioni:

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

Tuttavia, voglio un'altra colonna che identifica quale data.frame ogni è venuta la fila. Mi aspettavo di essere in grado di utilizzare il metodo deparse(substitute(x)) (here e altrove) per ottenere il nome del relativo data.frame e aggiungere una colonna. Questo è come mi sono avvicinato esso:

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

che restituisce

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]] 

Quindi, ovviamente, ogni elemento della lista non contiene il nome credo di sì. Qualcuno può suggerire un modo per ottenere quello che mi aspettavo (mostrato sotto)?

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

Non esattamente una risposta, ma si potrebbe essere interessati a vari metodi utilizzati [qui] (http://stackoverflow.com/q/15162197/324364). – joran

+1

Spararsi nel piede non usando una lista nominata. –

risposta

9

Definire la vostra lista con nomi e dovrebbe dare una colonna .id con il nome data.frame

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

uscita:

.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 

Quindi è possibile conoscere il nome data.frame dalla colonna df.all$.id

Modifica: Come per il commento di @Gary Weissman se si desidera generare automaticamente i nomi si può fare

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

Stavo scrivendo la stessa cosa tranne con 'do.call (rbind, df.list)' invece di 'ldply' che fornisce anche la riga originale – N8TRO

+2

L'unico svantaggio di questo approccio è che devi effettivamente scrivere a mano i nomi di tutti i tuoi dati. Potresti fare qualcosa come' names (df.list) <- paste0 ('df', seq_along (df.list)) ' –

+0

+1 Questo è veramente utile - in sostanza la risposta alla mia domanda è" Crea una lista nominata "- ma apprezzo che tu sia andato oltre! – alexwhan

3

Utilizzando solo base, si potrebbe provare qualcosa di simile:

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

do.call(rbind,dd) 
+0

@joran l'hai provato? sembra funzionare bene sulla mia macchina. –

+0

Heh. L'ho provato, ma era prima che avessi finito di modificarlo.Per un po ', avevi solo la linea 'lapply' lassù (e una versione diversa di esso anche boot) che sicuramente non funzionava. – joran

+0

ah scusate, il mio browser si è bloccato e le mie modifiche sono state mutilate ;-( –

2

nella definizione, df.list non hanno nomi, tuttavia, anche in questo caso il sostituto linguaggio Deparse non sembra lavorare easilty (come lapply chiamate .Internal(lapply(X, FUN)) - si dovrebbe guardare il sorgente per vedere se il nome dell'oggetto era disponibile e come ottenerlo

Qualcosa di simile

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

se si desidera utilizzare il function, invece di deparse(substitute(x)) uso match.call(), e si desidera che il secondo argomento, avendo cura di convertire a character

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