Подтвердить что ты не робот

Прочитайте небольшой случайный образец из большого CSV файла в фрейм данных Python

Файл CSV, который я хочу прочитать, не вписывается в основную память. Как я могу прочитать несколько (~ 10K) случайных строк и сделать некоторые простые статистические данные по выбранному кадру данных?

4b9b3361

Ответ 1

Предположим, что в 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)

было бы лучше, если read_csv имел keeprows, или если skiprows взял funback вместо списка.

С заголовком и неизвестной длиной файла:

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)

Ответ 2

@dlm ответ великолепен, но начиная с версии 0.20.0, skiprows принимает вызываемый. Вызываемый получает в качестве аргумента номер строки.

Если вы можете указать, какой процент строк вы хотите, а не сколько строк, вам даже не нужно определять размер файла, и вам просто нужно прочитать файл один раз. Предполагая заголовок в первой строке:

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
)

Или, если вы хотите взять каждую n -ю строку:

n = 100  # every 100th line = 1% of the lines
df = pd.read_csv(filename, header=0, skiprows=lambda i: i % n != 0)

Ответ 3

Это не в Pandas, но он достигает того же результата намного быстрее через bash, не считывая весь файл в память:

shuf -n 100000 data/original.tsv > data/sample.tsv

Команда shuf перетасует ввод, а аргумент и -n указывает, сколько строк мы хотим получить на выходе.

Соответствующий вопрос: https://unix.stackexchange.com/q/108581

Тест на 7M строк CSV доступны здесь (2008):

Лучший ответ:

def pd_read():
    filename = "2008.csv"
    n = sum(1 for line in open(filename)) - 1 #number of records in file (excludes header)
    s = 100000 #desired sample size
    skip = sorted(random.sample(range(1,n+1),n-s)) #the 0-indexed header will not be included in the skip list
    df = pandas.read_csv(filename, skiprows=skip)
    df.to_csv("temp.csv")

Время для панд:

%time pd_read()
CPU times: user 18.4 s, sys: 448 ms, total: 18.9 s
Wall time: 18.9 s

При использовании shuf:

time shuf -n 100000 2008.csv > temp.csv

real    0m1.583s
user    0m1.445s
sys     0m0.136s

Таким образом, shuf примерно в 12 раз быстрее и, что важно, не читает весь файл в память.

Ответ 4

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

Скажем, вы хотите m образцов. Во-первых, алгоритм сохраняет первые m выборок. Когда он видит i-й образец (i > m), с вероятностью m/i, алгоритм использует образец для случайной замены уже выбранного образца.

Таким образом, для любого i > m всегда имеется подмножество m выборок, случайным образом выбранных из первых я образцов.

Смотрите код ниже:

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

Ответ 5

Следующий код сначала считывает заголовок, а затем случайную выборку на других строках:

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)

Ответ 6

Нет 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

В итоге вы получите список sampled_lines. Какую статистику вы имеете в виду?

Ответ 7

используйте подвыборку

pip install subsample
subsample -n 1000 file.csv > file_1000_sample.csv

Ответ 8

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(",")

что-то вроде этого должно работать, я думаю