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
4 Réponses :
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.
@ 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.
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)
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. :)
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')
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
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.