3
votes

Marquer les doublons en fonction du décalage horaire entre les lignes successives

Il y a des transactions dupliquées dans un dataframe bancaire (DF). L'ID correspond aux ID client. Une transaction dupliquée est un multi-balayage, où un fournisseur facture accidentellement la carte d'un client plusieurs fois dans un court laps de temps (2 minutes ici).

    ID  Dollar  transactionDateTime     Duplicated?
0   111     1   2016-01-08 19:04:50     No
1   111     3   2016-01-29 19:03:55     No
2   111     1   2016-01-08 19:05:50     Yes
3   111     10  2016-01-08 20:08:50     No
4   222     25  2016-01-08 19:04:50     No
5   222     8   2016-02-08 19:04:50     No
6   222     25  2016-03-08 19:04:50     No
7   333     9   2016-01-08 19:04:50     Yes
8   333     20  2016-03-08 19:05:53     No
9   333     9   2016-01-08 19:03:20     Yes
10  333     9   2016-01-08 19:02:15     No
11  111     10  2016-02-08 20:08:50     No

Je souhaite ajouter une colonne à mon dataframe, qui reconnaît les transactions dupliquées (le montant en dollars du même identifiant client doit être le même et la date de transaction doit être inférieure à 2 minutes). Veuillez considérer la première transaction comme "normale".

DF = pd.DataFrame({'ID': ['111', '111', '111','111', '222', '222', '222', '333', '333', '333', '333','111'],'Dollar': [1,3,1,10, 25, 8, 25,9,20, 9, 9,10],'transactionDateTime': ['2016-01-08 19:04:50', '2016-01-29 19:03:55', '2016-01-08 19:05:50', '2016-01-08 20:08:50', '2016-01-08 19:04:50', '2016-02-08 19:04:50', '2016-03-08 19:04:50', '2016-01-08 19:04:50', '2016-03-08 19:05:53', '2016-01-08 19:03:20', '2016-01-08 19:02:15', '2016-02-08 20:08:50']})
DF['transactionDateTime'] = pd.to_datetime(DF['transactionDateTime'])

    ID  Dollar  transactionDateTime
0   111     1   2016-01-08 19:04:50
1   111     3   2016-01-29 19:03:55
2   111     1   2016-01-08 19:05:50
3   111     10  2016-01-08 20:08:50
4   222     25  2016-01-08 19:04:50
5   222     8   2016-02-08 19:04:50
6   222     25  2016-03-08 19:04:50
7   333     9   2016-01-08 19:04:50
8   333     20  2016-03-08 19:05:53
9   333     9   2016-01-08 19:03:20
10  333     9   2016-01-08 19:02:15
11  111     10  2016-02-08 20:08:50


3 commentaires

dépend aussi de l'ID?


oui, l'identifiant client doit être le même.


Vos données ne sont pas triées par transactionDateTime, il ne semble donc pas que votre sortie soit correcte.


4 Réponses :


4
votes

IIUC, vous pouvez groupby et diff pour vérifier si la différence entre les transactions successives est inférieure à 120 secondes:

df['Duplicated?'] = (df.sort_values(['transactionDateTime'])
                       .groupby(['ID', 'Dollar'], sort=False)['transactionDateTime']
                       .diff()
                       .dt.total_seconds()
                       .lt(120))
df

     ID  Dollar transactionDateTime  Duplicated?
0   111       1 2016-01-08 19:04:50        False
1   111       3 2016-01-29 19:03:55        False
2   111       1 2016-01-08 19:05:50         True
3   111     100 2016-01-08 20:08:50        False
4   222      25 2016-01-08 19:04:50        False
5   222       8 2016-02-08 19:04:50        False
6   222      25 2016-03-08 19:04:50        False
7   333       9 2016-01-08 19:04:50         True
8   333      20 2016-03-08 19:05:53        False
9   333       9 2016-01-08 19:03:20         True
10  333       9 2016-01-08 19:02:15        False
11  111     100 2016-02-08 20:08:50        False

Remarque que vos données ne sont pas triées, vous devez donc d'abord les trier pour obtenir un résultat significatif.


4 commentaires

@ P.J oui parce que vos données ne sont pas triées, le marquage des doublons n'a pas de sens à moins que vous ne les triiez d'abord.


@ P.J Si vous supprimez l'appel .sort_values ​​, vous obtenez le résultat que vous avez montré ci-dessus. Quelle IMO est FAUX.


Oui, j'en ai besoin en premier. Merci encore.


@ cs95 Je crois que vous devez également inclure le Dollar dans le groupby, afin de le considérer comme un doublon.



3
votes

Vous pouvez utiliser:

   customerID  Dollar transactionDateTime Duplicated?
0         111       1 2016-01-08 19:04:50          No
1         111       3 2016-01-29 19:03:55          No
2         111       1 2016-01-08 19:05:50         Yes
3         111     100 2016-01-08 20:08:50          No
4         222      25 2016-01-08 19:04:50          No
5         222       8 2016-02-08 19:04:50          No
6         222      25 2016-03-08 19:04:50          No
7         333       9 2016-01-08 19:04:50          No
8         333      20 2016-03-08 19:05:53          No
9         333       9 2016-01-08 19:03:20         Yes
10        333       9 2016-01-08 19:02:15         Yes
11        111     100 2016-02-08 20:08:50          No

m=(DF.groupby('customerID')['transactionDateTime'].diff()/ np.timedelta64(1, 'm')).le(2)
DF['Duplicated?']=np.where((DF.Dollar.duplicated()&m),'Yes','No')
print(DF)


2 commentaires

Je dois d'abord trier les temps? pour ID = 333 le premier arrivé 9 $ n'est pas un doublon, mais le deuxième et le troisième 9 $ dans l'ordre du temps sont dupliqués.


@ P.J en fonction de la sortie attendue oui un soring à temps est nécessaire. :) cs95 vous a couvert. :)



2
votes

Nous pouvons d'abord marquer les paiements en double dans votre colonne Dollar . Puis marquez par client si la différence est inférieure à 2 minutes:

   customerID  Dollar transactionDateTime Duplicated?
0         111       1 2016-01-08 19:04:50          No
1         111       1 2016-01-08 19:05:50         Yes
2         111     100 2016-01-08 20:08:50          No
3         111       3 2016-01-29 19:03:55          No
4         111     100 2016-02-08 20:08:50          No
5         222      25 2016-01-08 19:04:50          No
6         222       8 2016-02-08 19:04:50          No
7         222      25 2016-03-08 19:04:50          No
8         333       9 2016-01-08 19:02:15          No
9         333       9 2016-01-08 19:03:20         Yes
10        333       9 2016-01-08 19:04:50         Yes
11        333      20 2016-03-08 19:05:53          No

DF.sort_values(['customerID', 'transactionDateTime'], inplace=True)

m1 = DF.groupby('customerID', sort=False)['Dollar'].apply(lambda x: x.duplicated())
m2 = DF.groupby('customerID', sort=False)['transactionDateTime'].diff() <= pd.Timedelta(2, unit='minutes')

DF['Duplicated?'] = np.where(m1 & m2, 'Yes', 'No')


0 commentaires

2
votes

J'ai fait pd.Timedelta (minutes = 2) pour comparer avec le diff()

m2 = pd.Timedelta(minutes=2)    
DF['dup'] = DF.sort_values('transactionDateTime').groupby(['Dollar','ID']).transactionDateTime.diff().abs().le(m2).astype(int)


Out[272]:
    Dollar   ID transactionDateTime  dup
0        1  111 2016-01-08 19:04:50    0
1        3  111 2016-01-29 19:03:55    0
2        1  111 2016-01-08 19:05:50    1
3      100  111 2016-01-08 20:08:50    0
4       25  222 2016-01-08 19:04:50    0
5        8  222 2016-02-08 19:04:50    0
6       25  222 2016-03-08 19:04:50    0
7        9  333 2016-01-08 19:04:50    1
8       20  333 2016-03-08 19:05:53    0
9        9  333 2016-01-08 19:03:20    1
10       9  333 2016-01-08 19:02:15    0
11     100  111 2016-02-08 20:08:50    0


0 commentaires