2015-01-01 3 views
4

Я хочу записать некоторые случайные данные образца в файл csv, пока он не станет 1 ГБ. Работает следующий код:Самый быстрый способ написать большой CSV с Python

import numpy as np 
import uuid 
import csv 
import os 
outfile = 'data.csv' 
outsize = 1024 # MB 
with open(outfile, 'ab') as csvfile: 
    wtr = csv.writer(csvfile) 
    while (os.path.getsize(outfile)//1024**2) < outsize: 
     wtr.writerow(['%s,%.6f,%.6f,%i' % (uuid.uuid4(), np.random.random()*50, np.random.random()*50, np.random.randint(1000))])  

Как его получить быстрее?

+2

Почему вы помещаете этот вопрос в numpy, но не используете его (он не нужен для случайных чисел)? Зачем создавать csv-writer, но писать только одну строку в строке? Не указывается, что размер файла обновляется, пока файл не закрыт. Рассчитайте размер самостоятельно и не используйте 'getsize', намного быстрее. – Daniel

ответ

2

Удаление всех ненужных вещей, и поэтому он должен быть быстрее и легче понять:

import random 
import uuid 
outfile = 'data.csv' 
outsize = 1024 * 1024 * 1024 # 1GB 
with open(outfile, 'ab') as csvfile: 
    size = 0 
    while size < outsize: 
     txt = '%s,%.6f,%.6f,%i\n' % (uuid.uuid4(), random.random()*50, random.random()*50, random.randrange(1000)) 
     size += len(txt) 
     csvfile.write(txt) 
+0

Является ли len (txt) == filesize? И 'random.randint (1000)' принимает 2 аргумента. – Balzer82

+0

randint -> randrange. И 'len (txt)' - длина одной строки. – Daniel

+0

OK. Но длина одной строки или суммы длины строк не является размером файла. Кстати, ваш код не быстрее. Попробуйте. – Balzer82

4

Проблема, как представляется, в основном IO переплете. Вы можете улучшить I/O немного, запись в файл в больших кусков, вместо того, чтобы писать одну строку за один раз:

import numpy as np 
import uuid 
import csv 
import os 
outfile = 'data-alt.csv' 
outsize = 10 # MB 
chunksize = 1000 
with open(outfile, 'ab') as csvfile: 
    while (os.path.getsize(outfile)//1024**2) < outsize: 
     data = [[uuid.uuid4() for i in range(chunksize)], 
       np.random.random(chunksize)*50, 
       np.random.random(chunksize)*50, 
       np.random.randint(1000, size=(chunksize,))] 
     csvfile.writelines(['%s,%.6f,%.6f,%i\n' % row for row in zip(*data)]) 

Вы можете экспериментировать с chunksize (количество строк, записанных на куске), чтобы увидеть что лучше всего работает на вашей машине.


Вот тест, сравнивая приведенный выше код к исходному коду, с outsize набор 10 МБ:

% time original.py 

real 0m5.379s 
user 0m4.839s 
sys 0m0.538s 

% time write_in_chunks.py 

real 0m4.205s 
user 0m3.850s 
sys 0m0.351s 

Так что это около 25% быстрее, чем исходный код.


PS. Я попробовал заменить вызовы на os.path.getsize с оценкой количества необходимых нужных строк. К сожалению, это не улучшило скорость. Поскольку количество байтов, необходимых для представления окончательного значения int, меняется, оценка также неточна, то есть не полностью воспроизводит поведение вашего исходного кода. Поэтому я оставил os.path.getsize на месте.

Смежные вопросы