Как игнорировать первую строку данных при обработке данных CSV?


113

Я прошу Python напечатать минимальное число из столбца данных CSV, но верхняя строка - это номер столбца, и я не хочу, чтобы Python принимал во внимание верхнюю строку. Как я могу убедиться, что Python игнорирует первую строку?

Это пока что код:

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

Не могли бы вы также объяснить, что вы делаете, а не просто дать код? Я очень новичок в Python и хотел бы убедиться, что все понимаю.


5
Знаете ли вы, что вы просто создаете генератор, который возвращает 1.0для каждой строки в вашем файле, а затем берете минимум, который будет 1.0?
Wooble 05

@Wooble Технически это большой генератор 1.0. :)
Dougal

@Wooble хороший улов - ... datatype(row[column]... это то, чего, я думаю, пытается достичь ОП
Джон Клементс

Кто-то написал для меня этот код, но я этого не заметил, так что спасибо, ха-ха!

Ответы:


106

Вы можете использовать экземпляр класса csvмодуля, Snifferчтобы определить формат файла CSV и определить, присутствует ли строка заголовка вместе со встроенной next()функцией, чтобы пропустить первую строку только при необходимости:

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)

Поскольку datatypeи columnжестко запрограммированы в вашем примере, было бы немного быстрее обработать rowследующее:

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

Примечание: приведенный выше код предназначен для Python 3.x. Для Python 2.x используйте следующую строку, чтобы открыть файл вместо того, что показано:

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

2
Вместо того has_header(file.read(1024)), чтобы писать has_header(file.readline())? Я часто это вижу, но не понимаю, как has_reader()определить, есть ли заголовок в отдельной строке CSV-файла ...
Anto

1
@Anto: Код в моем ответе основан на «примере использования Sniffer» в документации , поэтому я предполагаю, что это предписанный способ сделать это. Я согласен , что делает это на основе одной линии данных не кажется , что он всегда будет достаточно данных , чтобы сделать такое определение, но я понятия не имею , поскольку , как эти Snifferработы не описываются. FWIW Я никогда не видел, has_header(file.readline())чтобы его использовали, и даже если бы он работал большую часть времени, я бы с большим подозрением отнесся к этому подходу по указанным причинам.
Мартино

Спасибо за ваш вклад. Тем не менее кажется, что использование file.read(1024) генерирует ошибки в csv lib python :. См. Также здесь, например.
Anto

@Anto: я никогда не сталкивался с такой ошибкой - 1024 байта - это не так уж и много памяти - и это не было проблемой для многих других людей, судя по голосам за этот ответ (а также тысячам людей, которые читали и следовали документации). По этим причинам я сильно подозреваю, что вашу проблему вызывает что-то еще.
Мартино

Я столкнулся с этой же ошибкой, как только переключился с readline()на read(1024). Пока мне удалось найти только людей, которые перешли на readline, чтобы решить проблему csv.dialect.
Anto

75

Чтобы пропустить первую строку, просто позвоните:

next(inf)

Файлы в Python - это итераторы по строкам.


22

В аналогичном случае использования мне приходилось пропускать надоедливые строки перед строкой с моими фактическими именами столбцов. Это решение отлично сработало. Сначала прочтите файл, затем передайте список в 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)))

Спасибо Veedrac. Рад узнать здесь, можете ли вы предложить правки, которые решат проблемы, которые вы цитируете? Мое решение выполняет свою работу, но, похоже, его можно улучшить?
Maarten

1
Я дал вам правку, которая заменяет код чем-то, что должно быть идентичным (непроверенным). Не стесняйтесь возвращаться, если это не соответствует тому, что вы имеете в виду. Я до сих пор не уверен, зачем вы делаете dataсловарь, и этот ответ на самом деле ничего не добавляет к принятому.
Veedrac

Спасибо Veedrac! Это действительно выглядит очень эффективно. Я отправил свой ответ, потому что принятый у меня не работал (сейчас не могу вспомнить причину). В чем будет проблема с определением data = dict () и последующим его немедленным заполнением (по сравнению с вашим предложением)?
Maarten

1
Это не плохо сделать data = dict()и заполнить, но это неэффективно и не идиоматично. Кроме того, следует использовать литералы dict ( {}) и enumerateдаже тогда.
Veedrac

1
FWIW, вы должны отвечать на мои сообщения, @Veedracесли хотите быть уверенным, что я уведомлен, хотя Stack Overflow, похоже, может угадать по имени пользователя. (Я не пишу, @Maartenпотому что ответчик будет уведомлен по умолчанию.)
Veedrac


19

Обычно вы используете, next(incsv)который продвигает итератор на одну строку, поэтому вы пропускаете заголовок. Другой (скажем, вы хотите пропустить 30 строк) будет:

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

6

используйте csv.DictReader вместо csv.Reader. Если параметр fieldnames опущен, значения в первой строке csvfile будут использоваться как имена полей. тогда вы сможете получить доступ к значениям полей, используя строку ["1"] и т. д.


2

Новый пакет pandas может быть более актуальным, чем csv. Приведенный ниже код будет читать файл CSV, по умолчанию интерпретируя первую строку как заголовок столбца и находя минимум по столбцам.

import pandas as pd

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

и вы также можете написать это в одну строку:pd.read_csv('all16.csv').min()
Финн Оруп Нильсен

1

Ну, моя мини-библиотека-оболочка тоже подойдет.

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

Между тем, если вы знаете, что такое индекс столбца заголовка, например «Столбец 1», вы можете сделать это вместо этого:

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

1

Для меня самый простой способ - использовать диапазон.

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

Поскольку это связано с тем, что я делал, я поделюсь здесь.

Что делать, если мы не уверены, есть ли заголовок, и вам также не хочется импортировать сниффер и другие вещи?

Если ваша задача простая, такая как печать или добавление в список или массив, вы можете просто использовать оператор 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

В документации по CSV-модулю Python 3 приведен следующий пример:

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

Он Snifferпопытается автоматически определить многие вещи в файле CSV. Вам нужно явно вызвать его has_header()метод, чтобы определить, есть ли в файле строка заголовка. Если это так, пропустите первую строку при итерации строк CSV. Сделать это можно так:

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

0

Я бы использовал tail, чтобы избавиться от нежелательной первой строки:

tail -n +2 $INFIL | whatever_script.py 

0

просто добавьте [1:]

пример ниже:

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

это работает для меня в iPython


0

Python 3.X

Обрабатывает UTF8 BOM + HEADER

Было довольно неприятно, что csvмодуль не мог легко получить заголовок, также есть ошибка с UTF-8 BOM (первый символ в файле). Это работает для меня, используя только csvмодуль:

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

Я бы преобразовал csvreader в список, а затем вставил первый элемент

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

Возвращает следующую строку итеративного объекта читателя в виде списка, проанализированного в соответствии с текущим диалектом.

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

Возвращает следующую строку итерируемого объекта читателя в виде списка (если объект был возвращен из reader ()) или слова (если это экземпляр DictReader), проанализированного в соответствии с текущим диалектом. Обычно вы должны называть это следующим (читатель).

csv_data = csv.reader(open('sample.csv'))
csv_data.__next__() # skip first row
for row in csv_data:
    print(row) # should print second row
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.