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 !
3 Réponses :
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
cette solution fonctionne même si l'id est uuid et plus lisible!
Utilisez DataFrameGroupBy.diff avec Series.dt.days , compre par greatee comme 1 et filtre uniquement la colonne id par DataFrame.loc a >: users['date'] = pd.to_datetime(users['date'])
i = users.loc[users.groupby('id')['date'].diff().dt.days.gt(1), 'id'].tolist()
print (i)
[2]
for val in i:
print( f'id {val} might have non-consecutive dates')
id 2 might have non-consecutive dates
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).
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)
Un véritable exemple minimal reproductible dans une question pandas ... Mérite vraiment +1 :-)