Поскольку было добавлено требование, чтобы было статистически равномерное распределение линий, выбранных из файла, я предлагаю этот простой подход.
"""randsamp - extract a random subset of n lines from a large file"""
import random
def scan_linepos(path):
"""return a list of seek offsets of the beginning of each line"""
linepos = []
offset = 0
with open(path) as inf:
# WARNING: CPython 2.7 file.tell() is not accurate on file.next()
for line in inf:
linepos.append(offset)
offset += len(line)
return linepos
def sample_lines(path, linepos, nsamp):
"""return nsamp lines from path where line offsets are in linepos"""
offsets = random.sample(linepos, nsamp)
offsets.sort() # this may make file reads more efficient
lines = []
with open(path) as inf:
for offset in offsets:
inf.seek(offset)
lines.append(inf.readline())
return lines
dataset = 'big_data.txt'
nsamp = 5
linepos = scan_linepos(dataset) # the scan only need be done once
lines = sample_lines(dataset, linepos, nsamp)
print 'selecting %d lines from a file of %d' % (nsamp, len(linepos))
print ''.join(lines)
Я проверил его на фиктивном файле данных из 3 миллионов строк, содержащем1,7 ГБ на диске.scan_linepos
доминировал во время выполнения, занимая на моем не очень горячем рабочем столе около 20 секунд.
Просто чтобы проверить производительность sample_lines
Я использовал модуль timeit
как так
import timeit
t = timeit.Timer('sample_lines(dataset, linepos, nsamp)',
'from __main__ import sample_lines, dataset, linepos, nsamp')
trials = 10 ** 4
elapsed = t.timeit(number=trials)
print u'%dk trials in %.2f seconds, %.2fµs per trial' % (trials/1000,
elapsed, (elapsed/trials) * (10 ** 6))
Для различных значений nsamp
;когда nsamp
равнялось 100, один sample_lines
завершался за 460 мкс и линейно масштабировался до 10 тыс. отсчетов при 47 мс на вызов.
Естественный следующий вопрос: Случайное вообще едва ли случайно?* и ответ «субкриптографический, но, безусловно, подходит для биоинформатики».