Come ignorare la prima riga di dati durante l'elaborazione dei dati CSV?


113

Chiedo a Python di stampare il numero minimo da una colonna di dati CSV, ma la riga superiore è il numero di colonna e non voglio che Python tenga conto della riga superiore. Come posso assicurarmi che Python ignori la prima riga?

Questo è il codice finora:

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

Potresti anche spiegare cosa stai facendo, non solo fornire il codice? Sono molto nuovo in Python e vorrei assicurarmi di aver capito tutto.


5
Sei consapevole che stai solo creando un generatore che restituisce un 1.0per ogni riga nel tuo file e quindi prendi il minimo, che sarà 1.0?
Wooble

@ Wooble Tecnicamente, è un grande generatore di 1.0. :)
Dougal

@Wooble buona cattura - ... datatype(row[column]... è quello che immagino che l'OP stia cercando di ottenere però
Jon Clements

qualcuno ha scritto quel codice per me e non l'ho capito, quindi grazie ahah!

Risposte:


106

È possibile utilizzare un'istanza della classe csvdel modulo Snifferper dedurre il formato di un file CSV e rilevare se una riga di intestazione è presente insieme alla next()funzione integrata per saltare la prima riga solo quando necessario:

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)

Poiché datatypee columnsono codificati nel tuo esempio, sarebbe leggermente più veloce elaborare in rowquesto modo:

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

Nota: il codice sopra è per Python 3.x. Per Python 2.x usa la seguente riga per aprire il file invece di quanto mostrato:

with open('all16.csv', 'rb') as file:

2
Invece di has_header(file.read(1024)), ha senso scrivere has_header(file.readline())? Lo vedo molto, ma non capisco come has_reader()possa rilevare se c'è o meno un'intestazione da una singola riga del file CSV ...
Anto

1
@Anto: Il codice nella mia risposta è basato sull '"esempio per l'uso di Sniffer" nella documentazione , quindi presumo che sia il modo prescritto per farlo. Sono d'accordo che farlo sulla base di una riga di dati non sembra che sarebbero sempre dati sufficienti per fare una tale determinazione, ma non ho idea dal momento che come i Snifferlavori non sono descritti. FWIW non ho mai visto has_header(file.readline())essere utilizzato e anche se funzionasse la maggior parte del tempo, sarei molto sospettoso dell'approccio per i motivi indicati.
martineau

Grazie per il tuo contributo. Tuttavia sembra che using file.read(1024) generi errori nella lib : csv di python . Vedi anche qui per esempio.
Anto

@Anto: non ho mai riscontrato un errore del genere - 1024 byte non è molta memoria dopotutto - né è stato un problema per molte altre persone sulla base dei voti positivi che questa risposta ha ricevuto (così come le migliaia di di persone che hanno letto e seguito la documentazione). Per questi motivi sospetto fortemente che qualcos'altro stia causando il tuo problema.
martineau

Mi sono imbattuto nello stesso identico errore non appena sono passato da readline()a read(1024). Finora sono riuscito a trovare solo persone che sono passate a readline per risolvere il problema di csv.dialect.
Anto

75

Per saltare la prima riga basta chiamare:

next(inf)

I file in Python sono iteratori su righe.


22

In un caso d'uso simile ho dovuto saltare le righe fastidiose prima della riga con i miei nomi di colonna effettivi. Questa soluzione ha funzionato bene. Leggere prima il file, quindi passare l'elenco a 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)))

Grazie Veedrac. Felice di apprendere qui, puoi suggerire modifiche che risolverebbero i problemi che citi? La mia soluzione porta a termine il lavoro, ma sembra che potrebbe essere ulteriormente migliorata?
Maarten

1
Ti ho fornito una modifica che sostituisce il codice con qualcosa che dovrebbe essere identico (non testato). Sentiti libero di tornare se non è in linea con ciò che intendi. Non sono ancora sicuro del motivo per cui stai creando il datadizionario, né questa risposta aggiunge davvero qualcosa a quella accettata.
Veedrac

Grazie Veedrac! Sembra davvero molto efficiente. Ho pubblicato la mia risposta perché quella accettata non funzionava per me (non ricordo il motivo ora). Quale sarebbe il problema nel definire data = dict () e poi riempirlo immediatamente (rispetto al tuo suggerimento)?
Maarten

1
Non è sbagliato farlo data = dict()e compilarlo, ma è inefficiente e non idiomatico. Inoltre, si dovrebbe usare dict literals ( {}) e enumerateanche allora.
Veedrac

1
FWIW, dovresti rispondere ai miei post con @Veedracse vuoi essere sicuro che riceva una notifica, anche se Stack Overflow sembra essere in grado di indovinare dal nome utente. (Non scrivo @Maartenperché chi risponde verrà avvisato per impostazione predefinita.)
Veedrac

21

Preso in prestito dal ricettario di Python ,
un codice modello più conciso potrebbe assomigliare a questo:

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

Normalmente useresti next(incsv)che fa avanzare l'iteratore di una riga, quindi salti l'intestazione. L'altro (diciamo che vuoi saltare 30 righe) sarebbe:

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

6

usa csv.DictReader invece di csv.Reader. Se il parametro fieldnames viene omesso, i valori nella prima riga del file csv verranno utilizzati come nomi di campo. sarà quindi possibile accedere ai valori dei campi utilizzando la riga ["1"] ecc


2

Il nuovo pacchetto "pandas" potrebbe essere più pertinente di "csv". Il codice seguente leggerà un file CSV, interpretando per impostazione predefinita la prima riga come intestazione di colonna e troverà il minimo tra le colonne.

import pandas as pd

data = pd.read_csv('all16.csv')
data.min()

e puoi anche scriverlo in una riga:pd.read_csv('all16.csv').min()
Finn Årup Nielsen

1

Bene, anche la mia mini libreria di wrapper farebbe il lavoro.

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

Nel frattempo, se sai qual è l'indice della colonna di intestazione uno, ad esempio "Colonna 1", puoi farlo invece:

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

1

Per me il modo più semplice è usare la portata.

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

Poiché questo è correlato a qualcosa che stavo facendo, lo condividerò qui.

E se non siamo sicuri che sia presente un'intestazione e non hai nemmeno voglia di importare sniffer e altre cose?

Se la tua attività è di base, come stampare o aggiungere a un elenco o un array, potresti semplicemente usare un'istruzione 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

La documentazione per il modulo CSV di Python 3 fornisce questo esempio:

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

Il Sniffercercherà di rilevare automaticamente molte cose sul file CSV. È necessario chiamare esplicitamente il suo has_header()metodo per determinare se il file ha una riga di intestazione. In tal caso, salta la prima riga durante l'iterazione delle righe CSV. Puoi farlo in questo modo:

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

0

Userei la coda per sbarazzarmi della prima riga indesiderata:

tail -n +2 $INFIL | whatever_script.py 

0

basta aggiungere [1:]

esempio sotto:

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

che funziona per me in iPython


0

Python 3.X

Gestisce UTF8 BOM + HEADER

Era abbastanza frustrante che il csvmodulo non potesse ottenere facilmente l'intestazione, c'è anche un bug con la distinta componenti UTF-8 (primo carattere nel file). Questo funziona per me usando solo il csvmodulo:

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

Vorrei convertire csvreader in list, quindi inserire il primo elemento

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

Restituisce la riga successiva dell'oggetto iterabile del lettore come un elenco, analizzato in base al dialetto corrente.

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

Restituisce la riga successiva dell'oggetto iterabile del lettore come un elenco (se l'oggetto è stato restituito da reader ()) o un dict (se è un'istanza di DictReader), analizzato in base al dialetto corrente. Di solito dovresti chiamarlo come successivo (lettore).

csv_data = csv.reader(open('sample.csv'))
csv_data.__next__() # skip first row
for row in csv_data:
    print(row) # should print second row
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.