我想创建DataFrame(可能稀疏),以测量用户之间的相关性。在这里,我对user_1
和user_2
之间的相关性的定义是它们在同一天执行相同的action
的次数。
我将尝试通过一个例子更好地解释自己。假设我具有以下数据框:
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
这种方法的问题是我的用例速度很慢。
答案 0 :(得分:2)
这是使用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'))
[出]
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
[出]
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