1
votes

vérifier si chaque utilisateur a des dates consécutives dans un dataframe python 3 pandas

Imaginez qu'il y ait un dataframe:

it should print id 2 might have non-consecutive dates

voici la commande create dataframe:

df['index_col'] = df.index

for id in df['id'].unique():

    # create an empty QA dataframe

    column_names = ["Delta"]
    df_qa = pd.DataFrame(columns = column_names)

    df_qa['Delta']=(df['index_col'] - df['index_col'].shift(1))

    if (df_qa['Delta'].iloc[1:] != 1).any() is True:

        print('id ' + id +' might have non-consecutive dates')

        # doesn't print any account => Each Customer's Daily Balance has Consecutive Dates
    break

Comment pourrais-je vérifier si chaque identifiant a dates consécutives ou pas? Je utilise le "shift" idée ici mais cela ne semble pas fonctionner:

Calcul du décalage horaire entre deux lignes

import pandas as pd
import numpy as np

users=pd.DataFrame(
                [
                {'id':1,'date':'01/01/2019', 'transaction_total':-1, 'balance_total':102},
                {'id':1,'date':'01/02/2019', 'transaction_total':-2, 'balance_total':100},
                {'id':1,'date':'01/03/2019', 'transaction_total':np.nan, 'balance_total':100},
                {'id':1,'date':'01/04/2019', 'transaction_total':np.nan, 'balance_total':100},
                {'id':1,'date':'01/05/2019', 'transaction_total':-4, 'balance_total':np.nan},
                {'id':2,'date':'01/01/2019', 'transaction_total':-2, 'balance_total':200},
                {'id':2,'date':'01/02/2019', 'transaction_total':-2, 'balance_total':100},
                {'id':2,'date':'01/04/2019', 'transaction_total':np.nan, 'balance_total':100},
                {'id':2,'date':'01/05/2019', 'transaction_total':-4, 'balance_total':96}  
                ]
                )

Résultat idéal:

   id        date  balance_total  transaction_total
0   1  01/01/2019          102.0               -1.0
1   1  01/02/2019          100.0               -2.0
2   1  01/03/2019          100.0                NaN
3   1  01/04/2019          100.0                NaN
4   1  01/05/2019           96.0               -4.0
5   2  01/01/2019          200.0               -2.0
6   2  01/02/2019          100.0               -2.0
7   2  01/04/2019          100.0                NaN
8   2  01/05/2019           96.0               -4.0

Merci !


1 commentaires

Un véritable exemple minimal reproductible dans une question pandas ... Mérite vraiment +1 :-)


3 Réponses :


2
votes

Utilisez groupby et diff:

df["date"] = pd.to_datetime(df["date"],format="%m/%d/%Y")

df["difference"] = df.groupby("id")["date"].diff()

print (df.loc[df["difference"]>pd.Timedelta(1, unit="d")])

#
   id       date  transaction_total  balance_total difference
7   2 2019-01-04                NaN          100.0     2 days


1 commentaires

cette solution fonctionne même si l'id est uuid et plus lisible!




1
votes

La première étape consiste à analyser date:

users ['date'] = pd.to_datetime (users.date) .

Ajoutez ensuite une colonne décalée sur les colonnes id et date:

0       NaT
1    1 days
2    1 days
3    1 days
4    1 days
5   -4 days
6    1 days
7    2 days
8    1 days
dtype: timedelta64[ns]

La différence entre les colonnes date et date_shifted est de intérêt:

>>> users.date - users.date_shifted

users['id_shifted'] = users.id.shift(1)
users['date_shifted'] = users.date.shift(1)

Vous pouvez maintenant interroger le DataFrame pour ce que vous veulent:

utilisateurs [(users.id_shifted == users.id) & (users.date_shifted - users.date! = np.timedelta64 (days = 1))]

C'est-à-dire des lignes consécutives du même utilisateur avec une différence de date! = 1 jour.

Cette solution suppose que les données sont triées par (id, date).


3 commentaires

Merci! J'ai eu une erreur de ValueError: impossible de définir un Timedelta avec un non-timedelta dans la dernière ligne users [(users.id_shifted == users.id) & (users.date_shifted - users. date! = np.timedelta64 (days = 1))] essaie toujours de le comprendre


je vois ce qui s'est passé. le vrai id ici est uuid au lieu d'entiers. Des pensées? @Freek Wiekmeijer


Nous ne faisons que deux choses avec la colonne id : shift (qui est insensible au dtype) et comparer id == id_shifted (qui est aussi un problème insensible à dtype car les deux colonnes ont le même dtype)