我正在尝试按列1分组查找列2中的top2值。
以下是数据框:
# groupby id and take only top 2 values.
df = pd.DataFrame({'id':[1,1,1,1,1,1,1,1,1,2,2,2,2,2],
'value':[20,20,20,30,30,30,30,40, 40,10, 10, 40,40,40]})
我已经完成了不使用链接分组的操作:
x = df.groupby('id')['value'].value_counts().groupby(level=0).nlargest(2).to_frame()
x.columns = ['count']
x.index = x.index.droplevel(0)
x = x.reset_index()
x
结果:
id value count
0 1 30 4
1 1 20 3
2 2 40 3
3 2 10 2
我们可以做到单链操作吗?
到目前为止,我已经做到了:
(df.groupby('id')['value']
.value_counts()
.groupby(level=0)
.nlargest(2)
.to_frame()
.rename({'value':'count'}))
现在,我停留在如何降低索引级别。 如何在一个链中完成所有这些操作?
答案 0 :(得分:1)
请尝试以下操作:
(df.groupby('id')['value']
.value_counts()
.groupby(level=0)
.nlargest(2)
.to_frame()).rename(columns={'value':'count'}).reset_index([1,2]).reset_index(drop=True)
答案 1 :(得分:1)
您可以使用apply
和head
而不使用第二个groupby
:
df.groupby('id')['value']\
.apply(lambda x: x.value_counts().head(2))\
.reset_index(name='count')\
.rename(columns={'level_1':'value'})
输出:
id value count
0 1 30 4
1 1 20 3
2 2 40 3
3 2 10 2
时间:
#This method
每个循环7 ms±116 µs(平均±标准偏差,共运行7次,每个循环100个循环)
#Groupby and groupby(level=0) with nlargest
每个循环12.9 ms±136 µs(平均±标准偏差,共运行7次,每个循环100个循环)
答案 2 :(得分:1)
另一个解决方案:
df.groupby('id')['value'].value_counts().rename('count')\
.groupby(level=0).nlargest(2).reset_index(level=[1, 2])\
.reset_index(drop=True)
答案 3 :(得分:0)
使用@Scott Boston的解决方案,我做了一些测试,并且 试图避免完全适用,但仍然适用于表现良好 与使用numpy一样:
import numpy as np
import pandas as pd
from collections import Counter
np.random.seed(100)
df = pd.DataFrame({'id':np.random.randint(0,5,10000000),
'value':np.random.randint(0,5,10000000)})
# df = pd.DataFrame({'id':[1,1,1,1,1,1,1,1,1,2,2,2,2,2],
# 'value':[20,20,20,30,30,30,30,40, 40,10, 10, 40,40,40]})
print(df.shape)
df.head()
%time
df.groupby('id')['value']\
.apply(lambda x: x.value_counts().head(2))\
.reset_index(name='count')\
.rename(columns={'level_1':'value'})
# CPU times: user 3 µs, sys: 0 ns, total: 3 µs
# Wall time: 6.2 µs
%time
grouped = df.groupby('id')['value']
res = np.zeros([2,3],dtype=int)
for name, group in grouped:
data = np.array(Counter(group.values).most_common(2))
ids = np.ones([2,1],dtype=int) * name
data = np.append(ids,data,axis=1)
res = np.append(res,data,axis=0)
pd.DataFrame(res[2:], columns=['id','value','count'])
# CPU times: user 3 µs, sys: 0 ns, total: 3 µs
# Wall time: 5.96 µs