2010-02-05 9 views
27

J'essaye de merge plusieurs data.frames en un data.frame. Comme j'ai toute une liste de fichiers, j'essaye de le faire avec une structure en boucle.Fusionner plusieurs data.frames en un data.frame avec une boucle

Jusqu'à présent, l'approche en boucle fonctionne bien. Cependant, cela semble assez inefficace et je me demande s'il existe une approche plus rapide et plus facile. Voici le scénario: J'ai un répertoire avec plusieurs fichiers .csv. Chaque fichier contient le même identifiant qui peut être utilisé comme variable de fusion. Étant donné que les fichiers sont assez volumineux, j'ai pensé lire chaque fichier un à la fois dans R au lieu de lire tous les fichiers à la fois. Donc, je reçois tous les fichiers du répertoire avec list.files et lire dans les deux premiers fichiers. Ensuite, j'utilise merge pour obtenir un 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) 

Maintenant, j'utiliser une boucle for pour obtenir tous les .csv fichiers restants et merge-les dans le déjà existant 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) 
} 

Même si cela fonctionne très bien, je me demandais s'il y a un plus moyen élégant pour faire le travail?

Répondre

37

Vous pouvez regarder de près le related question on stackoverflow.

J'approche en deux temps: importer toutes les données (avec plyr), puis fusionner ensemble:

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

Cela vous donnera une liste de tous les fichiers que vous avez besoin maintenant de fusionner . Il y a plusieurs façons de le faire, mais voici une approche (avec Reduce):

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

Alternativement, vous pouvez le faire avec le package reshape si vous n'êtes pas à l'aise avec Reduce:

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

Il peut être intéressant de remarquer que vous pouvez obtenir toute e fusionné, avec une colonne '.id' supplémentaire contenant les noms de fichiers en appelant' ldply' au lieu de 'llply'. L'appel 'Reduce' ou' merge' n'est alors pas nécessaire. – CharlesB

1

Si je ne me trompe pas, un changement assez simple pourrait éliminer le 3:length(FileNames) bidouille:

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: puisque 'dataMerge' est un' data.frame 'vide, la fonction 'merge()' ne trouve pas d'identifiant commun dans la première boucle 'for'. si j'assigne par exemple le premier fichier à 'dataMerge', cela me ramène à mon idée initiale. – mropa

+0

Désolé, j'aurais dû l'essayer en premier. Je pensais à rbind(), dans lequel une trame de données vide est traitée comme si les colonnes requises étaient présentes mais vides. –