删除有条件的行(多索引情况)

Delete rows with conditions (Multi-Index case)

我是 Stack Overflow 的新手,我有这个数据集:

df=pd.DataFrame({'ID': {0: 4, 1: 4, 2: 4, 3: 88, 4: 88, 5: 323, 6: 323},
         'Step': {0: 'A', 1: 'Bar', 2: 'F', 3: 'F', 4: 'Bar', 5: 'F', 6: 'A'},
         'Num': {0: 38, 1: 38, 2: 38, 3: 320, 4: 320, 5: 433, 6: 432},
         'Date': {0: '2018-08-02',
          1: '2018-12-02',
          2: '2019-03-02',
          3: '2017-03-02',
          4: '2018-03-02',
          5: '2020-03-04',
          6: '2020-02-03'},
         'Occurence': {0: 3, 1: 3, 2: 3, 3: 2, 4: 2, 5: 2, 6: 2}})

变量'ID'和'Step'是Multi-index.

我想做两件事:

第一个:

如果'Num'对于相同的'ID'不同,则删除该ID的行。

其次:

对于相同的ID,步骤'F'应该是最后一步(最近的日期)。如果不是,则删除此ID的行。

我遇到了一些困难,因为命令 df['Step'] 和 df['ID'] 不工作('ID' 和 'Step'最近 groupby() ).

的多索引原因

我试过在

上找到的 groupby(level=0)

但是我还有一些困难。

有人可以帮我吗?

预期输出:

df=pd.DataFrame({'ID': {0: 4, 1: 4, 2: 4},
         'Step': {0: 'A', 1: 'Bar', 2: 'F'},
         'Num': {0: 38, 1: 38, 2: 38},
         'Date': {0: '2018-08-02',
          1: '2018-12-02',
          2: '2019-03-02',
         'Occurence': {0: 3, 1: 3, 2: 3}})

ID 88 已被删除,因为步骤 'F' 不是最后一步(具有最新日期)。 ID 323 已被删除,因为 Num 433!=Num 432.

不知道我理解的对不对。 但是你可以试试这个

import os
import pandas as pd 

sheet = pd.read_excel(io="you_file", sheet_name='sheet_name', na_filter=False, header=0 )

list_objects          = []

for index,row in sheet.iterrows():
    if (row['ID'] != index):
        list_objects.append(row)

list_objects 将是 dict

的列表
  • 按列对数据框进行分组 ID
  • Transform Num 列使用 nunique 标识唯一值
  • 使用 last 转换 Step 列以检查每组的最后一个值是否为 F
  • 使用逻辑和组合布尔掩码并过滤行
g = df.groupby('ID')
m = g['Num'].transform('nunique').eq(1) & g['Step'].transform('last').eq('F')
print(df[m])

   ID Step  Num        Date  Occurence
0   4    A   38  2018-08-02          3
1   4  Bar   38  2018-12-02          3
2   4    F   38  2019-03-02          3

groupbyfilter 的替代方法,但效率可能低于上述方法

df.groupby('ID').filter(lambda g: g['Step'].iloc[-1] == 'F' and g['Num'].nunique() == 1)

   ID Step  Num        Date  Occurence
0   4    A   38  2018-08-02          3
1   4  Bar   38  2018-12-02          3
2   4    F   38  2019-03-02          3

注意:如果 IDStep 是 MultiIndex,您必须在使用上述建议的解决方案之前 reset 索引。

既然你说ID和Step都在索引中,那么我们可以这样:

df1[df1.sort_values('Date').groupby('ID')['Num']\
       .transform(lambda x: (x.nunique() == 1) & 
                            (x.index.get_level_values(1)[-1] == 'F'))]

输出:

         Num        Date  Occurence
ID Step                            
4  A      38  2018-08-02          3
   Bar    38  2018-12-02          3
   F      38  2019-03-02          3

如何?

  • 首先按'Date'
  • 对数据框进行排序
  • 然后按 ID 对数据帧进行分组
  • 获取每组数据帧并使用 'Num' 列在布尔序列中进行转换,我们 首先获取 'Num' 中唯一元素的数量 组,如果该数字等于 1,则您知道在该组中 所有 'Num' 都相同,那就是 True
  • 其次,我们得到 MultiIndex 的内层 (level=1) 和 我们使用 [-1] 索引检查最后一个值,如果该值是 等于 'F' 那么也有一个 True

使用 groupby 查找出现 1 次的行。我根据 groupby 结果的 ID return 删除数据框中的行。我排除了一次出现的 ID,不包括删除中的 ID。

df=pd.DataFrame({'ID': {0: 4, 1: 4, 2: 4, 3: 88, 4: 88, 5: 323, 6: 323},
     'Step': {0: 'A', 1: 'Bar', 2: 'F', 3: 'F', 4: 'Bar', 5: 'F', 6: 'A'},
     'Num': {0: 38, 1: 38, 2: 38, 3: 320, 4: 320, 5: 433, 6: 432},
     'Date': {0: '2018-08-02',
      1: '2018-12-02',
      2: '2019-03-02',
      3: '2017-03-02',
      4: '2018-03-02',
      5: '2020-03-04',
      6: '2020-02-03'},
     'Occurence': {0: 3, 1: 3, 2: 3, 3: 2, 4: 2, 5: 2, 6: 2}})
df.set_index(['ID','Step'],inplace=True)
print(df)
print("If 'Num' is different for the same 'ID', then delete the rows of this ID.")

 #exclude id with single occurrences
 grouped=df.groupby([df.index.get_level_values(0)]).size().eq(1)
 labels=set([x for x,y in (grouped[grouped.values==True].index)])

 filter=[x for x in df.index.get_level_values(0) if x not in labels]

 grouped = df[df.index.get_level_values(0).isin(filter)].groupby([df.index.get_level_values(0),'Num']).size().eq(1)

 labels=set([x for x,y in (grouped[grouped.values==True].index)])
 if len(labels)>0:
     df = df.drop(labels=labels, axis=0,level=0)    
 print(df)

输出:

  Num        Date  Occurence
  ID Step                            
  4  A      38  2018-08-02          3
     Bar    38  2018-12-02          3
     F      38  2019-03-02          3
  88 F     320  2017-03-02          2
     Bar   320  2018-03-02          2