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】:

让我们尝试 groupbytransform ,然后得到最常见值的计数,然后 sort_valuesdrop_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 - 性能的主要内容,如果未能解决你的问题,请参考以下文章

如何计算熊猫一周中每天最大值的最常见时间

Python熊猫中的组合数据帧

将两个熊猫数据框组合在一起Python [重复]

查找字符串中最重复(不是最常见)序列的算法(也称为串联重复)

如何用大熊猫找字?或者两个词的组合?

Python - 在图像中查找主要/最常见的颜色