Как применить пользовательскую функцию к группам в кадре данных dask, используя несколько столбцов в качестве входных данных функции - PullRequest
0 голосов
/ 17 марта 2020

У меня очень большой фрейм данных, с которым я работаю dask . Фрейм данных выглядит в общем и целом так:

Col_1    Col_2   Bool_1   Bool_2
A        1       True     False
B        1       True     True
C        1       False    False
D        1       True     False
A        2       False    True
B        2       False    False
C        2       True     False
D        2       True     True

Но в нем миллионы строк.

В этой точке кода я пытаюсь вычислить расстояние Джакарта между Bool_1 и Bool_2 для каждой группы, сформированной в Col_2. Это потому, что целью этой программы является создание одной строки для каждой группы , присутствующей в Col_2 (каждая строка имеет несколько статистических данных, я сообщаю только о соответствующих столбцах).

Для этого я сначала группирую кадр данных по Col_2, используя df.groupby("Col_2"), но потом не знаю, как поступить. Каждая попытка, которую я до сих пор пробовал, приводила к ошибке.

1 : я пытался определить функцию compute_jacc_dist() и передать ее через apply(compute_jacc_dist, axis=1) группам, но у нее есть проблемы с args и kwargs (ось особенно, см. https://github.com/dask/dask/issues/1572, который я пока не могу решить).

2 : я пытался использовать from dask_distance import jaccard и использовать его для вычисления расстояния J между Bool_1 и Bool_2, но это дает странные результаты (каждая группа возвращает J = 1, даже если пересечения НЕТ).

3 : я попытался compute() фрейма данных и перебрать группы, используя:

for name, group in df.groupby("Col_2"):
   jacc = dask_distance.jaccard(group["Bool_1"], group["Bool_2"])

Но этот ад чертовски медленный, потому что он вызывает вычисление, а затем оперирует такой огромной группой данных по группам (т.е. я не хочу ее использовать). Для справки: сценарий с этой функцией выполняется уже два дня, хотя я предполагаю, что любое из решений № 1 и № 2, которые я попробовал, при правильной настройке вернет результаты через 1-2 часа.

Любое предложение о том, как я мог бы решить эту проблему? Мое идеальное решение - правильно использовать df.groupby("Col_1").apply(compute_jacc_dist). Любая помощь высоко ценится!

1 Ответ

0 голосов
/ 17 марта 2020

После многих часов попыток вот как я это сделал. Если вы читаете это, вы можете захотеть прочитать это ( Как применить евклидову функцию расстояния к объекту groupby в pandas dataframe? ) и это ( Применение нескольких функций к нескольким столбцам groupby ).

def my_function(x):

    d = {}
    v1 = np.array(x["Bool_1"])
    v2 = np.array(x["Bool_2"])
    intersection = np.logical_and(v1, v2).sum()
    union = np.logical_or(v1, v2).sum()
    d["Jaccard"] = float(intersection) / float(union)
    return pd.Series(d, index=["Jaccard"])

df = df.groupby("Col_2").apply(my_function, meta={"Jaccard":"float16"}).compute()

Объяснение

Я создаю функцию, которая вычисляет расстояние по Джакарду между двумя столбцами моего информационного кадра. Внутри функции я создаю словарь (d), который будет содержать результаты моих вычислений.

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

Затем функция возвращает pd.Series, содержащий словарь.

Эта функция применяется к группам данных, которые основаны на Col_2. meta типы данных указываются в apply(), и все это имеет compute() в конце, так как это фрейм данных dask, и для получения результата должны быть запущены вычисления.

В apply() должно быть столько meta, сколько имеется выходных столбцов.

...