Jak zignorować pierwszą linię danych podczas przetwarzania danych CSV?

113

Proszę Pythona o wydrukowanie minimalnej liczby z kolumny danych CSV, ale górny wiersz to numer kolumny i nie chcę, aby Python wziął pod uwagę górny wiersz. Jak mogę się upewnić, że Python ignoruje pierwszą linię?

To jest dotychczasowy kod:

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

Czy mógłbyś również wyjaśnić, co robisz, a nie tylko podać kod? Jestem bardzo nowy w Pythonie i chciałbym się upewnić, że wszystko rozumiem.

martineau
źródło
5
Czy zdajesz sobie sprawę, że po prostu tworzysz generator, który zwraca wartość 1.0dla każdej linii w pliku, a następnie pobiera minimum, które będzie 1.0?
Wooble,
@Wooble Technicznie rzecz biorąc, jest to duży generator 1.0. :)
Dougal,
@Wooble dobry chwyt - ... datatype(row[column]... jest to, co chyba próbuje osiągnąć OP
Jon Clements
Ktoś napisał dla mnie ten kod i tego nie złapałem, więc dzięki haha!

Odpowiedzi:

106

Możesz użyć instancji klasy csvmodułu, Snifferaby wydedukować format pliku CSV i wykryć, czy wiersz nagłówka jest obecny wraz z wbudowaną next()funkcją, aby pominąć pierwszy wiersz tylko wtedy, gdy jest to konieczne:

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)

Ponieważ w twoim przykładzie datatypei columnsą zakodowane na stałe, nieco szybciej byłoby przetworzyć w rowten sposób:

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

Uwaga: powyższy kod dotyczy Pythona 3.x. W przypadku Python 2.x użyj następującego wiersza, aby otworzyć plik zamiast tego, co jest pokazane:

with open('all16.csv', 'rb') as file:
martineau
źródło
2
Czy zamiast tego has_header(file.read(1024))warto pisać has_header(file.readline())? Widzę to często, ale nie rozumiem, jak has_reader()można wykryć, czy istnieje nagłówek z pojedynczej linii pliku CSV ...
Anto
1
@Anto: Kod w mojej odpowiedzi jest oparty na „przykładzie użycia Sniffera” w dokumentacji , więc zakładam, że jest to zalecany sposób. Zgadzam się, że zrobienie tego na podstawie jednej linii danych nie wydaje się być wystarczającą ilością danych, aby dokonać takiego ustalenia - ale nie mam pojęcia, ponieważ nie opisano tego, jakSniffer prace. FWIW, którego nigdy nie widziałem has_header(file.readline()), a nawet gdyby działało przez większość czasu, byłbym bardzo podejrzliwy wobec tego podejścia z podanych powodów.
martineau
Dzięki za wkład. Niemniej jednak wydaje się, że za pomocą file.read(1024) generuje błędy w Pythona csv lib . Zobacz też na przykład tutaj .
Anto
@Anto: Nigdy nie spotkałem się z takim błędem - w końcu 1024 bajty to niewiele pamięci - ani też nie stanowiło to problemu dla wielu innych osób na podstawie głosów pozytywnych, które otrzymała ta odpowiedź (a także tysiące osób, które przeczytały i zastosowały się do dokumentacji). Z tych powodów mocno podejrzewam, że problem powoduje coś innego.
martineau
Natrafiłem na dokładnie ten sam błąd, gdy tylko przełączyłem się z readline()na read(1024). Do tej pory udało mi się znaleźć tylko osoby, które przeszły na readline, aby rozwiązać problem z csv.dialect.
Anto
75

Aby pominąć pierwszą linię, po prostu zadzwoń:

next(inf)

Pliki w Pythonie są iteratorami po wierszach.

jfs
źródło
22

W podobnym przypadku musiałem pominąć irytujące wiersze przed wierszem z rzeczywistymi nazwami kolumn. To rozwiązanie działało ładnie. Przeczytaj najpierw plik, a następnie przekaż listę do 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
źródło
Dzięki, Veedrac. Chętnie się tutaj dowiesz. Czy możesz zasugerować zmiany, które rozwiązałyby przytaczane przez Ciebie problemy? Moje rozwiązanie spełnia swoje zadanie, ale wygląda na to, że można je jeszcze ulepszyć?
Maarten
1
Dałem ci edycję, która zastępuje kod czymś, co powinno być identyczne (nieprzetestowane). Możesz je cofnąć, jeśli nie jest to zgodne z tym, co masz na myśli. Nadal nie jestem pewien, dlaczego tworzysz datasłownik, ani ta odpowiedź tak naprawdę nie dodaje niczego ponad zaakceptowany.
Veedrac
Dzięki, Veedrac! Wygląda to rzeczywiście bardzo wydajnie. Opublikowałem swoją odpowiedź, ponieważ zaakceptowana odpowiedź nie działała dla mnie (nie pamiętam teraz przyczyny). Jaki byłby problem ze zdefiniowaniem data = dict (), a następnie natychmiastowym wypełnieniem go (w porównaniu z twoją sugestią)?
Maarten
1
Nie jest źle robić data = dict()i wypełniać to, ale jest to nieefektywne i nie idiomatyczne. Ponadto należy używać literałów dict ( {}), a enumeratenawet wtedy.
Veedrac
1
FWIW, powinieneś odpowiadać na moje posty, @Veedracjeśli chcesz mieć pewność, że otrzymałem powiadomienie, chociaż Stack Overflow wydaje się być w stanie odgadnąć na podstawie nazwy użytkownika. (Nie piszę, @Maartenponieważ osoba odpowiadająca zostanie powiadomiona domyślnie.)
Veedrac
21

Zapożyczony z książki kucharskiej Pythona ,
bardziej zwięzły kod szablonu może wyglądać następująco:

import csv
with open('stocks.csv') as f:
    f_csv = csv.reader(f) 
    headers = next(f_csv) 
    for row in f_csv:
        # Process row ...
piszczel
źródło
19

Normalnie użyłbyś, next(incsv)który przesuwa iterator o jeden wiersz do przodu, więc pomijasz nagłówek. Drugi (powiedzmy, że chcesz pominąć 30 wierszy) to:

from itertools import islice
for row in islice(incsv, 30, None):
    # process
Jon Clements
źródło
6

użyj csv.DictReader zamiast csv.Reader. Jeśli parametr fieldnames zostanie pominięty, wartości w pierwszym wierszu pliku csv zostaną użyte jako nazwy pól. wtedy możesz uzyskać dostęp do wartości pól za pomocą wiersza ["1"] itp

iruvar
źródło
2

Nowy pakiet „pandy” może być bardziej odpowiedni niż „csv”. Poniższy kod odczyta plik CSV, domyślnie interpretując pierwszą linię jako nagłówek kolumny i znajdując minimum między kolumnami.

import pandas as pd

data = pd.read_csv('all16.csv')
data.min()
Finn Årup Nielsen
źródło
i możesz to również zapisać w jednej linii:pd.read_csv('all16.csv').min()
Finn Årup Nielsen
1

Cóż, moja mini biblioteka z opakowaniami również się nada.

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

W międzyczasie, jeśli wiesz, jaki jest indeks kolumny nagłówka, na przykład „Kolumna 1”, możesz zamiast tego zrobić to:

>>> min(data.column["Column 1"])
chfw
źródło
1

Dla mnie najłatwiejszym sposobem jest użycie zasięgu.

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
źródło
1

Ponieważ jest to związane z czymś, co robiłem, podzielę się tutaj.

Co jeśli nie jesteśmy pewni, czy istnieje nagłówek, a Ty też nie masz ochoty importować sniffera i innych rzeczy?

Jeśli twoje zadanie jest podstawowe, takie jak drukowanie lub dołączanie do listy lub tablicy, możesz po prostu użyć instrukcji if:

# 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.
źródło
1

Dokumentacji modułu Python 3 CSV zapewnia ten przykład:

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 ...

SnifferSpróbuje auto-wykrywanie wielu rzeczy o pliku CSV. Musisz jawnie wywołać jego has_header()metodę, aby określić, czy plik ma wiersz nagłówka. Jeśli tak, pomiń pierwszy wiersz podczas iteracji wierszy CSV. Możesz to zrobić w ten sposób:

if sniffer.has_header():
    for header_row in reader:
        break
for data_row in reader:
    # do something with the row
Lassi
źródło
0

Użyłbym taila, aby pozbyć się niechcianej pierwszej linii:

tail -n +2 $INFIL | whatever_script.py 
Karel Adams
źródło
0

po prostu dodaj [1:]

przykład poniżej:

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

to działa dla mnie w iPythonie

ciekawy umysł
źródło
0

Python 3.X

Obsługuje UTF8 BOM + HEADER

To było dość frustrujące, że csvmoduł nie mógł łatwo uzyskać nagłówka, jest też błąd w BOM UTF-8 (pierwszy znak w pliku). To działa dla mnie używając tylko csvmodułu:

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
źródło
0

Przekonwertowałbym csvreader na listę, a następnie wrzuciłbym pierwszy element

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
źródło
0

Python 2.x

csvreader.next()

Zwraca następny wiersz iterowalnego obiektu czytnika jako listę, przeanalizowaną zgodnie z bieżącym dialektem.

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__()

Zwraca następny wiersz iterowalnego obiektu czytnika jako listę (jeśli obiekt został zwrócony z reader ()) lub dict (jeśli jest to instancja DictReader), przeanalizowaną zgodnie z bieżącym dialektem. Zwykle powinieneś nazywać to jako następny (czytelnik).

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
źródło