2017-08-14 3 views
0

Ich habe eine Reihe von sehr chaotisch * .csv-Dateien, die von Pandas eingelesen werden. Ein Beispiel csv ist:Ignorieren schlechte Zeilen von Daten in pandas.read_csv(), die Kopfzeile brechen = Stichwort

Instrument 35392 
"Log File Name : station" 
"Setup Date (MMDDYY) : 031114" 
"Setup Time (HHMMSS) : 073648" 
"Starting Date (MMDDYY) : 031114" 
"Starting Time (HHMMSS) : 090000" 
"Stopping Date (MMDDYY) : 031115" 
"Stopping Time (HHMMSS) : 235959" 
"Interval (HHMMSS) : 010000" 
"Sensor warmup (HHMMSS) : 000200" 
"Circltr warmup (HHMMSS) : 000200" 


"Date","Time","","Temp","","SpCond","","Sal","","IBatt","" 
"MMDDYY","HHMMSS","","øC","","mS/cm","","ppt","","Volts","" 

"Random message here 031114 073721 to 031114 083200" 
03/11/14,09:00:00,"",15.85,"",1.408,"",.74,"",6.2,"" 
03/11/14,10:00:00,"",15.99,"",1.96,"",1.05,"",6.3,"" 
03/11/14,11:00:00,"",14.2,"",40.8,"",26.12,"",6.2,"" 
03/11/14,12:00:01,"",14.2,"",41.7,"",26.77,"",6.2,"" 
03/11/14,13:00:00,"",14.5,"",41.3,"",26.52,"",6.2,"" 
03/11/14,14:00:00,"",14.96,"",41,"",26.29,"",6.2,"" 
"message 3" 
"message 4"** 

Ich habe diesen Code wurde mit der * .csv-Datei, verarbeiten die doppelten Header, ziehen Sie die leeren Spalten importieren und dann mit schlechten Daten, die beanstandeten Zeilen Streifen:

DF = pd.read_csv(BADFILE,parse_dates={'Datetime_(ascii)': [0,1]}, sep=",", \ 
      header=[10,11],na_values=['','na', 'nan nan'], \ 
      skiprows=[10], encoding='cp1252') 

DF = DF.dropna(how="all", axis=1) 
DF = DF.dropna(thresh=2) 
droplist = ['message', 'Random'] 
DF = DF[~DF['Datetime_(ascii)'].str.contains('|'.join(droplist))] 

DF.head() 

Datetime_(ascii) (Temp, øC) (SpCond, mS/cm) (Sal, ppt) (IBatt, Volts) 
0 03/11/14 09:00:00 15.85 1.408 0.74 6.2 
1 03/11/14 10:00:00 15.99 1.960 1.05 6.3 
2 03/11/14 11:00:00 14.20 40.800 26.12 6.2 
3 03/11/14 12:00:01 14.20 41.700 26.77 6.2 
4 03/11/14 13:00:00 14.50 41.300 26.52 6.2 

Dies funktioniert gut und schön, bis ich eine Datei, die eine erronious 1 Zeilenleitung nach dem Header hat: „Random Nachricht hier 031.114 073.721 bis 031.114 083.200“

der Fehler I ist receieve:

*C:\Users\USER\AppData\Local\Continuum\Anaconda3\lib\site- 
    packages\pandas\io\parsers.py in _do_date_conversions(self, names, data) 
    1554    data, names = _process_date_conversion(
    1555     data, self._date_conv, self.parse_dates, self.index_col, 
    -> 1556     self.index_names, names, 
    keep_date_col=self.keep_date_col) 
    1557 
    1558   return names, data 
    C:\Users\USER\AppData\Local\Continuum\Anaconda3\lib\site- 
    packages\pandas\io\parsers.py in _process_date_conversion(data_dict, 
    converter, parse_spec, index_col, index_names, columns, keep_date_col) 
    2975  if not keep_date_col: 
    2976   for c in list(date_cols): 
    -> 2977    data_dict.pop(c) 
    2978    new_cols.remove(c) 
    2979 
    KeyError: ('Time', 'HHMMSS')* 

Wenn ich diese Zeile entfernen, funktioniert der Code einwandfrei. Ähnlich, wenn ich die header = Zeile entferne, funktioniert der Code gut. Ich möchte dies jedoch beibehalten können, weil ich Hunderte von diesen Dateien lese.

Schwierigkeit: Ich würde nicht jede Datei vor dem Aufruf an pandas.read_csv() öffnen, da diese Dateien ziemlich groß sein können - also möchte ich nicht mehrere Male lesen und speichern! Außerdem würde ich eine echte Pandas/Python-Lösung bevorzugen, bei der die Datei nicht zuerst als StringIO-Puffer geöffnet wird, um störende Zeilen zu entfernen.

+0

Können Sie die fehlerhafte Zeile schreiben? Ist es die gleiche Art von fehlerhafter Zeile, die in jedem Fall angezeigt wird, wenn Sie einen Fehler erhalten, oder gibt es andere Arten von Problemen in anderen Zeilen in einigen Dateien? –

+0

die fehlerhafte Zeile, die den Fehler erstellt, ist: "zufällige Nachricht hier 031114 073721 bis 031114 083200" Diese Zeile möglicherweise oder möglicherweise nicht in allen Dateien vorhanden. Daher kann ich nicht nur den Index skiprows = erhöhen. Auch wenn ich den tatsächlichen Text dieser Zeile ändern, bleibt der Fehler bestehen - es ist egal, was der Text ist, aber das ist eine Zeile mit nur 1 Spalte nach der Überschrift. –

Antwort

1

Hier ist ein Ansatz, der die Tatsache nutzt, dass skip_rows eine aufrufbare Funktion akzeptiert. Die Funktion empfängt nur den Zeilenindex, der berücksichtigt wird. Dies ist eine integrierte Einschränkung dieses Parameters.

Als solche prüft die aufrufbare Funktion skip_test() zuerst, ob der aktuelle Index in der Menge der zu überspringenden Indizes ist. Wenn nicht, dann öffnet es die tatsächliche Datei und überprüft die entsprechende Zeile, um zu sehen, ob ihr Inhalt übereinstimmt.

Die skip_test() Funktion ist ein wenig hacky in dem Sinne, dass es die tatsächliche Datei inspiziert, obwohl es nur inspiziert, bis der aktuelle Zeilenindex ausgewertet wird. Es wird auch angenommen, dass die fehlerhafte Zeile immer mit der gleichen Zeichenfolge beginnt (im Beispielfall "foo"), aber das scheint eine sichere Annahme zu sein, wenn OP gegeben wird.

# example data 
""" foo.csv 
uid,a,b,c 
0,1,2,3 
skip me 
1,11,22,33 
foo 
2,111,222,333 
""" 

import pandas as pd 

def skip_test(r, fn, fail_on, known): 
    if r in known: # we know we always want to skip these 
     return True 
    # check if row index matches problem line in file 
    # for efficiency, quit after we pass row index in file 
    f = open(fn, "r") 
    data = f.read() 
    for i, line in enumerate(data.splitlines()): 
     if (i == r) & line.startswith(fail_on): 
      return True 
     elif i > r: 
      break 
    return False 

fname = "foo.csv" 
fail_str = "foo" 
known_skip = [2] 
pd.read_csv(fname, sep=",", header=0, 
      skiprows=lambda x: skip_test(x, fname, fail_str, known_skip)) 
# output 
    uid a b c 
0 0 1 2 3 
1 1 11 22 33 
2 2 111 222 333 

Wenn Sie genau wissen, welche die zufällige Meldung Zeile wird auf angezeigt werden, wenn es angezeigt wird, dann wird dies viel schneller, als man es einfach nicht sagen kann, den Inhalt der Datei für jeden Index über die mögliche Straftaten zu inspizieren Linie.

+0

Danke! Ja, ich weiß, welche Meldungen beim Durchgehen meiner Dateien angezeigt werden, damit ich sie analysieren kann. –

+0

Gern geschehen! –

0

Nach etwas Basteln gestern fand ich eine Lösung und was das mögliche Problem sein könnte.

Ich versuchte, die skip_test() Funktion Antwort oben, aber ich war immer noch Fehler mit der Größe der Tisch zu bekommen:

pandas\_libs\parsers.pyx in pandas._libs.parsers.TextReader.read (pandas\_libs\parsers.c:10862)() 

pandas\_libs\parsers.pyx in pandas._libs.parsers.TextReader._read_low_memory (pandas\_libs\parsers.c:11138)() 

pandas\_libs\parsers.pyx in pandas._libs.parsers.TextReader._read_rows (pandas\_libs\parsers.c:11884)() 

pandas\_libs\parsers.pyx in pandas._libs.parsers.TextReader._tokenize_rows (pandas\_libs\parsers.c:11755)() 

pandas\_libs\parsers.pyx in pandas._libs.parsers.raise_parser_error (pandas\_libs\parsers.c:28765)() 

ParserError: Error tokenizing data. C error: Expected 1 fields in line 14, saw 11 

So, nachdem das Spiel mit skiprows = ich, dass ich entdeckte, war nur nicht das Verhalten, das ich wollte, wenn Sie die engine = 'c'. read_csv() bestimmte immer noch die Größe der Datei aus diesen ersten Zeilen, und einige dieser einzelnen Spaltenzeilen wurden noch übergeben. Es kann sein, dass ich in meinem CSV-Set noch ein paar schlechtere Spaltenzeilen habe, die ich nicht geplant habe.

Stattdessen erstelle ich einen beliebig großen Datenrahmen als Vorlage. Ich ziehe die gesamte Datei .csv, dann verwenden Sie die Logik, um die NaN Zeilen zu entfernen.

Zum Beispiel weiß ich, dass die größte Tabelle, die ich mit meinen Daten begegnen werde 10 Zeilen lang sein wird. Also mein Aufruf an Pandas ist:

DF = pd.read_csv(csv_file, sep=',', \ 
    parse_dates={'Datetime_(ascii)': [0,1]},\ 
    na_values=['','na', '999999', '#'], engine='c',\ 
    encoding='cp1252', names = list(range(0,10))) 

ich dann diese beiden Zeilen verwenden, um die NaN Zeilen und Spalten aus dem Datenrahmen fallen zu lassen:

#drop the null columns created by double deliminators 
DF = DF.dropna(how="all", axis=1) 
DF = DF.dropna(thresh=2) # drop if we don't have at least 2 cells with real values 
Verwandte Themen