Wie ignoriere ich die erste Datenzeile bei der Verarbeitung von CSV-Daten?

112

Ich fordere Python auf, die Mindestanzahl aus einer Spalte mit CSV-Daten zu drucken, aber die oberste Zeile ist die Spaltennummer, und ich möchte nicht, dass Python die oberste Zeile berücksichtigt. Wie kann ich sicherstellen, dass Python die erste Zeile ignoriert?

Dies ist der bisherige Code:

import csv

with open('all16.csv', 'rb') as inf:
    incsv = csv.reader(inf)
    column = 1                
    datatype = float          
    data = (datatype(column) for row in incsv)   
    least_value = min(data)

print least_value

Können Sie auch erklären, was Sie tun, und nicht nur den Code angeben? Ich bin sehr, sehr neu in Python und möchte sicherstellen, dass ich alles verstehe.

Martineau
quelle
5
Ist Ihnen bewusst, dass Sie nur einen Generator erstellen, der 1.0für jede Zeile in Ihrer Datei ein a zurückgibt und dann das Minimum nimmt, das sein wird 1.0?
Wooble
@Wooble Technisch gesehen ist es ein großer Generator von 1.0. :)
Dougal
@Wooble guter Fang - ... datatype(row[column]... ist das, was das OP allerdings zu erreichen versucht
Jon Clements
Ich hatte jemanden, der diesen Code für mich schrieb und ihn nicht verstand, also danke haha!

Antworten:

104

Sie können eine Instanz der csvModulklasse verwenden Sniffer, um das Format einer CSV-Datei abzuleiten und festzustellen, ob eine Kopfzeile vorhanden ist, sowie die integrierte next()Funktion, um die erste Zeile nur bei Bedarf zu überspringen:

import csv

with open('all16.csv', 'r', newline='') as file:
    has_header = csv.Sniffer().has_header(file.read(1024))
    file.seek(0)  # Rewind.
    reader = csv.reader(file)
    if has_header:
        next(reader)  # Skip header row.
    column = 1
    datatype = float
    data = (datatype(row[column]) for row in reader)
    least_value = min(data)

print(least_value)

Da datatypeund columnin Ihrem Beispiel fest codiert sind, wäre es etwas schneller, Folgendes zu verarbeiten row:

    data = (float(row[1]) for row in reader)

Hinweis: Der obige Code gilt für Python 3.x. Verwenden Sie für Python 2.x die folgende Zeile, um die Datei anstelle der angezeigten zu öffnen:

with open('all16.csv', 'rb') as file:
Martineau
quelle
2
Ist has_header(file.read(1024))es sinnvoll, stattdessen zu schreiben has_header(file.readline())? Ich sehe das sehr oft, aber ich verstehe nicht, wie ich has_reader()feststellen kann, ob es einen Header aus einer einzelnen Zeile der CSV-Datei gibt oder nicht ...
Anto
1
@Anto: Der Code in meiner Antwort basiert auf dem "Beispiel für die Verwendung von Sniffer" in der Dokumentation , daher gehe ich davon aus, dass dies die vorgeschriebene Methode ist. Ich bin damit einverstanden , dass es auf der Grundlage einer Zeile von Daten scheint nicht zu tun , wie es immer genügend Daten , eine solche Bestimmung aber zu machen sein würde , ich habe keine Ahnung , da , wie die SnifferArbeiten nicht beschrieben. FWIW Ich habe noch nie gesehen, has_header(file.readline())dass es verwendet wird, und selbst wenn es die meiste Zeit funktioniert hätte, wäre ich aus den genannten Gründen sehr misstrauisch gegenüber dem Ansatz.
Martineau
Danke für deinen Beitrag. Trotzdem scheint die Verwendung von file.read(1024) Fehlern in der csv lib von Python zu generieren :. Siehe auch hier zum Beispiel.
Anto
@Anto: Ich bin noch nie auf einen solchen Fehler gestoßen - 1024 Bytes sind schließlich nicht viel Speicher - und es war auch kein Problem für viele andere Leute, basierend auf den Up-Votes, die diese Antwort erhalten hat (sowie den Tausenden von von Personen, die die Dokumentation gelesen und befolgt haben). Aus diesen Gründen vermute ich stark, dass etwas anderes Ihr Problem verursacht.
Martineau
Ich bin genau auf diesen Fehler gestoßen, sobald ich von readline()zu gewechselt bin read(1024). Bisher habe ich nur Leute gefunden, die zu readline gewechselt sind, um das Problem mit csv.dialect zu lösen.
Anto
75

Um die erste Zeile zu überspringen, rufen Sie einfach an:

next(inf)

Dateien in Python sind Iteratoren über Zeilen.

jfs
quelle
21

In einem ähnlichen Anwendungsfall musste ich nervige Zeilen vor der Zeile mit meinen tatsächlichen Spaltennamen überspringen. Diese Lösung hat gut funktioniert. Lesen Sie zuerst die Datei und übergeben Sie die Liste an csv.DictReader.

with open('all16.csv') as tmp:
    # Skip first line (if any)
    next(tmp, None)

    # {line_num: row}
    data = dict(enumerate(csv.DictReader(tmp)))
Maarten
quelle
Danke Veedrac. Können Sie hier Änderungen vorschlagen, mit denen Sie die von Ihnen genannten Probleme lösen können? Meine Lösung erledigt den Job, aber es sieht so aus, als könnte sie weiter verbessert werden?
Maarten
1
Ich habe Ihnen eine Bearbeitung gegeben, die den Code durch etwas ersetzt, das identisch sein sollte (ungetestet). Fühlen Sie sich frei, zurückzukehren, wenn es nicht mit dem übereinstimmt, was Sie meinen. Ich bin mir immer noch nicht sicher, warum Sie das dataWörterbuch erstellen, und diese Antwort fügt auch nichts über das akzeptierte hinzu.
Veedrac
Danke Veedrac! Das sieht in der Tat sehr effizient aus. Ich habe meine Antwort gepostet, weil die akzeptierte nicht für mich funktioniert hat (ich kann mich jetzt nicht an den Grund erinnern). Was wäre das Problem, wenn Sie data = dict () definieren und dann sofort füllen würden (im Vergleich zu Ihrem Vorschlag)?
Maarten
1
Es ist nicht falsch, es zu tun data = dict()und auszufüllen, aber es ist ineffizient und nicht idiomatisch. Außerdem sollte man dikt Literale ( {}) verwenden und enumerateauch dann.
Veedrac
1
FWIW, Sie sollten auf meine Beiträge mit antworten, @Veedracwenn Sie sicher sein möchten, dass ich benachrichtigt werde, obwohl Stack Overflow den Benutzernamen zu erraten scheint. (Ich schreibe nicht, @Maartenweil der Antwortende standardmäßig benachrichtigt wird.)
Veedrac
21

Aus dem Python-Kochbuch entlehnt , könnte
ein prägnanterer Vorlagencode folgendermaßen aussehen:

import csv
with open('stocks.csv') as f:
    f_csv = csv.reader(f) 
    headers = next(f_csv) 
    for row in f_csv:
        # Process row ...
Schienbein
quelle
19

Normalerweise wird verwendet, next(incsv)wodurch der Iterator um eine Zeile vorgerückt wird, sodass Sie den Header überspringen. Die andere (sagen wir, Sie wollten 30 Zeilen überspringen) wäre:

from itertools import islice
for row in islice(incsv, 30, None):
    # process
Jon Clements
quelle
6

Verwenden Sie csv.DictReader anstelle von csv.Reader. Wenn der Parameter Feldnamen weggelassen wird, werden die Werte in der ersten Zeile der CSV-Datei als Feldnamen verwendet. Sie können dann mit Zeile ["1"] usw. auf Feldwerte zugreifen

iruvar
quelle
2

Das neue 'Pandas'-Paket ist möglicherweise relevanter als' csv '. Der folgende Code liest eine CSV-Datei, interpretiert standardmäßig die erste Zeile als Spaltenüberschrift und ermittelt das Minimum über Spalten hinweg.

import pandas as pd

data = pd.read_csv('all16.csv')
data.min()
Finn Årup Nielsen
quelle
und Sie können es auch in einer Zeile schreiben:pd.read_csv('all16.csv').min()
Finn Årup Nielsen
1

Nun, meine Mini-Wrapper-Bibliothek würde den Job auch machen.

>>> import pyexcel as pe
>>> data = pe.load('all16.csv', name_columns_by_row=0)
>>> min(data.column[1])

Wenn Sie wissen, um welchen Header-Spaltenindex es sich handelt, z. B. "Spalte 1", können Sie dies stattdessen tun:

>>> min(data.column["Column 1"])
chfw
quelle
1

Für mich ist es am einfachsten, die Reichweite zu nutzen.

import csv

with open('files/filename.csv') as I:
    reader = csv.reader(I)
    fulllist = list(reader)

# Starting with data skipping header
for item in range(1, len(fulllist)): 
    # Print each row using "item" as the index value
    print (fulllist[item])  
Clint Hart
quelle
1

Da dies mit etwas zusammenhängt, das ich getan habe, werde ich es hier teilen.

Was ist, wenn wir nicht sicher sind, ob es einen Header gibt und Sie auch keine Lust haben, Sniffer und andere Dinge zu importieren?

Wenn Ihre Aufgabe grundlegend ist, z. B. Drucken oder Anhängen an eine Liste oder ein Array, können Sie einfach eine if-Anweisung verwenden:

# Let's say there's 4 columns
with open('file.csv') as csvfile:
     csvreader = csv.reader(csvfile)
# read first line
     first_line = next(csvreader)
# My headers were just text. You can use any suitable conditional here
     if len(first_line) == 4:
          array.append(first_line)
# Now we'll just iterate over everything else as usual:
     for row in csvreader:
          array.append(row)
Roy W.
quelle
1

Die Dokumentation zum Python 3 CSV-Modul enthält dieses Beispiel:

with open('example.csv', newline='') as csvfile:
    dialect = csv.Sniffer().sniff(csvfile.read(1024))
    csvfile.seek(0)
    reader = csv.reader(csvfile, dialect)
    # ... process CSV file contents here ...

Der Snifferwird versuchen, viele Dinge über die CSV-Datei automatisch zu erkennen. Sie müssen die has_header()Methode explizit aufrufen , um festzustellen, ob die Datei eine Kopfzeile enthält. Wenn dies der Fall ist, überspringen Sie die erste Zeile, wenn Sie die CSV-Zeilen durchlaufen. Sie können es so machen:

if sniffer.has_header():
    for header_row in reader:
        break
for data_row in reader:
    # do something with the row
Lassi
quelle
0

Ich würde Schwanz verwenden , um die unerwünschte erste Zeile loszuwerden:

tail -n +2 $INFIL | whatever_script.py 
Karel Adams
quelle
0

füge einfach [1:] hinzu

Beispiel unten:

data = pd.read_csv("/Users/xyz/Desktop/xyxData/xyz.csv", sep=',', header=None)**[1:]**

das funktioniert bei mir in iPython

der neugierige Geist
quelle
0

Python 3.X.

Behandelt UTF8 BOM + HEADER

Es war ziemlich frustrierend, dass das csvModul den Header nicht leicht bekommen konnte, es gibt auch einen Fehler mit der UTF-8-Stückliste (erstes Zeichen in der Datei). Dies funktioniert bei mir nur mit dem csvModul:

import csv

def read_csv(self, csv_path, delimiter):
    with open(csv_path, newline='', encoding='utf-8') as f:
        # https://bugs.python.org/issue7185
        # Remove UTF8 BOM.
        txt = f.read()[1:]

    # Remove header line.
    header = txt.splitlines()[:1]
    lines = txt.splitlines()[1:]

    # Convert to list.
    csv_rows = list(csv.reader(lines, delimiter=delimiter))

    for row in csv_rows:
        value = row[INDEX_HERE]
Christophe Roussy
quelle
0

Ich würde csvreader in list konvertieren und dann das erste Element einfügen

import csv        

with open(fileName, 'r') as csvfile:
        csvreader = csv.reader(csvfile)
        data = list(csvreader)               # Convert to list
        data.pop(0)                          # Removes the first row

        for row in data:
            print(row)
Tim John
quelle
0

Python 2.x.

csvreader.next()

Geben Sie die nächste Zeile des iterierbaren Objekts des Lesers als Liste zurück, die gemäß dem aktuellen Dialekt analysiert wurde.

csv_data = csv.reader(open('sample.csv'))
csv_data.next() # skip first row
for row in csv_data:
    print(row) # should print second row

Python 3.x.

csvreader.__next__()

Geben Sie die nächste Zeile des iterierbaren Objekts des Lesers als Liste (wenn das Objekt von reader () zurückgegeben wurde) oder als Diktat (wenn es sich um eine DictReader-Instanz handelt) zurück, die gemäß dem aktuellen Dialekt analysiert wurde. Normalerweise sollten Sie dies als nächstes (Leser) bezeichnen.

csv_data = csv.reader(open('sample.csv'))
csv_data.__next__() # skip first row
for row in csv_data:
    print(row) # should print second row
Patel Romil
quelle