Как разделить чтение большого 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
,