¿Cómo ignorar la primera línea de datos al procesar datos CSV?

113

Le estoy pidiendo a Python que imprima el número mínimo de una columna de datos CSV, pero la fila superior es el número de la columna y no quiero que Python tenga en cuenta la fila superior. ¿Cómo puedo asegurarme de que Python ignore la primera línea?

Este es el código hasta ahora:

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

¿Podría también explicar lo que está haciendo, no solo dar el código? Soy muy nuevo en Python y me gustaría asegurarme de que entiendo todo.

martineau
fuente
5
¿Sabe que solo está creando un generador que devuelve un 1.0para cada línea en su archivo y luego toma el mínimo, que será 1.0?
Wooble
@Wooble Técnicamente, es un gran generador de 1.0. :)
Dougal
@Wooble buena captura - ... datatype(row[column]... es lo que supongo que el OP está tratando de lograr
Jon Clements
Hice que alguien me escribiera ese código y no lo entendí, así que gracias, jaja

Respuestas:

106

Puede usar una instancia de la clase csvdel módulo Snifferpara deducir el formato de un archivo CSV y detectar si una fila de encabezado está presente junto con la next()función incorporada para omitir la primera fila solo cuando sea necesario:

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)

Dado que datatypey columnestán codificados en su ejemplo, sería un poco más rápido procesar rowesto:

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

Nota: el código anterior es para Python 3.x. Para Python 2.x, use la siguiente línea para abrir el archivo en lugar de lo que se muestra:

with open('all16.csv', 'rb') as file:
martineau
fuente
2
En lugar de has_header(file.read(1024)), ¿tiene sentido escribir has_header(file.readline())? Veo eso mucho, pero no entiendo cómo has_reader()podría detectar si hay o no un encabezado de una sola línea del archivo CSV ...
Anto
1
@Anto: El código de mi respuesta se basa en el "ejemplo para el uso de Sniffer" en la documentación , así que supongo que es la forma prescrita de hacerlo. Estoy de acuerdo en que lo hace sobre la base de una línea de datos no parece que siempre sería suficientes datos para tomar una determinación, pero como no tengo ni idea ya que la forma en las Snifferque no se describen las obras. FWIW nunca he visto que has_header(file.readline())se use e incluso si funcionara la mayor parte del tiempo, sospecharía mucho del enfoque por las razones expuestas.
martineau
Gracias por tu contribución. Sin embargo, parece que el uso file.read(1024) genera errores en la biblioteca csv de python :. Véase también aquí, por ejemplo.
Anto
@Anto: Nunca me he encontrado con un error de este tipo; después de todo, 1024 bytes no es mucha memoria, ni ha sido un problema para muchas otras personas según los votos a favor que ha recibido esta respuesta (así como los miles de de personas que han leído y seguido la documentación). Por esas razones, sospecho fuertemente que algo más está causando su problema.
martineau
Me encontré exactamente con este mismo error tan pronto como cambié de readline()a read(1024). Hasta ahora solo he logrado encontrar personas que se hayan cambiado a readline para resolver el problema de csv.dialect.
Anto
75

Para omitir la primera línea, simplemente llame:

next(inf)

Los archivos en Python son iteradores sobre líneas.

jfs
fuente
22

En un caso de uso similar, tuve que omitir líneas molestas antes de la línea con los nombres de mis columnas reales. Esta solución funcionó muy bien. Primero lea el archivo y luego pase la lista 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)))
Maarten
fuente
Gracias Veedrac. Feliz de aprender aquí, ¿puede sugerir ediciones que resolverían los problemas que cita? Mi solución hace el trabajo, pero parece que podría mejorarse aún más.
Maarten
1
Te di una edición que reemplaza el código con algo que debería ser idéntico (no probado). Siéntase libre de revertir si no está en línea con lo que quiere decir. Todavía no estoy seguro de por qué está haciendo el datadiccionario, ni esta respuesta realmente agrega nada sobre la aceptada.
Veedrac
¡Gracias Veedrac! Eso parece muy eficiente de hecho. Publiqué mi respuesta porque la aceptada no me funcionaba (no recuerdo el motivo ahora). ¿Cuál sería el problema de definir data = dict () y luego llenarlo inmediatamente (en comparación con su sugerencia)?
Maarten
1
No está mal hacerlo data = dict()y completarlo, pero es ineficiente y no idiomático. Además, uno debería usar dict literals ( {}) e enumerateincluso entonces.
Veedrac
1
FWIW, debe responder a mis publicaciones con @Veedracsi quiere asegurarse de que me notifiquen, aunque Stack Overflow parece poder adivinar el nombre de usuario. (No escribo @Maartenporque el respondedor será notificado de forma predeterminada.)
Veedrac
21

Tomado de un libro de cocina de Python ,
un código de plantilla más conciso podría verse así:

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

Normalmente utilizaría next(incsv)que avanza el iterador una fila, por lo que se salta el encabezado. El otro (digamos que desea omitir 30 filas) sería:

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

utilice csv.DictReader en lugar de csv.Reader. Si se omite el parámetro fieldnames, los valores de la primera fila del archivo csv se utilizarán como nombres de campo. entonces podrá acceder a los valores de campo usando la fila ["1"], etc.

iruvar
fuente
2

El nuevo paquete 'pandas' podría ser más relevante que 'csv'. El siguiente código leerá un archivo CSV, interpretando de forma predeterminada la primera línea como el encabezado de columna y encontrando el mínimo entre columnas.

import pandas as pd

data = pd.read_csv('all16.csv')
data.min()
Finn Årup Nielsen
fuente
y también puede escribirlo en una línea:pd.read_csv('all16.csv').min()
Finn Årup Nielsen
1

Bueno, mi mini biblioteca de contenedores también haría el trabajo.

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

Mientras tanto, si sabe qué es el índice de la columna de encabezado uno, por ejemplo, "Columna 1", puede hacer esto en su lugar:

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

Para mí, la forma más fácil de hacerlo es usar range.

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
fuente
1

Debido a que esto está relacionado con algo que estaba haciendo, lo compartiré aquí.

¿Qué pasa si no estamos seguros de si hay un encabezado y tampoco quieres importar sniffer y otras cosas?

Si su tarea es básica, como imprimir o agregar a una lista o matriz, puede usar una declaración 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.
fuente
1

La documentación del módulo CSV de Python 3 proporciona este ejemplo:

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

El Sniffertratará de detectar automáticamente muchas cosas sobre el archivo CSV. Debe llamar explícitamente a su has_header()método para determinar si el archivo tiene una línea de encabezado. Si es así, omita la primera fila al iterar las filas CSV. Puedes hacerlo así:

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

Usaría tail para deshacerme de la primera línea no deseada:

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

solo agrega [1:]

ejemplo a continuación:

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

eso me funciona en iPython

la mente curiosa
fuente
0

Python 3.X

Maneja UTF8 BOM + HEADER

Fue bastante frustrante que el csvmódulo no pudiera obtener fácilmente el encabezado, también hay un error con UTF-8 BOM (primer carácter en el archivo). Esto funciona para mí usando solo el csvmódulo:

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
fuente
0

Convertiría csvreader a list, luego aparecería el primer 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)
Tim John
fuente
0

Python 2.x

csvreader.next()

Devuelve la siguiente fila del objeto iterable del lector como una lista, analizada según el dialecto actual.

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

Devuelve la siguiente fila del objeto iterable del lector como una lista (si el objeto fue devuelto por reader ()) o un dict (si es una instancia de DictReader), analizado según el dialecto actual. Por lo general, debería llamar a esto como siguiente (lector).

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
fuente