根据行数

时间:2017-01-06 11:58:01

标签: python pandas dataframe slice

我认为这是相当简单的事情,但我找不到如何做到这一点。我一直在寻找教程和stackoverflow。

假设我有一个像这样的数据帧df:

Group   Id_In_Group   SomeQuantity
1        1              10
1        2              20
2        1               7
3        1              16
3        2              22
3        3               5
3        4              12
3        5              28
4        1               1
4        2              18
4        3              14
4        4               7
5        1              36

我想只选择组中至少有4个对象的行(因此至少有4行具有相同的“组”编号),并且对于第4个对象的SomeQuantity,当按组排序时升序SomeQuantity,大于20(例如)。

在给定的Dataframe中,例如,它只返回第3组,因为它有4个(> = 4)成员,其第4个SomeQuantity(排序后)是22(> = 20),所以应该构建数据框:

Group   Id_In_Group   SomeQuantity
3        1              16
3        2              22
3        3               5
3        4              12
3        5              28

(由SomeQuantity分类或不分类。)

有人可以帮助我吗? :)

3 个答案:

答案 0 :(得分:5)

我会使用.groupby() + .filter()方法:

In [66]: df.groupby('Group').filter(lambda x: len(x) >= 4 and x['SomeQuantity'].max() >= 20)
Out[66]:
   Group  Id_In_Group  SomeQuantity
3      3            1            16
4      3            2            22
5      3            3             5
6      3            4            12
7      3            5            28

答案 1 :(得分:3)

使用mapvalue_countsgroupbyfilter的方法略有不同:

(df[df.Group.map(df.Group.value_counts().ge(4))]
   .groupby('Group')
   .filter(lambda x: np.any(x['SomeQuantity'].sort_values().iloc[3] >= 20)))

enter image description here

步骤细分:

执行value_counts以计算列中存在的不同元素的总计数。

>>> df.Group.value_counts()

3    5
4    4
1    2
5    1
2    1
Name: Group, dtype: int64

使用map功能,如字典(其中索引成为键,系列元素成为值),将这些结果映射回原始DF

>>> df.Group.map(df.Group.value_counts())

0     2
1     2
2     1
3     5
4     5
5     5
6     5
7     5
8     4
9     4
10    4
11    4
12    1
Name: Group, dtype: int64

然后,我们检查值为4或更高的元素,这是我们的阈值限制,并仅从整个DF中获取那些子集。

>>> df[df.Group.map(df.Group.value_counts().ge(4))]   

    Group  Id_In_Group  SomeQuantity
3       3            1            16
4       3            2            22
5       3            3             5
6       3            4            12
7       3            5            28
8       4            1             1
9       4            2            28
10      4            3            14
11      4            4             7

为了对此使用groupby.filter操作,我们必须确保在执行排序过程时返回与每个分组键对应的单个布尔值,并将第四个元素与阈值20进行比较。 np.any会返回与我们的过滤器匹配的所有可能性。

>>> df[df.Group.map(df.Group.value_counts().ge(4))]         \
      .groupby('Group').apply(lambda x: x['SomeQuantity'].sort_values().iloc[3])

 Group
3    22
4    18
dtype: int64

从这些中,我们比较第四个元素.iloc[3],因为它是基于0的索引并返回所有这些有利的匹配。

答案 2 :(得分:1)

这就是我处理你的问题,疣和所有的方法。我确定有更好的方法可以做到这一点。

查找包含“群组中的4个对象”的群组

import collections

groups = list({k for k, v in collections.Counter(df.Group).items() if v > 3} );groups

Out:[3, 4]

使用这些组过滤到包含这些组的新df:

df2 = df[df.Group.isin(groups)]

“4th SomeQuantity(排序后)是22(> = 20)”

 df3 = df2.sort_values(by='SomeQuantity',ascending=False)

(根据以下评论更新......)

df3.groupby('Group').filter(lambda grp: any(grp.sort_values('SomeQuantity').iloc[3] >= 20)).sort_index()

    Group   Id_In_Group SomeQuantity
  3    3        1       16
  4    3        2       22
  5    3        3       5
  6    3        4       12
  7    3        5       28