比较大熊猫中基于行的复杂条件

时间:2020-01-13 12:12:33

标签: pandas pandas-groupby

我有一个数据框,如下所示。 这是检查员提出问题的数据。

Iss_id Ins_ID    XY      Duplicate      Raised_Date               Type
1      1        (2,5)    Yes            2019-10-07 10:27:50        A
2      1        (2,5)    Yes            2019-10-07 10:27:50        A
3      2        (2,5)    No             2019-10-07 10:27:50        A
4      2        (3,5)    No             2019-10-07 10:29:50        A
5      2        (2,5)    No             2019-10-07 10:29:50        A
6      2        (2,5)    No             2019-10-07 10:29:50        A
7      3        (2,5)    No             2019-10-07 11:27:50        A
8      2        (2,5)    No             2019-10-07 11:27:50        B
9      3        (2,5)    No             2019-10-07 10:27:50        C
10     2        (2,5)    Yes            2019-10-07 10:27:50        A

从上面我想根据条件找出实际重复项

条件1:在重复编号中,匹配所有其他行。也就是说,同一检查人员在相同的XY位置同时提出相同的问题类型。

预期的输出1:

Iss_id Ins_ID    XY      Duplicate      Raised_Date               Type
5      2        (2,5)    No             2019-10-07 10:29:50        A
6      2        (2,5)    No             2019-10-07 10:29:50        A

条件2:在重复的编号中,同一检查员在5分钟内以相同的XY提出相同的问题类型。

预期的输出2:

Iss_id Ins_ID    XY      Duplicate      Raised_Date               Type
3      2        (2,5)    No             2019-10-07 10:27:50        A
5      2        (2,5)    No             2019-10-07 10:29:50        A
6      2        (2,5)    No             2019-10-07 10:29:50        A

条件3:在重复的编号中,在相同的XY处,在120分钟内键入相同的问题。 (检查员可以相同,也可以不同)。

预期的输出3:

Iss_id Ins_ID    XY      Duplicate      Raised_Date               Type
3      2        (2,5)    No             2019-10-07 10:27:50        A
5      2        (2,5)    No             2019-10-07 10:29:50        A
6      2        (2,5)    No             2019-10-07 10:29:50        A
7      3        (2,5)    No             2019-10-07 11:27:50        A

1 个答案:

答案 0 :(得分:3)

第一部分答案是仅匹配重复的No列(如果不存在Yes行:

df['Raised_Date'] = pd.to_datetime(df['Raised_Date'])

df1 = df[df.drop(['Duplicate','Iss_id'], 1).duplicated(keep=False)]
mask = (df1.assign(Duplicate = df1['Duplicate'].eq('No'))
           .groupby(df1.columns.difference(['Duplicate','Iss_id']).tolist())['Duplicate']
           .transform('all'))

df1 = df1[mask]
print (df1)
   Iss_id  Ins_ID     XY Duplicate         Raised_Date Type
4       5       2  (2,5)        No 2019-10-07 10:29:50    A
5       6       2  (2,5)        No 2019-10-07 10:29:50    A

对于接下来的2个解决方案,使用merge_asof函数和可能的公差参数,并通过参数by检查同一列:

df21 = df[df['Duplicate'].eq('No')].sort_values('Raised_Date').copy()
df22 = df1.drop_duplicates().sort_values('Raised_Date').copy()
#print (df21)
#print (df22)

df2 = (pd.merge_asof(df21, df22, 
                     on='Raised_Date', 
                     by=['Ins_ID','XY','Type'], 
                     tolerance=pd.Timedelta(5 * 60, unit='s'),
                     direction='forward',
                     suffixes=('','_'))
         .dropna(subset=['Duplicate_'])
         .drop(['Duplicate_','Iss_id_'], axis=1))


print (df2)
   Iss_id  Ins_ID     XY Duplicate         Raised_Date Type
0       3       2  (2,5)        No 2019-10-07 10:27:50    A
3       5       2  (2,5)        No 2019-10-07 10:29:50    A
4       6       2  (2,5)        No 2019-10-07 10:29:50    A

类似的解决方案,只需要direction='forward'direction='backward'(默认值,因此省略),合并列并过滤不丢失的行:

df31 = (pd.merge_asof(df21, df22, 
                     on='Raised_Date', 
                     by=['XY','Type'], 
                     tolerance=pd.Timedelta(120 * 60, unit='s'),
                      direction='forward',
                     suffixes=('','_'))
         )
df32 = (pd.merge_asof(df21, df22, 
                     on='Raised_Date', 
                     by=['XY','Type'], 
                     tolerance=pd.Timedelta(120 * 60, unit='s'),
                     suffixes=('','_'))
         )

df3 = df21[df31['Duplicate_'].fillna(df32['Duplicate_']).notna().to_numpy()]
print (df3)
   Iss_id  Ins_ID     XY Duplicate         Raised_Date Type
2       3       2  (2,5)        No 2019-10-07 10:27:50    A
4       5       2  (2,5)        No 2019-10-07 10:29:50    A
5       6       2  (2,5)        No 2019-10-07 10:29:50    A
6       7       3  (2,5)        No 2019-10-07 11:27:50    A