根据行数切片 Pandas Dataframe

Slicing Pandas Dataframe according to number of lines

我想这是相当简单的事情,但我找不到如何制作它。我一直在搜索教程和计算器。

假设我有一个像这样的数据框 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

我只想 select 组中至少有 4 个对象的行(因此至少有 4 行具有相同的 "group" 编号)并且第 4 个为 SomeQuantity对象在组中按 SomeQuantity 升序排序时大于 20(例如)。

例如,在给定的 Dataframe 中,它只会 return 第三组,因为它有 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 排序)。

有人可以帮助我吗? :)

我会使用 .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

使用 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)))


步骤分解:

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

>>> 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 操作,我们必须确保我们 return 在执行排序过程并将第四个元素与阈值为 20。 np.any return 所有这些可能性都符合我们的过滤器。

>>> 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 开始索引和 return 所有这些有利的匹配。

我就是这样解决你的问题的,包括缺点和所有问题。我相信有更好的方法可以做到这一点。

查找“组中有 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)]

“第 4 个 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