通过聚合在pandas组中查找频繁项的最有效方法是啥[重复]

Posted

技术标签:

【中文标题】通过聚合在pandas组中查找频繁项的最有效方法是啥[重复]【英文标题】:What is the most efficient way to find a frequent item in pandas group by aggregation [duplicate]通过聚合在pandas组中查找频繁项的最有效方法是什么[重复] 【发布时间】:2018-12-23 05:20:51 【问题描述】:

我试图在通过 pandas 聚合时找到每列中最常出现的值。为了找到最常见的值,我按照建议 here 使用 value_counts,但面临性能问题(请参阅下面的 sn-p 代码)

import random
import time

import pandas as pd
df = pd.DataFrame('Country_ID': [random.randint(1000, 100001) for i in
                                   range(100000)],
                  'City': [random.choice(['NY', 'Paris', 'London',
                                   'Delhi']) for i in range(100000)])
agg_col = 'City': lambda x: x.value_counts().index[0]
start = time.time()
df_agg = df.groupby('Country_ID').agg(agg_col)
print("Time Taken: 0".format(time.time() - start))
print("Data: ", df_agg.head(5))

结果:

Time Taken: 24.467301845550537
Data: 
              City
Country_ID        
1000        London
1001         Paris
1003        London
1004        London
1006        London

有什么办法可以提高上述性能?

【问题讨论】:

试过 scipy.stats agg_col2 = 'City': lambda x: scipy.stats.mode(x)[0][0]? pd.Series.mode 怎么样? 【参考方案1】:

pandas 中的某些操作比它们需要的慢得多(例如,即使 max 本身很快,groupby 上的 idxmax 也会很痛苦)。有时退回到理论上效率较低的操作(例如,当我们只需要最大值时进行排序)但沿着优化路径行进可能会有所帮助。 [好的,这里我们实际上可以使用 transform(max) ,然后是过滤器。]

def orig(df):
    agg_col = 'City': lambda x: x.value_counts().index[0]
    df_agg = df.groupby('Country_ID').agg(agg_col)
    return df_agg.reset_index()

def via_sort(df):
    size = df.groupby(["Country_ID", "City"]).size().reset_index()
    size = size.sort_values(["City", 0])  # sort City to break ties
    df_agg = size.groupby("Country_ID")["City"].last()
    return df_agg.reset_index()

这给了我

In [33]: %time orig_out = orig(df.iloc[:10000])
Wall time: 4.87 s

In [34]: %time sort_out = via_sort(df.iloc[:10000])
Wall time: 31.2 ms

我迫不及待地等待完整的100000完成原始代码,但是:

In [39]: %time sort_out = via_sort(df)
Wall time: 93.6 ms

现在应该注意的是,两者给出的结果并不完全相同——它们在平局的处理方式上有所不同。例如:

In [48]: orig_out.loc[(orig_out != sort_out).any(axis=1)].head(1)
Out[48]: 
   Country_ID    City
9        1093  London

In [49]: sort_out.loc[(orig_out != sort_out).any(axis=1)].head(1)
Out[49]: 
   Country_ID   City
9        1093  Paris

In [50]: df.query('Country_ID == 1093')
Out[50]: 
       Country_ID    City
1758         1093  London
7378         1093   Paris
29188        1093   Delhi

但您可以随意自定义。

【讨论】:

【参考方案2】:

以下给出了几乎即时的结果(在我的机器上大约 0.1 秒):

使用多索引 ('Country_ID', 'City') 获取计数系列

df_agg = df.groupby('Country_ID')['City'].value_counts()
Country_ID  City  
1000        London    6
            Delhi     4
            Paris     3
            NY        2
1001        NY        6
            Delhi     4
            Paris     4
            London    3
1002        Delhi     2
            Paris     2
            London    1
            NY        1

将多索引的一部分移动到列中

df_agg = df_agg.reset_index(level='City', name='Counts')
              City  Counts
Country_ID                
1000        London       6
1000         Delhi       4
1000         Paris       3
1000            NY       2
1001            NY       6
1001         Delhi       4
1001         Paris       4
1001        London       3
1002         Delhi       2
1002         Paris       2
1002        London       1
1002            NY       1

由于value_counts() 返回排序结果,我们只需要删除重复项,保留每个索引的第一行

df_agg = df_agg[~df_agg.index.duplicated(keep='first')]
              City  Counts
Country_ID                
1000        London       6
1001            NY       6
1002         Delhi       2

现在只需删除计数

df_agg = df_agg[['City']]
              City
Country_ID        
1000        London
1001            NY
1002         Delhi

【讨论】:

以上是关于通过聚合在pandas组中查找频繁项的最有效方法是啥[重复]的主要内容,如果未能解决你的问题,请参考以下文章

识别和删除数组中重复项的最有效方法是啥?

对本身位于元组中的元组(可迭代的可迭代)求和的最有效方法是啥?

使用 Perl 检查数据数组中重复项的最有效方法是啥?

到目前为止,按同一组中的聚合元素分组 - Pandas

从 JavaScript 中的关联数组中获取第一项的最有效方法是啥?

在 C# List 中查找重复项索引的最优雅方法是啥