Pandas Datenrahmen read_csv bei fehlerhaften Daten

73

Ich möchte eine sehr große CSV-Datei einlesen (kann nicht einfach in Excel geöffnet und bearbeitet werden), aber irgendwo in der 100.000sten Zeile gibt es eine Zeile mit einer zusätzlichen Spalte, die zum Absturz des Programms führt. Diese Zeile ist fehlerhaft, daher muss ich die Tatsache ignorieren, dass es sich um eine zusätzliche Spalte handelt. Es gibt ungefähr 50 Spalten, daher ist es nicht vorzuziehen, die Header fest zu codieren und Namen oder Usecols zu verwenden. Ich werde dieses Problem möglicherweise auch in anderen CSVs finden und möchte eine generische Lösung. Ich konnte leider nichts in read_csv finden. Der Code ist so einfach:

def loadCSV(filePath):
    dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1', nrows=1000)
    datakeys = dataframe.keys();
    return dataframe, datakeys
Fonti
quelle
2
Zusätzlich zu den oben genannten kann die Verwendung warn_bad_lines=Trueweiter helfen, die problematischen Zeilen zu diagnostizieren.
Herpes Free Engineer

Antworten:

106

Übergeben error_bad_lines=False, um fehlerhafte Zeilen zu überspringen:

error_bad_lines: Boolesche, standardmäßige True Lines mit zu vielen Feldern (z. B. eine CSV-Zeile mit zu vielen Kommas) führen standardmäßig dazu, dass eine Ausnahme ausgelöst wird und kein DataFrame zurückgegeben wird. Wenn False, werden diese "fehlerhaften Zeilen" aus dem zurückgegebenen DataFrame entfernt. (Nur gültig mit C-Parser)

EdChum
quelle
Ich habe vergessen, das zu erwähnen. Es wird für das funktionieren, was ich gerade tun möchte, aber später werde ich die Zeile nur ohne den zusätzlichen Mehrwert wollen.
Fonti
8
Eine Alternative besteht darin, eine einzelne Zeile zu lesen, um die richtige Anzahl von Spalten zu erhalten, und dann erneut zu lesen, um nur diese Spalten zu lesen. cols = pd.read_csv(file, nrows=1).columns df = pd.read_csv(file, usecols=cols)Dies ignoriert dann die zusätzliche Spalte, die ich für diese Fehlerzeile denke. Versuchen Sie das und lassen Sie mich wissen, ob sie funktioniert Sie
EdChum
2
@Fonti: Es gibt keine Option für truncate_bad_lines. Dies wäre eine schlechte Praxis. Sie gehen davon aus, dass Sie im Voraus wissen, warum die Daten fehlerhaft sind (an sie wurde ein zusätzlicher Wert angehängt). Aber was ist, wenn es zu wenige Spalten hat? Was ist, wenn der zusätzliche Wert eingefügt und nicht angehängt wurde? So etwas zu tun ist ein Insektenmagnet.
Steven Rumbalski
2
Eigentlich habe ich es gerade versucht und es wird nicht funktionieren. Ich denke, Sie müssen error_bad_lines=Falsedie Warnungen weitergeben und analysieren, um die Zeilennummern zu erhalten und nur diese Zeilen mitheader=None
EdChum
@ Edchum Das ist seltsam, ich denke es hat bei mir funktioniert. Anstatt einen Fehler in dieser Zeile zu bekommen, bekam ich einen Speicherfehler (4 Millionen + Zeilen). Ein ganz anderer Fisch zum Anpacken.
Fonti
5

Um Informationen über fehlerverursachende Zeilen zu erhalten, verwenden Sie die Kombination aus error_bad_lines=Falseund warn_bad_lines=True:

dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1', nrows=1000,
                        warn_bad_lines=True, error_bad_lines=False)

error_bad_lines=FalseÜberspringt fehlerverursachende Zeilen und warn_bad_lines=Truedruckt Fehlerdetails und Zeilennummer wie folgt:

'Skipping line 3: expected 4 fields, saw 3401\nSkipping line 4: expected 4 fields, saw 30...'

Wenn Sie die Warnmeldung speichern möchten (dh für eine weitere Verarbeitung), können Sie sie auch in einer Datei speichern (unter Verwendung von contextlib):

import contextlib

with open(r'D:\Temp\log.txt', 'w') as log:
    with contextlib.redirect_stderr(log):
        dataframe = pd.read_csv(filePath, index_col=False, encoding='iso-8859-1', 
                                warn_bad_lines=True, error_bad_lines=False)
Lukas
quelle
0

Hier ist mein Weg, um dieses Problem zu lösen. Es ist langsam, funktioniert aber so gut. Einfach gesagt, lesen Sie einfach die CSV-Datei als txt-Datei und gehen Sie jede Zeile durch. Wenn das Komma "," kleiner ist als es sein sollte, überspringen Sie einfach diese Zeile. Eventuell die richtigen Leitungen sichern.

def bad_lines(path):
    import itertools
    num_columns = []
    lines = ""
    
    for i in range(10,50,5):
        content = open(path).readlines(i)[0]
        if (content.count("'") == 0) and (content.count('"') == 0):
            num_columns.append(content.count(","))

    if len(set(num_columns)) == 1:
        for line in itertools.islice(open(path), 0, None):
            if line.count(",") >= num_columns[0]:
                lines = lines + line

    text_file = open("temp.txt", "w")
    n = text_file.write(lines)
    text_file.close()
    
    return("temp.txt")
Sway Wu
quelle