python - pandas 每组特定值的频率

标签 python pandas dataframe pandas-groupby

假设我有 5 万购物者及其购买的产品的数据。我想统计每个用户购买产品“a”的次数。 value_counts 似乎是计算分组 Pandas 数据框的这些类型数字的最快方法。然而,令我惊讶的是,使用 aggapply> 计算仅一种特定产品(例如“a”)的购买频率要慢得多。我可以从使用 value_counts 创建的数据框中选择特定列,但这对于包含大量产品的非常大的数据集可能相当低效。

下面是一个模拟示例,其中每个客户从一组三种产品中购买 10 次。在此大小下,您已经注意到 applyaggvalue_counts 相比的速度差异。有没有更好/更快的方法从分组的 pandas 数据框中提取这样的信息?

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "col1": [f'c{j}' for i in range(10) for j in range(50000)],
    "col2": np.random.choice(["a", "b", "c"], size=500000, replace=True)
})
dfg = df.groupby("col1")

# value_counts is fast
dfg["col2"].value_counts().unstack()

# apply and agg are (much) slower
dfg["col2"].apply(lambda x: (x == "a").sum())
dfg["col2"].agg(lambda x: (x == "a").sum())

# much faster to do
dfg["col2"].value_counts().unstack()["a"]

编辑:

对这个问题的两个很好的回答。 考虑到已经分组的数据框的起点,似乎没有比使用 (1) 使用 lambda 函数应用agg 或 (2) 使用 value_counts 获取所有级别的计数,然后选择您需要的级别。

groupby/size 方法是 value_counts 的绝佳替代方案。对 Cainã Max Couto-Silva 的答案稍加修改,结果如下:

dfg = df.groupby(['col1', 'col2'])
dfg.size().unstack(fill_value=0)["a"]

我认为在某些时候会有一个权衡,如果你有很多级别 apply/aggvalue_counts分组数据帧可能比需要创建新分组数据帧的groupby/size方法更快。当我有时间研究这个问题时,我会回复。

感谢您的评论和回答!

最佳答案

这仍然更快:

dfg = df.groupby(['col1','col2'])
dfg.size().unstack()

测试:

%%timeit
pd.crosstab(df.col1, df.col2)
# > 712 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
dfg = df.groupby("col1")
dfg["col2"].value_counts().unstack()
# > 165 ms ± 12.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
dfg = df.groupby(['col1','col2'])
dfg.size().unstack()
# > 131 ms ± 1.35 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

如果我们将数据框扩展到500万行:

df = pd.concat([df for _ in range(10)])

print(f'df.shape = {df.shape}')
# > df.shape = (5000000, 2)

print(f'{df.shape[0]:,} rows.')
# > 5,000,000 rows.
%%timeit
pd.crosstab(df.col1, df.col2)
# > 1.58 s ± 33.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
dfg = df.groupby("col1")
dfg["col2"].value_counts().unstack()
# > 1.27 s ± 47.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
dfg = df.groupby(['col1','col2'])
dfg.size().unstack()
# > 847 ms ± 53.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

关于python - pandas 每组特定值的频率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65067042/

相关文章:

python - 如何使用 python 添加屏幕截图以吸引报告?

Python - Tkinter - 如何从下拉选项中获取值并将其传递给另一个函数

python - 为 Python 脚本创建 GUI

python - 在 matplotlib 中旋转后对齐长刻度标记标签

python - 如何创建一个包含方程的函数并将其应用于不同的数据帧?

python - 从另一个数据框中计算 nunique

python - 在多列 Pandas 上加入 2 个数据框

python - 值错误: The number of classes has to be greater than one; got 1

python - 合并两个pandas DataFrame

python - 获取与Dataframe中每一行中的最大值相对应的所有列的列表