Lire un petit échantillon aléatoire à partir D'un grand fichier CSV dans un cadre de données Python
le fichier CSV que je veux lire ne rentre pas dans la mémoire principale. Comment puis-je lire quelques lignes aléatoires (~10K) De celui-ci et faire quelques statistiques simples sur la base de données sélectionnée?
8 réponses
sans en-tête dans le fichier CSV:
import pandas
import random
n = 1000000 #number of records in file
s = 10000 #desired sample size
filename = "data.txt"
skip = sorted(random.sample(xrange(n),n-s))
df = pandas.read_csv(filename, skiprows=skip)
serait mieux si read_csv avait un keeprows, ou si skiprows a pris un func callback au lieu d'une liste.
avec en-tête et longueur du fichier inconnue:
import pandas
import random
filename = "data.txt"
n = sum(1 for line in open(filename)) - 1 #number of records in file (excludes header)
s = 10000 #desired sample size
skip = sorted(random.sample(xrange(1,n+1),n-s)) #the 0-indexed header will not be included in the skip list
df = pandas.read_csv(filename, skiprows=skip)
@dlm réponse est grande, mais depuis v0.20.0, "151960920 paramètres" skiprows accepte un callable . Le callable reçoit comme argument le numéro de ligne.
si vous pouvez spécifier quel pourcentage des lignes que vous voulez, plutôt que combien de lignes , vous n'avez même pas besoin d'obtenir la taille du fichier et vous avez juste besoin de lire à travers le fichier une fois. En supposant un en-tête sur la première ligne:
import pandas as pd
import random
p = 0.01 # 1% of the lines
# keep the header, then take only 1% of lines
# if random from [0,1] interval is greater than 0.01 the row will be skipped
df = pd.read_csv(
filename,
header=0,
skiprows=lambda i: i>0 and random.random() > p
)
Ou, si vous voulez prendre tous les n
e ligne:
n = 100 # every 100th line = 1% of the lines
df = pd.read_csv(filename, header=0, skiprows=lambda i: i % n != 0)
ce N'est pas dans Pandas, mais il obtient le même résultat beaucoup plus rapidement par bash:
shuf -n 100000 data/original.tsv > data/sample.tsv
la commande shuf
mélangera l'entrée et l'argument -n
indique combien de lignes nous voulons dans la sortie.
question pertinente: https://unix.stackexchange.com/q/108581
voici un algorithme qui ne nécessite pas de compter le nombre de lignes dans le fichier à l'avance, donc vous n'avez besoin de lire le fichier qu'une seule fois.
dites que vous voulez des échantillons M. Tout d'abord, l'algorithme conserve les premiers échantillons M. Quand il voit l'échantillon I-E (i > m), avec la probabilité m/i, l'algorithme utilise l'échantillon pour remplacer au hasard un échantillon déjà sélectionné.
ce faisant, pour tout i > m, nous avons toujours un sous-ensemble d'échantillons m choisis au hasard à partir de la première fois que je les échantillons.
voir code ci-dessous:
import random
n_samples = 10
samples = []
for i, line in enumerate(f):
if i < n_samples:
samples.append(line)
elif random.random() < n_samples * 1. / (i+1):
samples[random.randint(0, n_samples-1)] = line
Le code suivant lit d'abord la tête, puis un échantillon aléatoire sur les autres lignes:
import pandas as pd
import numpy as np
filename = 'hugedatafile.csv'
nlinesfile = 10000000
nlinesrandomsample = 10000
lines2skip = np.random.choice(np.arange(1,nlinesfile+1), (nlinesfile-nlinesrandomsample), replace=False)
df = pd.read_csv(filename, skiprows=lines2skip)
Pas de pandas!
import random
from os import fstat
from sys import exit
f = open('/usr/share/dict/words')
# Number of lines to be read
lines_to_read = 100
# Minimum and maximum bytes that will be randomly skipped
min_bytes_to_skip = 10000
max_bytes_to_skip = 1000000
def is_EOF():
return f.tell() >= fstat(f.fileno()).st_size
# To accumulate the read lines
sampled_lines = []
for n in xrange(lines_to_read):
bytes_to_skip = random.randint(min_bytes_to_skip, max_bytes_to_skip)
f.seek(bytes_to_skip, 1)
# After skipping "bytes_to_skip" bytes, we can stop in the middle of a line
# Skip current entire line
f.readline()
if not is_EOF():
sampled_lines.append(f.readline())
else:
# Go to the begginig of the file ...
f.seek(0, 0)
# ... and skip lines again
f.seek(bytes_to_skip, 1)
# If it has reached the EOF again
if is_EOF():
print "You have skipped more lines than your file has"
print "Reduce the values of:"
print " min_bytes_to_skip"
print " max_bytes_to_skip"
exit(1)
else:
f.readline()
sampled_lines.append(f.readline())
print sampled_lines
vous finirez avec une liste sampled_lines. De quel type de statistiques parlez-vous?
class magic_checker:
def __init__(self,target_count):
self.target = target_count
self.count = 0
def __eq__(self,x):
self.count += 1
return self.count >= self.target
min_target=100000
max_target = min_target*2
nlines = randint(100,1000)
seek_target = randint(min_target,max_target)
with open("big.csv") as f:
f.seek(seek_target)
f.readline() #discard this line
rand_lines = list(iter(lambda:f.readline(),magic_checker(nlines)))
#do something to process the lines you got returned .. perhaps just a split
print rand_lines
print rand_lines[0].split(",")
quelque chose comme ça devrait marcher je pense
utiliser sous-échantillon
pip install subsample
subsample -n 1000 file.csv > file_1000_sample.csv