Como ignorar a primeira linha de dados ao processar dados CSV?

113

Estou pedindo ao Python que imprima o número mínimo de uma coluna de dados CSV, mas a linha superior é o número da coluna e não quero que o Python leve em consideração a linha superior. Como posso ter certeza de que o Python ignora a primeira linha?

Este é o código até agora:

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

Você também poderia explicar o que está fazendo, não apenas fornecer o código? Eu sou muito novo no Python e gostaria de ter certeza de que entendi tudo.

martineau
fonte
5
Você está ciente de que está apenas criando um gerador que retorna um 1.0para cada linha em seu arquivo e depois pegando o mínimo, que vai ser 1.0?
Wooble
@Wooble Tecnicamente, é um grande gerador de 1.0. :)
Dougal
@Wooble good catch - ... datatype(row[column]... é o que eu acho que o OP está tentando alcançar
Jon Clements
Eu pedi para alguém escrever aquele código para mim e não entendeu, então, obrigado haha!

Respostas:

106

Você pode usar uma instância da classe csvdo módulo Snifferpara deduzir o formato de um arquivo CSV e detectar se uma linha de cabeçalho está presente junto com a next()função integrada para pular a primeira linha apenas quando necessário:

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)

Uma vez que datatypee columnestão codificados em seu exemplo, seria um pouco mais rápido processar da rowseguinte forma:

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

Observação: o código acima é para Python 3.x. Para Python 2.x, use a seguinte linha para abrir o arquivo em vez do que é mostrado:

with open('all16.csv', 'rb') as file:
martineau
fonte
2
Em vez de has_header(file.read(1024)), faz sentido escrever has_header(file.readline())? Eu vejo muito isso, mas não entendo como has_reader()poderia detectar se há ou não um cabeçalho de uma única linha do arquivo CSV ...
Anto
1
@Anto: O código em minha resposta é baseado no "exemplo para uso do Sniffer" na documentação , então presumo que seja a maneira prescrita de fazer isso. Concordo que fazer isso com base em uma linha de dados nem sempre parece que seriam dados suficientes para fazer tal determinação - mas não tenho ideia, pois como o Snifferfuncionamento não é descrito. FWIW Eu nunca vi has_header(file.readline())sendo usado e mesmo que funcionasse na maioria das vezes, eu suspeitaria muito da abordagem pelas razões apresentadas.
martineau de
Obrigado pela sua contribuição. No entanto, parece que o uso de file.read(1024) gera erros no csv lib do python :. Veja também aqui, por exemplo.
Anto
@Anto: Eu nunca encontrei tal erro - 1024 bytes não é muita memória, afinal - nem foi um problema para muitas outras pessoas com base nos votos positivos que esta resposta recebeu (bem como os milhares de de pessoas que leram e seguiram a documentação). Por esses motivos, suspeito fortemente que outra coisa está causando o problema.
martineau de
Encontrei exatamente o mesmo erro assim que mudei de readline()para read(1024). Até agora, só consegui encontrar pessoas que mudaram para readline para resolver o problema csv.dialect.
Anto
75

Para pular a primeira linha, basta ligar:

next(inf)

Os arquivos em Python são iteradores em linhas.

jfs
fonte
22

Em um caso de uso semelhante, tive que pular linhas irritantes antes da linha com os nomes reais das colunas. Esta solução funcionou bem. Leia o arquivo primeiro e depois passe a lista para 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
fonte
Obrigado Veedrac. Feliz em aprender aqui, você pode sugerir edições que resolvam os problemas citados? Minha solução dá conta do recado, mas parece que ela poderia ser melhorada?
Maarten
1
Eu lhe dei uma edição que substitui o código por algo que deveria ser idêntico (não testado). Sinta-se à vontade para reverter se não estiver de acordo com o que você quis dizer. Ainda não sei por que você está fazendo o datadicionário, nem esta resposta realmente acrescenta nada em relação à aceita.
Veedrac
Obrigado Veedrac! Isso parece muito eficiente, de fato. Publiquei minha resposta porque a aceita não estava funcionando para mim (não me lembro o motivo agora). Qual seria o problema em definir data = dict () e, em seguida, preenchê-lo imediatamente (em comparação com sua sugestão)?
Maarten
1
Não é errado fazer data = dict()e preencher, mas é ineficiente e não idiomático. Além disso, deve-se usar literais dict ( {}) e enumeratemesmo assim.
Veedrac
1
FWIW, você deve responder às minhas postagens com @Veedracse quiser ter certeza de que fui notificado, embora o Stack Overflow pareça ser capaz de adivinhar pelo nome de usuário. (Não escrevo @Maartenporque o respondente será notificado por padrão.)
Veedrac
21

Emprestado do livro de receitas do python ,
um código de modelo mais conciso pode ser assim:

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

Você normalmente usaria o next(incsv)que avança o iterador uma linha, portanto, pula o cabeçalho. O outro (digamos que você queira pular 30 linhas) seria:

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

use csv.DictReader em vez de csv.Reader. Se o parâmetro fieldnames for omitido, os valores na primeira linha do csvfile serão usados ​​como nomes de campo. você poderia acessar os valores dos campos usando a linha ["1"] etc.

iruvar
fonte
2

O novo pacote 'pandas' pode ser mais relevante do que 'csv'. O código abaixo irá ler um arquivo CSV, por padrão interpretando a primeira linha como o cabeçalho da coluna e encontrar o mínimo nas colunas.

import pandas as pd

data = pd.read_csv('all16.csv')
data.min()
Finn Årup Nielsen
fonte
e você também pode escrever em uma linha:pd.read_csv('all16.csv').min()
Finn Årup Nielsen
1

Bem, minha minibiblioteca de invólucro também faria o trabalho.

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

Enquanto isso, se você souber qual é o índice de coluna de cabeçalho um, por exemplo, "Coluna 1", você pode fazer isso:

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

Para mim, a maneira mais fácil de fazer é usar o alcance.

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

Porque isso está relacionado a algo que eu estava fazendo, vou compartilhar aqui.

E se não tivermos certeza se há um cabeçalho e você também não quiser importar um sniffer e outras coisas?

Se sua tarefa for básica, como imprimir ou anexar a uma lista ou array, você pode usar apenas uma instrução 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.
fonte
1

A documentação para o módulo Python 3 CSV fornece este exemplo:

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

O Sniffertentará detectar automaticamente muitas coisas sobre o arquivo CSV. Você precisa chamar explicitamente seu has_header()método para determinar se o arquivo tem uma linha de cabeçalho. Em caso afirmativo, pule a primeira linha ao iterar as linhas CSV. Você pode fazer assim:

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

Eu usaria o tail para me livrar da primeira linha indesejada:

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

basta adicionar [1:]

exemplo abaixo:

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

que funciona para mim no iPython

a mente curiosa
fonte
0

Python 3.X

Lida com UTF8 BOM + HEADER

Foi muito frustrante que o csvmódulo não conseguisse obter o cabeçalho facilmente, há também um bug com o BOM UTF-8 (primeiro caractere no arquivo). Isso funciona para mim usando apenas o 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
fonte
0

Gostaria de converter csvreader para list e, em seguida, pop o primeiro 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
fonte
0

Python 2.x

csvreader.next()

Retorna a próxima linha do objeto iterável do leitor como uma lista, analisada de acordo com o dialeto atual.

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

Retorne a próxima linha do objeto iterável do leitor como uma lista (se o objeto foi retornado do leitor ()) ou um dicionário (se for uma instância de DictReader), analisado de acordo com o dialeto atual. Normalmente você deve chamar isso de próximo (leitor).

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
fonte