我试图在按熊猫进行汇总时在每列中找到最常出现的值。为了找到最常使用的值,我按照建议的here使用了SGDClassifier
,但遇到了性能问题(请参见下面的代码段代码)
value_counts
结果:
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))
有什么方法可以改善上述效果?
答案 0 :(得分:2)
在熊猫中进行某些操作比所需的要慢得多(例如,即使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
但是您可以根据需要自定义它。
答案 1 :(得分:1)
以下给出了几乎瞬时的结果(在我的计算机上大约为0.1s):
使用多索引('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