Pandas - 根据条件计算相关事件

Posted

技术标签:

【中文标题】Pandas - 根据条件计算相关事件【英文标题】:Pandas - Count correlated events on condition 【发布时间】:2020-05-08 09:05:02 【问题描述】:

我想创建 DataFrame,可能是稀疏的,用于衡量用户之间的相关性。在这里,我对user_1user_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

可以使用这个sn-p生成:

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_1user_2 之间的相关性为 2,因为它们都在 07 当天执行了动作 a,在 08 当天执行了动作 cuser_2user_3 之间的相关性是 1,因为它们在 05 日执行了操作 b。其余的都是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

这种方法的问题是在我的用例中变慢了。

【问题讨论】:

你的数据框有多大? DataFrame 中大约有 20 万个不同的用户和数十亿行 【参考方案1】:

这是一种潜在的方法,使用merge,在dateaction 上自我加入。然后使用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

【讨论】:

非常感谢,我真的很喜欢你的方法。我不需要照顾下三角形(实际上是对角线的下方,所以我跳过了查询)。由于pivot_table,我面临ValueError: Unstacked DataFrame is too big, causing int32 overflow 错误。我试图了解我想要获得的内容是否仅使用 RAM 是可行的。 我的秘密希望是 pandas 会通过使用稀疏表示来管理内存,但我可能过于乐观 是的,我刚刚看到您发布此数据后的数据大小......它非常庞大!可能需要另一种方法来以这种方式处理大量数据 我完全同意你的观点,我可能会尝试使用图形表示。尽管如此,对于合理大小的数据,您的答案几乎是当场的(对于虚拟数据集的性能提高了 10 倍的记录)

以上是关于Pandas - 根据条件计算相关事件的主要内容,如果未能解决你的问题,请参考以下文章

Pandas DataFrame 的条件计算列

Python:numpy/pandas 根据条件更改值

使用 pandas 根据条件将 csv 值附加到列表

pandas有没有计算低于某个值的函数

高效的条件滚动计算 Pandas

使用 pandas,计算 Cramer 的系数矩阵