2010-02-05 3 views
27

Sto provando a merge diversi in uno data.frame. Dal momento che ho un intero elenco di file sto cercando di farlo con una struttura ad anello.Unisci più data.frames in un data.frame con un loop

Finora l'approccio del ciclo funziona correttamente. Tuttavia, sembra piuttosto inefficiente e mi chiedo se esiste un approccio più rapido e semplice.

Ecco lo scenario: Ho una directory con diversi file .csv. Ogni file contiene lo stesso identificatore che può essere utilizzato come variabile di fusione. Poiché i file sono di dimensioni piuttosto grandi, ho pensato di leggere ogni file uno alla volta in R invece di leggere tutti i file contemporaneamente. Quindi ottengo tutti i file della directory con list.files e letto nei primi due file. Successivamente uso merge per ottenere uno data.frame.

FileNames <- list.files(path=".../tempDataFolder/") 
FirstFile <- read.csv(file=paste(".../tempDataFolder/", FileNames[1], sep=""), 
      header=T, na.strings="NULL") 
SecondFile <- read.csv(file=paste(".../tempDataFolder/", FileNames[2], sep=""), 
       header=T, na.strings="NULL") 
dataMerge <- merge(FirstFile, SecondFile, by=c("COUNTRYNAME", "COUNTRYCODE", "Year"), 
      all=T) 

Ora uso un ciclo for per ottenere tutti i .csv file rimanenti e merge loro nel già esistente data.frame:

for(i in 3:length(FileNames)){ 
ReadInMerge <- read.csv(file=paste(".../tempDataFolder/", FileNames[i], sep=""), 
       header=T, na.strings="NULL") 
dataMerge <- merge(dataMerge, ReadInMerge, by=c("COUNTRYNAME", "COUNTRYCODE", "Year"), 
      all=T) 
} 

Anche se funziona bene mi chiedevo se esiste un altro modo elegante per fare il lavoro?

risposta

37

Si consiglia di guardare da vicino related question on stackoverflow.

vorrei affrontare questo in due fasi: importare tutti i dati (con plyr), poi unire insieme:

filenames <- list.files(path=".../tempDataFolder/", full.names=TRUE) 
library(plyr) 
import.list <- llply(filenames, read.csv) 

Che vi darà una lista di tutti i file che è ora necessario fondere insieme . Ci sono molti modi per farlo, ma qui è un approccio (con Reduce):

data <- Reduce(function(x, y) merge(x, y, all=T, 
    by=c("COUNTRYNAME", "COUNTRYCODE", "Year")), import.list, accumulate=F) 

In alternativa, si può fare questo con il pacchetto reshape se non si ha familiarità con Reduce:

library(reshape) 
data <- merge_recurse(import.list) 
+1

può valere la pena di notare che è possibile ottenere l'intera ° unito, con una colonna '.id' aggiuntiva contenente nomi di file chiamando' ldply' invece di 'llply'. La chiamata 'Reduce' o' merge' non è più necessaria. – CharlesB

1

Se non mi sbaglio, una abbastanza semplice cambiamento potrebbe eliminare la 3:length(FileNames) kludge:

FileNames <- list.files(path=".../tempDataFolder/", full.names=TRUE) 
dataMerge <- data.frame() 
for(f in FileNames){ 
    ReadInMerge <- read.csv(file=f, header=T, na.strings="NULL") 
    dataMerge <- merge(dataMerge, ReadInMerge, 
       by=c("COUNTRYNAME", "COUNTRYCODE", "Year"), all=T) 
} 
+0

@ken: poiché 'dataMerge' è un' data.frame' vuoto, la funzione 'merge()' non riesce a trovare un identificatore comune nel primo ciclo 'for'. se assegno, ad esempio, il primo file a "dataMerge", questo mi riporta alla mia idea iniziale. – mropa

+0

Scusa, avrei dovuto provarlo prima. Stavo pensando a rbind(), in cui un frame di dati vuoto viene trattato come se le colonne richieste fossero presenti ma vuote. –