如果我有以下DataFrame:
Name Total Category
A 150 c1
A 92 c2
A 13 c9
A 4 c8
B 100 c8
B 12 c7
B 10 c5
C 410 c2
C 222 c1
C 33 c4
C 24 c9
如何使用以下规则过滤上述DataFrame: 对于每个不同的名称,请返回最低总计的两行。
在上面的例子中,我想得到这个:
Name Total Category
A 13 c9
A 4 c8
B 12 c7
B 10 c5
C 33 c4
C 24 c9
答案 0 :(得分:2)
SeriesGroupBy.nsmallest
的解决方案:
获取get_level_values
分组最小值的所有索引,因为获取MultiIndex
并需要选择第二级,然后按loc
选择:
print (df.loc[df.groupby('Name')['Total'].nsmallest(2).index.get_level_values(1)])
Name Total Category
3 A 4 c8
2 A 13 c9
6 B 10 c5
5 B 12 c7
10 C 24 c9
9 C 33 c4
使用set_index
的解决方案,但是有必要重新排序列:
df = df.set_index('Category').groupby('Name')['Total'].nsmallest(2).reset_index()
df = df[['Name','Total','Category']]
print (df)
Name Total Category
0 A 4 c8
1 A 13 c9
2 B 10 c5
3 B 12 c7
4 C 24 c9
5 C 33 c4
<强>计时强>:
#len(df) = 60k
df = pd.concat([df]*10000).reset_index(drop=True)
In [92]: %timeit (df.set_index('Category').groupby('Name')['Total'].nsmallest(2).reset_index())
100 loops, best of 3: 19.2 ms per loop
In [93]: %timeit (df.sort_values(['Name','Total']).groupby('Name').head(2))
10 loops, best of 3: 27.5 ms per loop
#len(df)=600k
df = pd.concat([df]*100000).reset_index(drop=True)
In [104]: %timeit (df.loc[df.groupby('Name')['Total'].nsmallest(2).index.get_level_values(1)])
10 loops, best of 3: 123 ms per loop
In [96]: %timeit (df.set_index('Category').groupby('Name')['Total'].nsmallest(2).reset_index())
10 loops, best of 3: 162 ms per loop
In [97]: %timeit (df.set_index('Category').groupby('Name')['Total'].nsmallest(2).reset_index()[['Name','Total','Category']])
10 loops, best of 3: 161 ms per loop
In [98]: %timeit (df.sort_values(['Name','Total']).groupby('Name').head(2))
1 loop, best of 3: 351 ms per loop
答案 1 :(得分:1)
试试这个:
In [247]: df.sort_values(['Name','Total']).groupby('Name').head(2)
Out[247]:
Name Total Category
3 A 4 c8
2 A 13 c9
6 B 10 c5
5 B 12 c7
10 C 24 c9
9 C 33 c4