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.


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:

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.


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

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

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

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


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

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"])

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])  

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)

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

0

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

tail -n +2 $INFIL | whatever_script.py 

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


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]

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)

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.