过滤pandas DataFrame

时间:2016-11-06 21:35:51

标签: python pandas

如果我有以下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

2 个答案:

答案 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