Puisque l'exigence a été ajoutée qu'il y ait une distribution statistiquement uniforme des lignes sélectionnées dans le fichier, je propose cette approche simple.
"""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)
Je l'ai testé sur un fichier de données fictif de 3 millions de lignes comprenant 1,7 Go sur le disque. Le site scan_linepos
a dominé le temps d'exécution qui prend environ 20 secondes sur mon bureau pas si chaud.
Juste pour vérifier les performances de sample_lines
J'ai utilisé le timeit
comme suit
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))
Pour différentes valeurs de nsamp
; lorsque nsamp
était de 100, un seul sample_lines
achevé en 460µs et mis à l'échelle linéairement jusqu'à 10k échantillons à 47ms par appel.
La question suivante est naturellement Le hasard n'est pas du tout aléatoire ? et la réponse est "sous-cryptographique mais certainement très bien pour la bioinformatique".
0 votes
Duplicata possible de Méthode paresseuse pour lire un gros fichier en Python ?
2 votes
@ken - L'OP demande comment faire cela en utilisant
islice
Dans ce message, l'OP demande comment faire cela avecyield
.0 votes
Duplicata possible de Comment lire un fichier de N lignes à la fois en Python ?