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

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

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

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

2 ответа

Решение

Просто сделай свой 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[:]
        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]

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

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

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

Другие вопросы по тегам