Pandas - подсчет коррелированных событий при условии - PullRequest
4 голосов
/ 22 января 2020

Я хотел бы создать DataFrame, возможно, разреженный, который измеряет корреляции между пользователями. Здесь мое определение корреляции между user_1 и user_2 - это количество раз, когда они оба выполнили один и тот же action в один и тот же день.

Я попытаюсь объяснить себя лучше на примере. Предположим, у меня есть следующий Dataframe:

date    action  user
6   2019-05-05  b   user_3
9   2019-05-05  b   user_2
1   2019-05-06  b   user_2
5   2019-05-06  a   user_1
0   2019-05-07  b   user_3
7   2019-05-07  a   user_2
8   2019-05-07  a   user_1
2   2019-05-08  c   user_2
4   2019-05-08  c   user_1
3   2019-05-09  c   user_3

, который можно сгенерировать с помощью этого фрагмента:

import numpy as np
import pandas as pd

np.random.seed(12)
users = np.random.choice(['user_1', 'user_2', 'user_3'], size=10)
actions = np.random.choice(['a', 'b', 'c'], size=10)
date = np.random.choice(pd.date_range(start='2019-05-05', end='2019-05-10', freq='D'), size=10)

df = pd.DataFrame(dict(date=date, action=actions, user=users))
df.date = pd.to_datetime(df.date)
df = df.sort_values('date')

Корреляция между user_1 и user_2 равна 2, так как они оба выполнено действие a в день 07 и действие c в день 08. Корреляция между user_2 и user_3 равна 1, поскольку они выполнили действие b в день 05. Все остальное NaN. Они выводят DataFrame, который я ищу:

        user_1  user_2  user_3
user_1  NaN     NaN     NaN
user_2  2.0     NaN     NaN
user_3  NaN     1.0     NaN

Мой неэффективный способ создания этого DataFrame следующий:

from itertools import combinations
df_result = pd.DataFrame(columns=['user_1', 'user_2', 'user_3'],
                         index=['user_1', 'user_2', 'user_3'], dtype=np.float64)    

for index, group in df.groupby(['date', 'action']):
    for x, y in combinations(list(group.user.values), 2):
        if np.isnan(df_result.loc[x,y]):
            df_result.loc[x, y] = 1
        else:
            df_result.loc[x, y] = df_result.loc[x, y] + 1

Проблема с этим подходом заключается в способ замедления в моем случае использования.

1 Ответ

2 голосов
/ 22 января 2020

Вот один потенциальный подход, использующий merge, для самостоятельного объединения на date и action. Затем используйте query, чтобы отфильтровать, где пользователь равен с обеих сторон, и, наконец, pivot_table для вывода.

df_corr = (df.merge(df, on=['date', 'action'])
           .query('user_x != user_y')
           .pivot_table(index='user_x', columns='user_y', aggfunc='size'))

[out]

user_y  user_1  user_2  user_3
user_x                        
user_1     NaN     2.0     NaN
user_2     2.0     NaN     1.0
user_3     NaN     1.0     NaN

Если показ только нижнего треугольника матрицы корреляции является требованием, вы можете NaN вывести верхнюю часть, используя:

mask = np.triu_indices_from(df_corr)
df_corr.values[mask] = np.nan

[out]

user_y  user_1  user_2  user_3
user_x                        
user_1     NaN     NaN     NaN
user_2     2.0     NaN     NaN
user_3     NaN     1.0     NaN
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...