2012-07-11 16 views
112

Angenommen, wir haben einen Ordner mit mehreren data.csv-Dateien, die jeweils die gleiche Anzahl von Variablen enthalten, aber jeweils zu unterschiedlichen Zeiten.Importieren mehrerer CSV-Dateien in R

Gibt es einen Weg in R, um alle gleichzeitig zu importieren, anstatt sie alle einzeln importieren zu müssen?

Mein Problem ist, dass ich rund 2000 Datendateien zu importieren und sie einzeln nur importieren zu müssen, indem Sie den Code verwenden:

read.delim(file="filename", header=TRUE, sep="\t") 

nicht sehr effizient ist.

Antwort

155

So etwas wie die folgenden funktionieren soll:

temp = list.files(pattern="*.csv") 
myfiles = lapply(temp, read.delim) 

Dies setzt voraus, dass Sie diese CSVs in einem einzigen Verzeichnis haben - Ihr aktuelles Arbeitsverzeichnis - und dass alle von ihnen haben die untere Gehäuseverlängerung .csv.

aktualisieren

Schnelle und schmutzige Lösung getrennt data.frames („dirty“, weil ich nicht die Mühe gemacht haben, die .csv Erweiterung zu bereinigen, aber das ist leicht genug, um mit etwas regex zu tun) zu erhalten:

temp = list.files(pattern="*.csv") 
for (i in 1:length(temp)) assign(temp[i], read.csv(temp[i])) 

Oder ohne assign, und zu zeigen, (1), wie der Dateiname gereinigt und kann (2) zeigen, wie list2env verwenden möchten, können Sie versuchen, die folgenden:

temp = list.files(pattern="*.csv") 
list2env(
    lapply(setNames(temp, make.names(gsub("*.csv$", "", temp))), 
     read.csv), envir = .GlobalEnv) 
+0

Dank! Das funktioniert sehr gut ... Wie würde ich jede Datei, die ich gerade importiert habe, benennen, damit ich sie leicht aufrufen kann? –

+0

Wenn Sie uns die ersten Zeilen einiger Ihrer Dateien zeigen können, haben wir vielleicht ein paar Vorschläge - bearbeiten Sie Ihre Frage dazu! – Spacedman

+1

Der obige Code funktioniert perfekt, um sie als einzelne Objekte zu importieren, aber wenn ich versuche, eine Spalte aus dem Datensatz aufzurufen, erkennt sie es nicht, da es nur ein einzelnes Objekt ist. dh meine Version des obigen Codes ist: setwd ('C:/Users/neu/Desktop/Dives/0904_003') Temp <-list.files (pattern = "*. csv") ddives <- lapply (temp, read.csv) So, jetzt Jede Datei heißt ddives [n], aber wie würde ich eine Schleife schreiben, um alle Datenrahmen und nicht einzelne Objekte zu erstellen? Ich kann dies einzeln mit dem data.frame-Operator erreichen, bin mir aber nicht sicher, wie ich das umwandeln kann. @mrdwab –

22

Sie könnten nicht nur lapply oder ein anderes Schleifenkonstrukt in R verwenden, sondern auch Ihre CSV-Dateien in eine Datei zusammenführen.

In Unix, wenn die Dateien und keine Header, seine dann so einfach wie:

cat *.csv > all.csv 

oder wenn es Header, und Sie können eine Zeichenfolge finden, die Kopf- und nur Header übereinstimmt (dh suppose Kopfzeilen alle mit „Alter“) beginnen, dann würden Sie tun:

cat *.csv | grep -v ^Age > all.csv 

ich in Windows denken Sie dies aus dem DOS-Eingabefeld mit COPY und SEARCH (oder FIND oder etwas) tun könnten, aber warum nicht installieren cygwin und hol den po Wer ist die Unix-Kommandozeile?

+0

oder gehen Sie sogar mit der _Git Bash_, die mit der 'Git'-Installation stolpert? –

-3

Dies ist ein Teil meines Skripts.

#This cycle read the files in a directory and assign the filenames to datasets 
files <- list.files(pattern=".csv$") 
for(i in files) { 
    X <- read.table(i, header=TRUE) 
    SN<-X$A/X$B 
    X<-cbind(X,SN) 
    ds<-paste("data_",i, sep="")#this add "data_" to the name of file 
    ds<-substr(ds, 1, nchar(ds)-4)#remove the last 4 char (.csv) 
    assign(ds, X) 
} 
7

Dies ist der Code, den ich alle csv-Dateien in R. lesen entwickelt Es wird ein Datenrahmen für jede CSV-Datei einzeln und Titel, der den ursprünglichen Namen der Datei (Entfernen von Leerzeichen und die .csv) Ich hoffe, Sie erstellen Datenrahmen finde es nützlich!

59

Hier ist eine weitere Option zum Konvertieren der CSV-Dateien in eine data.frame. Verwenden der R-Basisfunktionen. Dies ist eine Größenordnung langsamer als die Optionen unten.

# Get the files names 
files = list.files(pattern="*.csv") 
# First apply read.csv, then rbind 
myfiles = do.call(rbind, lapply(files, function(x) read.csv(x, stringsAsFactors = FALSE))) 

Edit: - Noch ein paar zusätzliche Möglichkeiten mit data.table und readr

Eine fread()-Version, die eine Funktion des data.table Paket. Dies sollte die schnellste Option sein.

library(data.table) 
DT = do.call(rbind, lapply(files, fread) 
# the same using `rbindlist()` 
DT = rbindlist(lapply(files, fread)) 

readr verwenden, die für das Lesen von CSV-Dateien ein neues hadley Paket. Ein bisschen langsamer als fread aber mit unterschiedlichen Funktionalitäten.

library(readr) 
library(dplyr) 
tbl = lapply(files, read_csv) %>% bind_rows() 
+2

Wie funktioniert dies gegen Reduzieren (rbind, lapply (...))? Nur lernen, R aber meine Schätzung ist weniger performant – aaron

+4

Ich habe hinzugefügt eine 'data.table' -Version, die die Leistung verbessern sollte – marbel

+0

Ist es möglich, nur bestimmte Dateien zu lesen? ex Dateien, die" Wetter "im Namen enthalten? – SoilSciGuy

-1

Ich benutze diese erfolgreich:

xlist<-list.files(pattern = "*.csv") 

for(i in xlist) { 
    x <- read.csv((i)) 
    assign(i, x) 
    } 
-1

, wenn Sie verschiedene csv-Dateien in eine data.frame sammeln möchten, können Sie die folgenden. Beachten Sie, dass das "x" data.frame im Voraus erstellt werden sollte.

2

Aufbauend auf dem Kommentar von dnlbrk kann assign bei großen Dateien wesentlich schneller sein als list2env.

library(readr) 
library(stringr) 

List_of_file_paths <- list.files(path ="C:/Users/Anon/Documents/Folder_with_csv_files/", pattern = ".csv", all.files = TRUE, full.names = TRUE) 

Durch das full.names Argument auf true setzen, werden Sie den vollständigen Pfad zu jeder Datei als separate Zeichenfolge in der Liste der Dateien erhalten, zum Beispiel List_of_file_paths [1] wird so etwas wie „C: /Users/Anon/Documents/Folder_with_csv_files/file1.csv“

for(f in 1:length(List_of_filepaths)) { 
    file_name <- str_sub(string = List_of_filepaths[f], start = 46, end = -5) 
    file_df <- read_csv(List_of_filepaths[f]) 
    assign(x = file_name, value = file_df, envir = .GlobalEnv) 
} 

könnten Sie die data.table fread oder Basispaket read.csv R anstelle von read_csv. Mit dem Schritt Dateiname können Sie den Namen so aufräumen, dass jeder Datenrahmen nicht den vollständigen Pfad zur Datei als Namen enthält. Sie könnten Ihre Schleife erstrecken sich weiter Dinge auf die Datentabelle zu tun, bevor es auf die globale Umwelt, zum Beispiel die Übertragung:

for(f in 1:length(List_of_filepaths)) { 
    file_name <- str_sub(string = List_of_filepaths[f], start = 46, end = -5) 
    file_df <- read_csv(List_of_filepaths[f]) 
    file_df <- file_df[,1:3] #if you only need the first three columns 
    assign(x = file_name, value = file_df, envir = .GlobalEnv) 
} 
26

Eine raschere und prägnante tidyverse(aka: dplyr/purrr) Lösung:

tbl <- 
    list.files(pattern="*.csv") %>% 
    map_df(~read_csv(.)) 

Wenn die Typumwandlung frech ist, können Sie alle Spalten dazu zwingen, als Zeichen zu fungieren.

tbl <- 
    list.files(pattern="*.csv") %>% 
    map_df(~read_csv(., col_types = cols(.default = "c"))) 

Wenn Sie wollen, in Unterverzeichnisse tauchen Sie Ihre Liste von Dateien zu konstruieren, um schließlich zu binden, dann müssen Sie die Pfadnamen enthalten, sowie die Dateien mit ihren vollständigen Namen in der Liste registrieren. Dadurch kann die Bindungsarbeit außerhalb des aktuellen Verzeichnisses ausgeführt werden. (Denken an den vollen Pfadnamen als wie Pässe Betriebs Bewegung über Verzeichnis ‚Grenzen‘ zu erlauben, zurück.)

tbl <- 
    list.files(path = "./subdirectory/", 
       pattern="*.csv", 
       full.names = T) %>% 
    map_df(~read_csv(., col_types = cols(.default = "c"))) 

Wie Hadley beschreibt here (etwa in der Mitte):

map_df(x, f) ist das Gleiche wie do.call("rbind", lapply(x, f)) aber unter der Haube ist viel effizienter.

und ein Dankeschön an Jake Kaupp für mich here zu map_df() einzuführen.

Bonus Feature-Hinzufügen von Dateinamen in den Datensätzen pro Niks Feature Request in den Kommentaren unten:
* original filename zu jedem Datensatz hinzufügen.

Code erklärt: eine Funktion zum Anhängen des Dateinamens an jeden Datensatz während der ersten Lesung der Tabellen. Verwenden Sie dann diese Funktion anstelle der -Funktion.

read_plus <- function(flnm) { 
    read_csv(flnm) %>% 
     mutate(filename = flnm) 
} 

tbl_with_sources <- 
    list.files(pattern="*.csv", 
       full.names = T) %>% 
    map_df(~read_plus(.)) 

(Die Schublade gesteckt und Unterverzeichnis Handhabung Ansätze können auch innerhalb der read_plus() funktioniert auf die gleiche Art und Weise wie in den zweiten und dritten Varianten vorschlagen oben behandelt werden.)

+0

Sie Lösung funktioniert für mich. In diesem möchte ich diesen Dateinamen speichern, um sie zu unterscheiden. Ist es möglich? – Niks

+0

@Niks - Sicher! Schreiben und vertauschen Sie einfach eine kleine Funktion, die nicht nur die Dateien liest, sondern jedem gelesenen Datensatz einen Dateinamen hinzufügt. Wie so 'readAddFilename <- function (flnm) { read_csv (flnm)%>% muate (filename = flnm) }' Dann einfach das in die 'map_df' anstelle der einfachen nur lesen' read_csv() ' das ist jetzt da. Ich kann den obigen Eintrag aktualisieren, um die Funktion und wie es in die Pipe passen würde, wenn Sie noch Fragen haben oder Sie denken, dass das hilfreich sein wird. –

3

plyr::ldply Verwendung ist es in etwa 50% Erhöhen Sie die Geschwindigkeit, indem Sie die Option .parallel aktivieren, während Sie 400 csv-Dateien mit jeweils etwa 30-40 MB lesen. Beispiel enthält eine Textfortschrittsleiste.

library(plyr) 
library(data.table) 
library(doSNOW) 

csv.list <- list.files(path="t:/data", pattern=".csv$", full.names=TRUE) 

cl <- makeCluster(4) 
registerDoSNOW(cl) 

pb <- txtProgressBar(max=length(csv.list), style=3) 
pbu <- function(i) setTxtProgressBar(pb, i) 
dt <- setDT(ldply(csv.list, fread, .parallel=TRUE, .paropts=list(.options.snow=list(progress=pbu)))) 

stopCluster(cl) 
0

Sie die hervorragende sparklyr Paket für diese verwenden:

# RStudio will help you get set-up with the Spark dependencies 
library(sparklyr) 
library(dplyr) 
sc <- spark_connect(master = "local", version = "2.0.2") 

df <- spark_read_csv(sc, 
        "dummy", 
        "file:////Users/bob/dev/data/results/*/*/*-metrics.csv") %>% 
    collect() 
Verwandte Themen