Подтвердить что ты не робот

Как разделить чтение большого CSV файла на куски одинакового размера в Python?

В основном у меня был следующий процесс.

import csv
reader = csv.reader(open('huge_file.csv', 'rb'))

for line in reader:
    process_line(line)

Смотрите этот question. Я хочу отправить технологическую линию каждые 100 строк, чтобы реализовать пакетное очертание.

Проблема с реализацией связанного ответа заключается в том, что объект csv не подлежит подписке и не может использовать len.

>>> import csv
>>> reader = csv.reader(open('dataimport/tests/financial_sample.csv', 'rb'))
>>> len(reader)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type '_csv.reader' has no len()
>>> reader[10:]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '_csv.reader' object is unsubscriptable
>>> reader[10]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '_csv.reader' object is unsubscriptable

Как я могу это решить?

4b9b3361

Ответ 1

Просто сделайте ваш reader подписанным, обернув его в list. Очевидно, что это повредит действительно большие файлы (см. альтернативы в Обновлениях ниже):

>>> reader = csv.reader(open('big.csv', 'rb'))
>>> lines = list(reader)
>>> print lines[:100]
...

Дополнительная информация: Как разделить список на куски одинакового размера в Python?


Обновление 1 (список версий). Другой возможный способ - просто обработать каждый патрон, поскольку он поступает во время итерации по строкам:

#!/usr/bin/env python

import csv
reader = csv.reader(open('4956984.csv', 'rb'))

chunk, chunksize = [], 100

def process_chunk(chuck):
    print len(chuck)
    # do something useful ...

for i, line in enumerate(reader):
    if (i % chunksize == 0 and i > 0):
        process_chunk(chunk)
        del chunk[:]
    chunk.append(line)

# process the remainder
process_chunk(chunk)

Обновление 2 (версия генератора): я не тестировал его, но, возможно, вы можете повысить производительность с помощью генератора чанков:

#!/usr/bin/env python

import csv
reader = csv.reader(open('4956984.csv', 'rb'))

def gen_chunks(reader, chunksize=100):
    """ 
    Chunk generator. Take a CSV 'reader' and yield
    'chunksize' sized slices. 
    """
    chunk = []
    for i, line in enumerate(reader):
        if (i % chunksize == 0 and i > 0):
            yield chunk
            del chunk[:]  # or: chunk = []
        chunk.append(line)
    yield chunk

for chunk in gen_chunks(reader):
    print chunk # process chunk

# test gen_chunk on some dummy sequence:
for chunk in gen_chunks(range(10), chunksize=3):
    print chunk # process chunk

# => yields
# [0, 1, 2]
# [3, 4, 5]
# [6, 7, 8]
# [9]

Есть небольшая ошибка, как указывает @totalhack points out:

Имейте в виду, что это дает один и тот же объект снова и снова с различным содержанием. Это прекрасно работает, если вы планируете делать все, что вам нужно, с чанком между каждой итерацией.

Ответ 2

Нет хорошего способа сделать это для всех файлов .csv. Вы должны разделить файл на куски, используя file.seek, чтобы пропустить раздел файла. Затем вам нужно сканировать один байт за раз, чтобы найти конец строки. Вы можете самостоятельно обрабатывать два куска. Что-то вроде следующего (непроверенного) кода должно начать вас.

file_one = open('foo.csv')
file_two = open('foo.csv') 
file_two.seek(0, 2)     # seek to the end of the file
sz = file_two.tell()    # fetch the offset
file_two.seek(sz / 2)   # seek back to the middle
chr = ''
while chr != '\n':
    chr = file_two.read(1)
# file_two is now positioned at the start of a record
segment_one = csv.reader(file_one)
segment_two = csv.reader(file_two)

Я не уверен, как вы можете сказать, что вы закончили прохождение segment_one. Если у вас есть столбец в CSV, который является идентификатором строки, вы можете остановить обработку segment_one, когда вы встретите идентификатор строки из первой строки в segment_two.

Ответ 3

Мы можем использовать модуль Pandas для обработки этих больших CSV файлов.

df = pd.DataFrame()
temp = pd.read_csv('BIG_File.csv', iterator=True, chunksize=1000)
df = pd.concat(temp, ignore_index=True)