【问题标题】:Group Pandas dataframe by one column, drop rows based on another column按一列对 Pandas 数据框进行分组,根据另一列删除行
【发布时间】:2023-03-08 06:10:01
【问题描述】:

我有一个看起来像这样的熊猫数据框:

     UNIT        MACHINE
1    a100        001
2    a100        002
3    a100        003
4    a100        001
5    b222        001
6    b222        002
7    b222        002
8    b222        003

我想根据“UNIT”对其进行分组,并删除没有 [001, 002, 003] “MACHINE” 序列的行。这意味着因为 UNIT "a100" 具有序列 [001, 002, 003, 001],它应该被删除,但 UNIT "b222" 仍然存在,因为无论 MACHINE 002 是否重复,序列都是正确的。

输出应如下所示:

     UNIT        MACHINE
5    b222        001
6    b222        002
7    b222        002
8    b222        003

序列 [001, 002, 003] 是我在这里作为示例编写的可接受的 MACHINE 序列之一。这样的序列有好几个,都是单调递增的。

我应该如何结合 GroupBy 和 drop 来执行此操作?

【问题讨论】:

  • 预期输出如何?你的那部分代码呢?
  • 我在上面添加了输出。不幸的是,我没有这方面的代码。
  • 在您自己找到解决方案后尝试自己。如果您遇到任何问题,那么 SO 将很乐意提供帮助。
  • @MaxU 我想 OP 只想要 MACHINE ID 的非递减序列。
  • 谢谢大家,问题已经用@COLDSPEED 的解决方案解决了。

标签: python pandas dataframe group-by pandas-groupby


【解决方案1】:
In [26]: chk_set = set(df.MACHINE.unique())

In [27]: df[df.groupby('UNIT')['MACHINE']
              .transform(lambda x: x.is_monotonic_increasing & chk_set.issubset(set(x)))]
Out[27]:
   UNIT MACHINE
5  b222     001
6  b222     002
7  b222     002
8  b222     003

更新:

假设你有以下 DF:

In [90]: df
Out[90]:
    UNIT MACHINE
1   a100     001
2   a100     002
3   a100     003
4   a100     001
5   b222     001
6   b222     002
7   b222     002
8   b222     003
9     c1     001
10    c1     003
11    c2     078
12    c2     079
13    c2     080
14    c3     078
16    c3     080

以及要检查的串联组数组:

In [91]: chk_groups = np.array(['001002003','078079080'])

解决方案:

In [92]: df[df.groupby('UNIT')['MACHINE']
              .transform(lambda x: x.is_monotonic_increasing
                                   & np.in1d(x.unique().sum(),chk_groups))]
Out[92]:
    UNIT MACHINE
5   b222     001
6   b222     002
7   b222     002
8   b222     003
11    c2     078
12    c2     079
13    c2     080

【讨论】:

  • 此解决方案功能退出。唯一的问题是我需要手动定义 chk_set,这使得推广解决方案有点困难。
  • @sepideh,这有帮助吗:chk_set = set(df.MACHINE.unique()) ?
  • MaxU 这可能是完美的解决方案。
  • @MaxU 问题是在同一个数据框中有不同的可接受的 MACHINE 订单。准确地说,如果 MACHINE 排序是 [001, 002, 003] 或 [078, 079,080],则可以接受。如果我在开头定义一个集合,那么我必须找到所有这些可接受的 MACHINE 订单。
  • @sepideh,如果您的问题包含这些边缘情况,那将非常有帮助......
【解决方案2】:

使用diff + groupby + transformall

m = df.MACHINE\
      .astype(int)\
      .diff()\
      .fillna(0)\
      .isin([0, 1])\
      .groupby(df.UNIT)\
      .transform('all')

m

1    False
2    False
3    False
4    False
5     True
6     True
7     True
8     True
Name: MACHINE, dtype: bool

使用diff + isin 来检测行是否非递减(只有0 或1 的步长被认为是有效的)。

接下来,使用m,索引到df

df[m]

   UNIT MACHINE
5  b222     001
6  b222     002
7  b222     002
8  b222     003

【讨论】:

  • @Dark 我并没有真正关注 cmets。对此我深表歉意。
  • 检查一次,任何一组的所有值都为 001
  • @Dark 我把ID转换成整数,所以没问题。
  • 不,我不是在谈论整数。试一次。而不是不同的值,它们都是相同的值。
  • @Dark 哦,我现在明白了。这个想法是有序列的,我的功能只是检查单调性,所以它不是一个完美的!
【解决方案3】:

你可以这样做:

 df.groupby('UNIT')['MACHINE'].transform(lambda x : (x.astype(int).diff().fillna(0) >= 0).all())     
df[sample]

   UNIT  MACHINE
5  b222        1
6  b222        2
7  b222        2
8  b222        3

【讨论】:

  • 不错,很简洁。
  • 从过去 30 分钟开始,它就在我的内核中。我想知道为什么我不发布解决方案
  • 我喜欢这个解决方案,但我不确定它是否涵盖了这种情况:['001','003'] PS 已投票,希望它会得到修复 ;-)...
  • MaxU 也许它应该是 != 1,而不是小于 0 。固定。
  • @Dark,我认为差异应该是01,如果它是2,那么从001003002 之间存在差异
猜你喜欢
  • 2016-06-05
  • 1970-01-01
  • 1970-01-01
  • 2017-10-09
  • 2020-08-05
  • 1970-01-01
  • 2015-10-29
  • 2019-02-25
  • 1970-01-01
相关资源
最近更新 更多