【问题标题】: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 怎么样?

标签: python python-3.x pandas pandas-groupby


【解决方案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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-23
      • 1970-01-01
      • 2021-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-02
      • 2019-09-09
      相关资源
      最近更新 更多