通过聚合在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.statsagg_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组中查找频繁项的最有效方法是啥[重复]的主要内容,如果未能解决你的问题,请参考以下文章
对本身位于元组中的元组(可迭代的可迭代)求和的最有效方法是啥?