2016-04-21 9 views
6

Ich habe eine ~ 220 Millionen Zeile, 7 Spalte CSV-Datei. Ich muss Zeile 2636759 entfernen. Diese Datei ist 7.7 GB, mehr als in den Speicher passen. Ich bin am vertrautesten mit R, könnte dies aber auch in Python oder Bash tun.Entfernen Sie bekannte genaue Zeile in großen csv

Ich kann diese Datei nicht in einem Vorgang lesen oder schreiben. Was ist der beste Weg, um diese Datei inkrementell auf der Festplatte zu erstellen, anstatt dies alles im Speicher zu tun?

Ich habe versucht, dies auf SO zu finden, aber habe nur gefunden, wie man das mit Dateien macht, die klein genug sind, um im Speicher zu lesen/schreiben, oder mit Zeilen, die am Anfang der Datei stehen.

+0

Dank, aber ich bereits Pandas versucht: -/ Tonnen von Fehlern, aber here zwei, zum Beispiel 'File "Pandas/parser.pyx", Linie 788, in pandas.parser.TextReader._read_low_memory (Pandas/Parser .c: 8244) ' ' Datei "pandas/parser.pyx", Zeile 1833, in pandas.parser.raise_parser_error (pandas/parser.c: 22649) pandas.parser.CParserError: Fehler beim Token von Daten. C-Fehler: Erwartete 7 Felder in Zeile 2636759, sah 8' – hedgedandlevered

+0

sicher, ich könnte 100.000 Reihen gleichzeitig tun ... wie? – hedgedandlevered

+0

Überprüfen Sie diese Lösung von einer anderen Frage. Es ändert die Datei an Ort und Stelle, sollte also schnell sein. http://StackOverflow.com/a/2330081/4190526 –

Antwort

6

Eine Python-Lösung:

import os 
with open('tmp.csv','w') as tmp: 

    with open('file.csv','r') as infile: 
     for linenumber, line in enumerate(infile): 
      if linenumber != 10234: 
       tmp.write(line) 

# copy back to original file. You can skip this if you don't 
# mind (or prefer) having both files lying around   
with open('tmp.csv','r') as tmp: 
    with open('file.csv','w') as out: 
     for line in tmp: 
      out.write(line) 

os.remove('tmp.csv') # remove the temporary file 

Diese dupliziert die Daten, die nicht optimal sein kann, wenn Speicherplatz ein Problem. Ein an Ort und Stelle Schreib wird komplizierter sein, ohne dass die gesamte Datei in den Arbeitsspeicher geladen ersten


Der Schlüssel ist, dass Python unterstützt natürlich files as iterables Handhabung. Das bedeutet, es kann lazily ausgewertet werden, und Sie werden nie


Ich mag diese Lösung auf einmal die ganze Sache im Speicher zu halten brauchen, wenn das primäre Anliegen nicht rohe Geschwindigkeit ist, weil Sie die ersetzen Linie linenumber != VALUE mit jedem bedingten Test zum Beispiel Linien Ausfiltern, die enthalten ein bestimmtes Datum

test = lambda line : 'NOVEMBER' in line 
with open('tmp.csv','w') as tmp: 
    ... 
    if test(line): 
    ... 

In-place read-writes und memory mapped file objects (was deutlich schneller sein können) verlangen, werden deutlich mehr Buchhaltung

+0

Hmmm ... Ich habe Probleme mit Ihrer zweiten 'with' Aussage in diesem zweiten Abschnitt. Sie lesen im Wesentlichen die gesamte Datei im Speicher abzüglich einer Zeile. – Zizouz212

+0

@ Zizouz212 festen –

+0

Haben Sie eine +1 von mir :) – Zizouz212

2

Verwendung sed '2636759d' file.csv > fixedfile.csv

Als Test für eine 1.3G csv 40,001 Linie, Linie entfernen 40,000 diese Weise 0m35.710s nimmt. Die Eingeweide der Python-Lösung von @en_Knight (einfach die Zeile entfernen und in eine temporäre Datei schreiben) sind ~ 2 Sekunden schneller für die gleiche Datei.

bearbeiten OK sed (oder einige Implementierungen) möglicherweise nicht (basierend auf dem Feedback von Frages)

Man könnte im Klar schlag, Zeile n aus einer Datei von N Zeilen zu entfernen, file.csv, können Sie do head -[n-1] file.csv > file_fixed.csv und tail -[N-n] file.csv >> file_fixed.csv (in beiden wird der Ausdruck in Klammern durch eine einfache Zahl ersetzt).

Um dies zu tun, obwohl Sie wissen müssen N. Die Python-Lösung ist besser ...

+0

läuft es jetzt ... – hedgedandlevered

+1

'sed: konnte nicht 35 Elemente auf stdout schreiben: Kein Platz auf dem Gerät übrig '. Dies ist auf einem Cloud-Laufwerk mit Tonnen von Speicher, so dass es etwas im Speicher tut, erscheint es – hedgedandlevered

+0

@hedgedandlevered hmm. Sind Sie sicher, dass es sich nicht um ein Speicherproblem handelt? Ich habe gerade meine obigen Tests erneut ausgeführt und sed scheint Streaming zu verwenden - die Speicherbelegung wurde nie über 600kb erreicht! viele Festplatten-I/O obwohl – jaimedash

1

Sie können dies auch in R um eine Zeile zu einem Zeitpunkt mit readLines Lesen und Schreiben jeder Zeile mit einer Ausnahme mit writeLines

Für eine Lösung ähnlich der in python:

con <- file('test.csv', 'r') 
out_con <- file('tmp.csv', 'w') 
bad_line <- 2636759 
ctr <- 1 
while (length(line <- readLines(con, n=1, warn=FALSE)) > 0){ 
    if (ctr != bad_line) 
    writeLines(line, out_con) 
    ctr <- ctr + 1 
} 

aber beachten Sie, das ist VIEL langsamer als Python (dauert ~ 3m40s auf der 40.000 Zeile Datei, wo sed 30s dauerte). Möglicherweise würde die Brockengröße n die Dinge beschleunigen, aber sed oder python scheinen viel einfacher.

Verwandte Themen