Как разделить чтение большого CSV-файла на куски одинакового размера в Python? - PullRequest
17 голосов
/ 10 февраля 2011

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

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

for line in reader:
    process_line(line)

См. Этот связанный вопрос .Я хочу отправлять строку процесса каждые 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

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

Ответы [ 3 ]

22 голосов
/ 10 февраля 2011

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

>>> 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[:]
        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]
1 голос
/ 10 февраля 2011

Не существует хорошего способа сделать это для всех .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.

0 голосов
/ 14 декабря 2018

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

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