Быстрый способ выборки фрейма данных Dask (Python) - PullRequest
0 голосов
/ 14 июля 2020

У меня есть огромный файл, который я читал с помощью Dask (Python). В файле около 6 миллионов строк и 550 столбцов. Я хотел бы выбрать случайную выборку из 5000 записей (без замены). Вот 2 метода, которые я пробовал, но для их выполнения требуется огромное количество времени (я остановился более чем через 13 часов):


df_s=df.sample(frac=5000/len(df), replace=None, random_state=10)


NSAMPLES=5000
samples = np.random.choice(df.index, size=NSAMPLES, replace=False)
df_s=df.loc[samples]

Я не уверен, что это подходящие методы для фреймов данных Dask. Есть ли более быстрый способ случайного выбора записей для огромных фреймов данных?

1 Ответ

0 голосов
/ 14 июля 2020

Я создал набор тестовых данных с 6 миллионами строк, но только 2 столбцами, и рассчитал время для нескольких методов выборки (два, которые вы опубликовали, плюс df.sample с параметром n). Для каждого метода выборка заняла немногим более 200 мс, что, на мой взгляд, достаточно быстро. В моем наборе данных значительно меньше столбцов, поэтому это может быть причиной, тем не менее, я думаю, что ваша проблема вызвана не самой выборкой, а загрузкой данных и хранением их в памяти.

Я не использовал Dask раньше, но я предполагаю, что он использует некоторый logi c для кэширования данных с диска или сетевого хранилища. В зависимости от шаблонов доступа может случиться так, что кеширование работает не очень хорошо, и фрагменты данных должны загружаться из потенциально медленного хранилища для каждого отобранного образца.

Если поддерживается Dask , возможное решение может заключаться в том, чтобы нарисовать индексы записей набора выборочных данных (как в вашем втором методе) до фактической загрузки всего набора данных и загрузить только выбранные записи. Это вариант?

Обновление:

Dask утверждает, что выборки по строкам, например df[df.x > 0], могут быть вычислены быстро / параллельно (https://docs.dask.org/en/latest/dataframe.html). Может, можно попробовать что-то вроде этого:

sampled_indices = random.sample(range(len(df)), NSAMPLES)
df_s = df[df.index in sampled_indices]

Вот код, который я использовал для определения времени и некоторых результатов:

import numpy as np
import pandas as pd
import random
import timeit

data = {
    's_val' : list(),
    'f_val' : list()}
for i in range(int(6e6)):
    data['s_val'].append('item #' + str(i))
    data['f_val'].append(random.random())
df = pd.DataFrame(data)

NSAMPLES = 5000
NRUNS = 50
methods = [
    lambda : df.sample(n=NSAMPLES, replace=None, random_state=10),
    lambda : df.sample(frac=NSAMPLES/len(df), replace=None, random_state=10),
    lambda : df.loc[np.random.choice(df.index, size=NSAMPLES, replace=False)],
    ]
for i, f in enumerate(methods):
    print('avg. time method {}: {} s'.format(
        i, timeit.timeit(methods[i], number=NRUNS) / NRUNS))


Примерные результаты:

avg. time method 0: 0.21715480241997284 s
avg. time method 1: 0.21541569983994122 s
avg. time method 2: 0.21495854450011392 s

...