2011-02-10 22 views
14

Trong cơ bản, tôi đã có quy trình tiếp theo.Làm cách nào để bạn chia tệp csv thành các khối có kích thước đồng đều bằng Python?

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

for line in reader: 
    process_line(line) 

Xem liên quan này question. Tôi muốn gửi dòng xử lý mỗi 100 hàng, để thực hiện hàng loạt sharding.

Sự cố khi triển khai câu trả lời có liên quan là đối tượng csv không thể ghi đè và không thể sử dụng 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 

Tôi làm cách nào để giải quyết vấn đề này?

Trả lời

20

Chỉ cần đặt reader của bạn có thể lập chỉ mục bằng cách gói nó vào list. Rõ ràng điều này sẽ phá vỡ trên thực sự file lớn (xem giải pháp thay thế trong cập nhật dưới đây):

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

Đọc thêm: How do you split a list into evenly sized chunks in Python?


Cập nhật 1 (danh sách phiên bản): Một cách khác có thể sẽ chỉ xử lý từng mâm cặp, khi nó đến trong khi lặp qua các dòng:

#!/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) 

Cập nhật 2 (phiên bản máy phát điện): Tôi đã không benchmarked nó, nhưng có lẽ bạn có thể tăng hiệu suất bằng cách sử dụng một đoạn phát:

#!/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] 
+0

Sự cố là đăng ký tệp, bắt buộc phải đọc tất cả các dòng của tệp. Đây là một tập tin thực sự rất lớn và sử dụng bộ nhớ tăng lên nhiều nếu tôi làm điều đó. –

+0

Đẹp, cảm ơn @TheMYYN :-) –

+1

@Mario: Đã thêm phiên bản trình tạo, có thể nhanh hơn (nhưng tôi không có thời gian để thử nghiệm - có thể bạn đã làm). – miku

1

Không có một tốt cách để thực hiện việc này cho tất cả các tệp .csv. Bạn có thể chia tệp thành các khối bằng cách sử dụng file.seek để bỏ qua một phần của tệp. Sau đó, bạn phải quét một byte tại một thời điểm để tìm kết thúc của hàng. Bạn có thể xử lý hai khối độc lập. Một cái gì đó như sau (chưa được kiểm tra) mã sẽ giúp bạn bắt đầu.

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) 

Tôi không chắc chắn làm thế nào bạn có thể biết rằng bạn đã hoàn thành việc vượt qua segment_one. Nếu bạn có một cột trong CSV là id hàng, thì bạn có thể ngừng xử lý segment_one khi bạn gặp phải id hàng từ hàng đầu tiên trong segment_two.

Các vấn đề liên quan