Сравните строки на основе сложных условий в pandas - PullRequest
1 голос
/ 13 января 2020

У меня есть фрейм данных, как показано ниже. Которые являются данными инспектора, поднимающего проблему.

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: среди дубликатов Нет один и тот же инспектор поднимает один и тот же тип проблемы в том же XY в течение 5 минут.

Ожидаемый результат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 Ответ

3 голосов
/ 13 января 2020

Ответ первой части соответствует только dupes 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

Для следующих двух решений используется 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
...