Python - 熊猫 - 找到最常见的组合与 tie-resolution - 性能
Posted
技术标签:
【中文标题】Python - 熊猫 - 找到最常见的组合与 tie-resolution - 性能【英文标题】:Python - pandas - find most frequent combination with tie-resolution - performance 【发布时间】:2021-02-19 16:32:36 【问题描述】:数据 我有一个看起来像这样的数据集:
| id | string_col_A | string_col_B | creation_date |
|-------|--------------|--------------|---------------|
| x12ga | STR_X1 | STR_Y1 | 2020-11-01 |
| x12ga | STR_X1 | STR_Y1 | 2020-10-10 |
| x12ga | STR_X2 | STR_Y2 | 2020-11-06 |
| x21ab | STR_X4 | STR_Y4 | 2020-11-06 |
| x21ab | STR_X5 | STR_Y5 | 2020-11-02 |
| x11aa | STR_X3 | STR_Y3 | None |
目标
-
我想为每个 id 找到最常见的值组合。
此外,在平局的情况下,我想提取最近的组合。
即上表的结果是:
| id | string_col_A | string_col_B |
|-------|--------------|--------------|
| x12ga | STR_X1 | STR_Y1 |
| x21ab | STR_X4 | STR_Y4 |
| x11aa | STR_X3 | STR_Y3 |
说明
-
对于
x12ga
,解释很简单。 STR_X1, STR_Y1 出现两次,STR_X2, STR_Y2 只出现一次(即没有平局解析)
x11aa
也很简单,只有一行
对于x21ab
,两个组合都有 1 行,但 STR_X4、STR_Y4 是最新的。
代码 这是我目前所拥有的:
def reducer(id_group):
id_with_sizes = id_group.groupby(
["id", "string_col_A", "string_col_B"], dropna=False).agg(
'creation_date': [len, max]
).reset_index()
id_with_sizes.columns = [
"id", "string_col_A", "string_col_B", "row_count",
"recent_date"
]
id_with_sizes.sort_values(by=["row_count", "recent_date"],
ascending=[False, False],
inplace=True)
return id_with_sizes.head(1).drop(["recent_date", "row_count"], axis=1)
我这样称呼上面的方法:
assignment = all_data.groupby("id").apply(inventor_reduce)
问题 上面的代码在使用数据进行测试时工作正常,但我正在使用的实际数据集有超过 10M 行,大约 3M ids。因此,处理 10K IDS 需要 5 分钟,总共需要 25 小时。我想提高性能。
解决方案 我在 ***(和其他地方)上看到了关于获得频繁组合(尽管没有 tie-resolution)和向量化过程以提高性能的问题。我不太确定如何解决上述问题。
理想情况下,解决方案仍然是基于 pandas 的(使用 pandas 的代码看起来和阅读效果更好)
【问题讨论】:
【参考方案1】:让我们尝试 groupby
和 transform
,然后得到最常见值的计数,然后 sort_values
和 drop_duplicates
df['help'] = df.groupby(['id','string_col_A','string_col_B'])['string_col_A'].transform('count')
out = df.sort_values(['help','creation_date'],na_position='first').drop_duplicates('id',keep='last').drop(['help','creation_date'],1)
out
Out[122]:
id string_col_A string_col_B
3 x21ab STR_X4 STR_Y4
5 x11aa STR_X3 STR_Y3
0 x12ga STR_X1 STR_Y1
【讨论】:
哇,这个解决方案非常快,每 10k 0.07 秒。我想这就是矢量化为您所做的。唯一的事情是我需要ascending=[False, False]
参数对吗?还有na_postition='last'
?【参考方案2】:
-
您可以创建一个系列
s
结合两列
返回最大计数的索引
按该索引过滤。 注意:如果您使用的是较早版本的 pandas,则从 .groupby
代码中取出 , sort=False
并在最后进行排序。
--
s = df['string_col_A'] + df['string_col_B']
df['max'] = df.groupby(['id',s])['id'].transform('count')
df = df.iloc[df.groupby('id', sort=False)['max'].idxmax().values].drop(['max', 'creation_date'], axis=1)
df
Out[1]:
id string_col_A string_col_B
0 x12ga STR_X1 STR_Y1
3 x21ab STR_X4 STR_Y4
5 x11aa STR_X3 STR_Y3
【讨论】:
【参考方案3】:您只需按id
列进行分组,并根据此找到最频繁的数据(模式)。
为方便起见,您可以创建另一列combined_str
:
df['combined_str'] = df['string_col_A'] + df['string_col_B']
按id
分组并使用pd.Series.mode
函数减少:
df = df.sort_values(by=['creation_date'])
df = df.groupby(['id'])['combined_str'].agg(most_common = ('combined_str', pd.Series.mode))
【讨论】:
在creation_date
上排序将确保我们处理好关系
好的,我正在使用 pandas 1.1.3 并且必须进行一些调整:df.groupby(['id'])['combined_str'].agg(pd.Series.mode).reset_index()
。在任何情况下,从性能方面来说,这很有效,每 10k ID 大约需要 18 秒。问题是我需要将 2 列作为最后的单独列。一种可能的解决方案是使用不明显的分隔符(如|
)并在最后一步拆分combined_str
。但这给我留下了不好的印象,它是一个不断发展的数据集,并且使用像 |
这样的任意字符似乎是在为未来的失败做准备。我会尝试其他答案并选择最有效的答案
当然不要使用任意字符来创建combined_str
。您可以改为使用元组并在 groupby 之后解压缩它们:df['combined_str'] = df[['colA', 'colB']].apply(lambda x: tuple([x['colA'], x['colB']), axis=1)
以上是关于Python - 熊猫 - 找到最常见的组合与 tie-resolution - 性能的主要内容,如果未能解决你的问题,请参考以下文章