webentwicklung-frage-antwort-db.com.de

Trimmen einer großen (3,5 GB) csv-Datei zum Einlesen in R

Ich habe also eine Datendatei (durch Semikolon getrennt) mit vielen Details und unvollständigen Zeilen (führt zu einer Drosselung von Access und SQL). Die Datensätze auf Landkreisebene sind für 40 Jahre in Segmente, Untersegmente und Untersubsegmente (für insgesamt ~ 200 Faktoren) unterteilt. Kurz gesagt, es ist riesig und wird nicht in den Speicher passen, wenn ich es einfach nur lesen möchte.

Meine Frage ist also, da ich alle Grafschaften will, aber nur ein Jahr (und nur die höchste Ebene des Segments ... was am Ende zu etwa 100.000 Zeilen führt), was wäre der beste Weg, um darüber zu kommen dieses Rollup in R?

Momentan versuche ich, irrelevante Jahre mit Python herauszuschneiden, die Dateigröße zu umgehen, indem ich nur eine Zeile lese und arbeite, aber ich würde eine reine R-Lösung bevorzugen (CRAN-Pakete OK). Gibt es eine ähnliche Möglichkeit, Dateien in R Stück für Stück einzulesen?

Alle Ideen wären sehr dankbar.

Update:

  • Einschränkungen
    • Muss my -Maschine verwenden, also keine EC2-Instanzen
    • So R-nur wie möglich. Geschwindigkeit und Ressourcen sind in diesem Fall kein Problem ... vorausgesetzt, meine Maschine explodiert nicht ...
    • Wie Sie unten sehen können, enthalten die Daten gemischte Typen, die ich später bearbeiten muss
  • Daten
    • Die Daten sind 3,5 GB, mit etwa 8,5 Millionen Zeilen und 17 Spalten
    • Ein paar tausend Zeilen (~ 2k) sind fehlerhaft, mit nur einer Spalte anstelle von 17
      • Diese sind völlig unwichtig und können fallen gelassen werden
    • Ich brauche nur ~ 100.000 Zeilen aus dieser Datei (siehe unten)

Datenbeispiel:

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC  [Malformed row]
[8.5 Mill rows]

Ich möchte einige Spalten herausschneiden und zwei von 40 verfügbaren Jahren auswählen (2009-2010 von 1980-2020), damit die Daten in R passen:

County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]

Ergebnisse:

Nachdem ich mich mit all den Vorschlägen beschäftigt hatte, entschied ich, dass die von JD und Marek vorgeschlagenen readLines am besten funktionieren würden. Ich habe Marek den Check gegeben, weil er eine Beispielimplementierung gegeben hat.

Ich habe eine etwas angepasste Version der Implementierung von Marek für meine endgültige Antwort hier reproduziert, indem ich strsplit und cat verwendete, um nur die Spalten zu behalten, die ich möchte.

Es sollte auch beachtet werden, dass dies VIEL weniger effizient als Python ist ... wie in, chomps Python durch die 3,5 GB-Datei in 5 Minuten, während R etwa 60 braucht ... aber wenn Sie nur R haben, dann ist das alles Das ist das Ticket.

## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
  line.split <- strsplit(line, ';')
  if (length(line.split[[1]]) > 1) {
    if (line.split[[1]][3] == '2009') {
        cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
    }
  }
  line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)

Fehler nach Ansatz:

  • sqldf
    • Dies ist definitiv das, was ich in Zukunft für diese Art von Problem verwenden werde, wenn die Daten gut geformt sind. Wenn dies jedoch nicht der Fall ist, verschluckt SQLite.
  • Karte verkleinern
    • Um ehrlich zu sein, haben mich die Docs ein wenig eingeschüchtert, also kam ich nicht dazu, es auszuprobieren. Es sah so aus, als müsste das Objekt im Gedächtnis sein, was den Punkt besiegen würde, wenn dies der Fall wäre.
  • bigmemory
    • Dieser Ansatz ist sauber mit den Daten verknüpft, kann jedoch nur jeweils einen Typ verarbeiten. Als Ergebnis fielen alle meine Zeichenvektoren, wenn sie in eine große Tabelle eingefügt wurden. Wenn ich jedoch große Datensätze für die Zukunft entwerfen muss, würde ich nur Zahlen verwenden, um diese Option am Leben zu erhalten.
  • scan
    • Der Scan schien ähnliche Probleme zu haben wie der große Speicher, jedoch mit allen Mechanismen von readLines. Kurz gesagt, es passte dieses Mal einfach nicht zur Rechnung.
84
FTWynn

Mein Versuch mit readLines. Dieser Codeteil erstellt csv mit ausgewählten Jahren.

file_in <- file("in.csv","r")
file_out <- file("out.csv","a")
x <- readLines(file_in, n=1)
writeLines(x, file_out) # copy headers

B <- 300000 # depends how large is one pack
while(length(x)) {
    ind <- grep("^[^;]*;[^;]*; 20(09|10)", x)
    if (length(ind)) writeLines(x[ind], file_out)
    x <- readLines(file_in, n=B)
}
close(file_in)
close(file_out)
37
Marek

Gibt es eine ähnliche Möglichkeit, Dateien in R Stück für Stück einzulesen?

Ja. Die Funktion readChar () liest einen Zeichenblock ein, ohne davon auszugehen, dass sie nullterminiert sind. Wenn Sie Daten in einer Zeile gleichzeitig lesen möchten, können Sie readLines () verwenden. Wenn Sie einen Block oder eine Zeile lesen, eine Operation ausführen und dann die Daten ausschreiben, können Sie den Speicherproblem vermeiden. Wenn Sie auf Amazon EC2 eine große Speicherinstanz starten möchten, können Sie bis zu 64 GB RAM erhalten. Das sollte Ihre Datei plus viel Platz für die Bearbeitung der Daten enthalten.

Wenn Sie mehr Geschwindigkeit benötigen, ist die Empfehlung von Shane, Map Reduce zu verwenden, sehr gut. Wenn Sie jedoch den Weg der Verwendung einer großen Speicherinstanz in EC2 gehen, sollten Sie sich das Multicore-Paket für die Verwendung aller Kerne auf einer Maschine ansehen. 

Wenn Sie viele Gigs mit begrenzten Daten in R einlesen möchten, sollten Sie zumindest das sqldf -Paket untersuchen, mit dem Sie direkt in sqldf von R importieren und dann die Daten innerhalb von R bearbeiten können der schnellsten Wege, um Gigs von Daten in R zu importieren, wie in dieser vorherigen Frage erwähnt. 

10
JD Long

Ich bin kein Experte in diesem Bereich, aber Sie könnten vielleicht MapReduce versuchen, was im Prinzip bedeuten würde, "auseinander zu gehen und zu erobern". R hat mehrere Optionen dafür, darunter:

  1. mapReduce (reines R)
  2. RHIPE (was Hadoop verwendet); Siehe Beispiel 6.2.2 in der Dokumentation Ein Beispiel für Subsetting-Dateien

Alternativ bietet R mehrere Pakete für den Umgang mit großen Daten, die außerhalb des Arbeitsspeichers (auf der Festplatte) liegen. Sie könnten wahrscheinlich das gesamte Dataset in ein bigmemory-Objekt laden und die Reduktion vollständig innerhalb von R durchführen. Siehe http://www.bigmemory.org/ für eine Reihe von Tools, um dies zu erreichen.

9
Shane

Das Paket ff ist eine transparente Methode, um mit großen Dateien umzugehen.

Sie können das Paket Website und/oder eine Präsentation darüber sehen.

Ich hoffe das hilft

6
Ali

Was ist mit readr und der read_*_chunked familie?

Also in deinem Fall:

testfile.csv

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5
lol
Ada County;NC;2013;1;FIRE;Financial;Banks;82.5

Aktueller Code

require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)

Dies gilt f für jeden Block, wobei die Col-Namen gespeichert und die gefilterten Ergebnisse am Ende kombiniert werden. Siehe ?callback , der die Quelle dieses Beispiels ist.

Das führt zu:

# A tibble: 2 × 8
      County State  Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment`   GDP
*      <chr> <chr> <int>   <int>   <chr>         <chr>             <chr> <dbl>
1 Ada County    NC  2009       4    FIRE     Financial             Banks   801
2 Ada County    NC  2010       1    FIRE     Financial             Banks   825

Sie können sogar chunk_size erhöhen, aber in diesem Beispiel gibt es nur 4 Zeilen.

5
Rentrop

Es gibt ein brandneues Paket namens colbycol, mit dem Sie nur die gewünschten Variablen aus riesigen Textdateien einlesen können:

http://colbycol.r-forge.r-project.org/

Alle Argumente werden an read.table übergeben, sodass Sie durch die Kombination eine recht enge Untermenge erhalten.

5
Ari B. Friedman

Sie könnten Daten in die SQLite-Datenbank importieren und dann mit RSQLite Teilmengen auswählen.

5
Marek

Haben Sie sich mit bigmemory befasst? _ Überprüfen Sie this und this

4
George Dontas

scan () hat sowohl ein nlines-Argument als auch ein überspringendes Argument. Gibt es einen Grund, aus dem Sie einfach einen Teil der Zeilen einlesen und das Datum überprüfen können, um zu sehen, ob es angebracht ist? Wenn die Eingabedatei nach Datum geordnet ist, können Sie einen Index speichern, der Sie darüber informiert, was Ihre Sprung- und Zeilenzeilen sein sollten, um den Prozess in der Zukunft zu beschleunigen.

3
frankc

Möglicherweise können Sie zu MySQL oder PostgreSQL migrieren, um die Einschränkungen von MS Access zu verhindern. 

Es ist ziemlich einfach, R mit diesen Systemen mit einem auf - DBI (auf CRAN verfügbaren) Datenbank-Connector zu verbinden. 

3
FloE

Heutzutage sind 3,5 GB nicht wirklich so groß. Ich kann in der Amazon-Cloud für $ 2,80 pro Stunde Zugriff auf einen Computer mit 244 GB RAM (r3.8xlarge) erhalten. Wie viele Stunden brauchen Sie, um herauszufinden, wie Sie das Problem mit Big-Data-Lösungen lösen können? Wie viel ist deine Zeit wert? Ja, es wird eine oder zwei Stunden dauern, um herauszufinden, wie AWS verwendet wird. Sie können jedoch die Grundlagen einer kostenlosen Stufe erlernen, die Daten hochladen und die ersten 10-KByte-Zeilen in R einlesen, um zu überprüfen, ob es funktioniert große Speicherinstanz wie r3.8xlarge und lesen Sie alles ein! Nur mein 2c.

1
Sean

Jetzt, 2017, würde ich vorschlagen, für spark und sparkR zu gehen. 

  • die Syntax kann auf einfache, ziemlich ähnliche Weise geschrieben werden

  • es passt gut zu kleinem Speicher (klein im Sinne von 2017)

Es kann jedoch eine einschüchternde Erfahrung sein, um loszulegen ...

0
Ott Toomet