2010-02-05 7 views
27

Próbuję merge kilka data.frames w jeden data.frame. Ponieważ mam całą listę plików, próbuję to zrobić za pomocą struktury pętli.Scal kilka data.frames w jednym data.frame z pętlą

Do tej pory podejście pętli działa dobrze. Wygląda to jednak dość nieefektywnie i zastanawiam się, czy istnieje szybsze i łatwiejsze podejście.

Oto scenariusz: Mam katalog z kilkoma plikami .csv. Każdy plik zawiera ten sam identyfikator, który może być użyty jako zmienna połączenia. Ponieważ pliki mają dość duży rozmiar, pomyślałem, aby czytać każdy plik po jednym na raz zamiast czytać wszystkie pliki naraz. Dostaję wszystkie pliki katalogu z list.files i czytam w pierwszych dwóch plikach. Następnie używam merge, aby uzyskać jedną 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) 

Teraz używam for pętlę, aby wszystkie pozostałe .csv plików i merge je do już istniejących 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) 
} 

Mimo że działa dobrze Zastanawiałem się, czy istnieje bardziej elegancki sposób na wykonanie pracy?

Odpowiedz

37

Być może zechcesz przyjrzeć się dokładnie related question on stackoverflow.

Chciałbym podejść do tego w dwóch etapach: import wszystkich danych (z plyr), a następnie połączyć je ze sobą:

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

To da ci listę wszystkich plików, które teraz trzeba połączyć razem . Istnieje wiele sposobów, aby to zrobić, ale tutaj jest jedno podejście (z Reduce):

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

Alternatywnie, można to zrobić za pomocą pakietu reshape jeśli nie są wygodne z Reduce:

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

może warto zauważyć, że można dostać cały th scalone, z dodatkową kolumną '.id' zawierającą nazwy plików poprzez wywołanie' ldply' zamiast 'llply'. Wywołanie 'Reduce' lub' merge' jest niepotrzebne. – CharlesB

1

Jeśli się nie mylę, to dość prosta zmiana może wyeliminować 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: ponieważ 'dataMerge' jest pustym' data.frame' funkcja 'merge()' nie może znaleźć wspólnego identyfikatora w pierwszej pętli 'for'. jeśli przypiszę np. pierwszy plik do 'dataMerge', to w pewien sposób przywróci mnie to do mojego pierwotnego pomysłu. – mropa

+0

Przepraszam, powinienem był wypróbować to pierwszy. Myślałem o rbind(), w którym pusta ramka danych jest traktowana tak, jakby wymagane kolumny były obecne, ale puste. –

Powiązane problemy