在 Python 中使用 any()

Using any() in Python

在下面的数据框中,我想删除 ITEM_IDVALUE 具有相同值的行对,但其中一个具有 TYPE == 'O' (对于 'outbound'),另一个有 TYPE == 'I'(对于 'inbound',稍后出现):

        Date        ITEM_ID TYPE VALUE
236656  2012-02-28  ECE240  O    1.0
242962  2012-03-02  ECE240  O    1.0
248720  2012-03-06  ECE240  O    1.0 (remove - out)
226194  2012-03-19  ECE240  I    1.0 (remove - in)
263320  2012-03-20  ECE240  O    1.0 (remove - out)
242977  2012-03-24  ECE240  I    1.0 (remove - in)
209713  2012-03-31  ECE240  O    1.0
279806  2012-04-06  ECE240  O    1.0
277213  2012-04-08  ECE240  O    1.0
288865  2012-04-17  ECE240  O    3.0
290041  2012-04-20  ECE240  O    2.0 (remove - out)
136730  2012-04-22  ECE240  I    2.0 (remove - in)
295236  2012-04-24  ECE240  O    1.0
292597  2012-04-30  ECE240  O    1.0
313503  2012-05-14  ECE240  O    1.0
314786  2012-05-15  ECE240  O    2.0
318277  2012-05-20  ECE240  O    1.0 (remove - out)
328787  2012-06-01  ECE240  O    2.0
2134    2012-06-16  ECE240  I    1.0 (remove - in)
343138  2012-06-17  ECE240  O    2.0
343139  2012-06-22  ECE240  O    1.0
346935  2012-06-29  ECE240  O    1.0
215777  2012-07-06  ECE240  O    1.0
356292  2012-07-06  ECE240  O    2.0
261989  2012-07-21  ECE240  O    2.0

代码:

df  = df.sort_values(by = ['ITEM_ID ', 'Date'])
df1 = df.groupby(['ITEM_ID ','VALUE']).filter(lambda x : ~(x['TYPE'].eq('I') & x['TYPE'].shift().eq('O')).any())
df1

返回:

        Date        ITEM_ID TYPE    VALUE
288865  2012-04-17  ECE240  O       3.0

这不是我想要的,因为我只希望删除 4 对(在上面的 df 中标记)。 预期输出:

        Date        ITEM_ID TYPE VALUE
236656  2012-02-28  ECE240  O    1.0
242962  2012-03-02  ECE240  O    1.0


209713  2012-03-31  ECE240  O    1.0
279806  2012-04-06  ECE240  O    1.0
277213  2012-04-08  ECE240  O    1.0
288865  2012-04-17  ECE240  O    3.0
 

295236  2012-04-24  ECE240  O    1.0
292597  2012-04-30  ECE240  O    1.0
313503  2012-05-14  ECE240  O    1.0
314786  2012-05-15  ECE240  O    2.0

328787  2012-06-01  ECE240  O    2.0

343138  2012-06-17  ECE240  O    2.0
343139  2012-06-22  ECE240  O    1.0
346935  2012-06-29  ECE240  O    1.0
215777  2012-07-06  ECE240  O    1.0
356292  2012-07-06  ECE240  O    2.0
261989  2012-07-21  ECE240  O    2.0

在 Python 文档中指出 any():

Return True if any element of the iterable is true. If the iterable is empty, return False.

我认为它删除了行的所有“组”,其中 TYPE==I 行和所有其他行 VALUE 相同且 TYPE==O。我怎样才能为每个“组”只删除一对(即,对于 TYPE==I 的每一行,只有 TYPE==O 前面的一行)?


[编辑 1]

我也试过:

df  = df.sort_values(by = ['ITEM_ID', 'Date'])
df1 = df.groupby(['ITEM_ID','VALUE']).filter(lambda x : ~(x['TYPE'].eq('I') & (x['TYPE'].shift().eq('O'))))
df1

发现错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-935-65eda184ce24> in <module>
      1 df= df.sort_values(by = ['ITEM_ID', 'Date'])
----> 2 df1= df.groupby(['ITEM_ID','VALUE']).filter(lambda x : ~(x['TYPE'].eq('I') & (x['TYPE'].shift().eq('O'))))
      3 df1

~\Anaconda3\lib\site-packages\pandas\core\groupby\generic.py in filter(self, func, dropna, *args, **kwargs)
   1594                 # non scalars aren't allowed
   1595                 raise TypeError(
-> 1596                     f"filter function returned a {type(res).__name__}, "
   1597                     "but expected a scalar bool"
   1598                 )

TypeError: filter function returned a Series, but expected a scalar bool

[编辑 2]

对于以下数据框:

        Date        ITEM_ID TYPE    VALUE
342874  2012-06-18  ECE240  O       1.0 (not removed - out)
342415  2012-06-18  ECE240  O       25.0
325718  2012-06-18  ECE240  O       1.0 (not removed - out)
334488  2012-06-18  ECE240  O       1.0 (not removed - out)
342412  2012-06-18  ECE240  O       25.0
341634  2012-06-18  ECE240  O       9.0
341996  2012-06-19  ECE240  O       2.0 (remove - out)
341747  2012-06-19  ECE240  O       1.0 (remove - out)
272185  2012-06-24  ECE240  I       1.0 (remove - in)
219     2012-06-24  ECE240  I       1.0 (not removed - in)
6896    2012-06-24  ECE240  I       2.0 (remove - in)
351560  2012-06-24  ECE240  O       1.0 (remove - out)
312636  2012-06-26  ECE240  I       1.0 (remove - in)
2376    2012-06-30  ECE240  I       1.0 (not removed - in)
350922  2012-07-02  ECE240  O       1.0 (remove - out)
270589  2012-07-09  ECE240  I       4.0
331689  2012-07-15  ECE240  I       1.0 (remove - in)
299912  2012-07-23  ECE240  I       1.0 (not removed - in) 
212418  2012-07-23  ECE240  I       3.0
3992    2012-07-24  ECE240  I       2.0
388937  2012-08-10  ECE240  O       10.0
124596  2012-08-18  ECE240  I       1.0 
368945  2012-08-19  ECE240  O       12.0
368944  2012-08-19  ECE240  O       6.0
239581  2012-08-24  ECE240  I       4.0

一些也满足条件的行没有被删除(见上面的数据框),因为它们不在 TYPE==I 行的正前方。要清除包括这些行在内的所有行,我想我可以重复 运行 代码,直到这些行用完为止。我想知道是否有其他方法可以做到这一点?

使用 filtergroupby 不起作用的原因是 pandas 期望每个组有一个布尔值 return。如果该值为真,则 whoel 组将被删除。

相反,您在这里要做的是删除组中的个别行。一个可能的解决方案是简单地使用 apply 创建一个布尔掩码:

mask = df.sort_values('Date')\
  .groupby(['ITEM_ID', 'VALUE'])['TYPE']\
  .apply(lambda x: ((x == 'O') & (x.shift(-1) == 'I')) | (x == 'I') & (x.shift(1) == 'O'))
df.loc[~mask]

这将 return 预期的结果。