Использование pd.DataFrame.sample в фрейме данных dask с groupby - PullRequest
1 голос
/ 06 августа 2020

У меня очень большой фрейм данных, который я передискретизирую большое количество раз, поэтому я хотел бы использовать dask для ускорения процесса. Однако у меня возникают проблемы с подачей заявки на группу. Примером кадра данных может быть

import numpy as np
import pandas as pd
import random
test_df = pd.DataFrame({'sample_id':np.array(['a', 'b', 'c', 'd']).repeat(100),
                       'param1':random.sample(range(1, 1000), 400)})
test_df.set_index('sample_id', inplace=True)

, который я обычно могу сгруппировать и передискретить, используя

N = 5;i=1

test = test_df\
    .groupby(['sample_id'])\
    .apply(pd.DataFrame.sample, n=N, replace=False)\
    .reset_index(drop=True)
test['bootstrap'] = i
test['resample'] = N

, который я превращаю в метод, который повторяет градиент N раз. Фактический фрейм данных очень большой, с несколькими столбцами, и, прежде чем кто-либо предположит, этот метод немного быстрее, чем подход np.random.choice к индексу - все в groupby. Я выполнил всю процедуру с помощью метода многопроцессорности, но я хотел посмотреть, смогу ли я получить немного больше скорости от его версии dask. Проблема в том, что документация предполагает, что если вы индексируете и разбиваете, то вы получаете полные группы для каждого раздела, что не является верным.

import dask.dataframe as dd

df1 = dd.from_pandas(test_df, npartitions=8)
df1=df1.persist()
df1.divisions

создает

('a' , 'b', 'c', 'd', 'd')

, что неудивительно, приводит к сбою

N = 5;i=1

test = df1\
    .groupby(['sample_id'])\
    .apply(pd.DataFrame.sample, n=N, replace=False)\
    .reset_index(drop=True)
test['bootstrap'] = i
test['resample'] = N

ValueError: вывод метаданных не удалось в groupby.apply(sample). Вы предоставили пользовательскую функцию, и Dask не может определить тип вывода, который возвращает эта функция. Чтобы решить эту проблему, укажите ключевое слово meta =. Строка документации запущенной вами функции Dask должна содержать больше информации. Исходная ошибка приведена ниже: ValueError ("Невозможно взять больше выборки, чем совокупность, когда 'replace = False'")

Я копал всю документацию по ключевым словам, фреймам данных и разделам dask, а также группировкам и просто мне просто не хватает решения, если оно есть в документах. Мы будем глубоко признательны за любые советы о том, как создать более умный набор разделов и / или получить groupby с образцом, играющим хорошо с dask.

1 Ответ

2 голосов
/ 06 августа 2020

Мне не совсем понятно, чего вы пытаетесь достичь и почему вам нужно добавить replace=False (по умолчанию), но следующий код мне подходит. Мне просто нужно добавить meta.

import dask.dataframe as dd

df1 = dd.from_pandas(test_df.reset_index(), npartitions=8)

N = 5
i = 1

test = df1\
    .groupby(['sample_id'])\
    .apply(lambda x: x.sample(n=N),
           meta={"sample_id": "object",
                 "param1": "f8"})\
    .reset_index(drop=True)
test['bootstrap'] = i
test['resample'] = N

Если вы затем хотите удалить sample_id, вам просто нужно добавить

df = df.drop("sample_id", axis=1)
...