J'ai besoin de calculer la différence entre deux colonnes pandas df qui contiennent des dates. J'ai besoin que la différence soit en jours et ne pas contenir les week-ends.

Je sais que je peux utiliser

 np.busday_count()

Pour y parvenir. Je sais aussi que pour que cette fonction fonctionne correctement, je devrai peut-être passer du type de données à datetime [64].

Mon problème est que mes données peuvent contenir NaT dans l'une ou l'autre des colonnes d'entrée pour certaines valeurs en raison de la source des données. np.nusday_count () n'aime pas ça.

Existe-t-il un moyen de calculer la différence entre deux colonnes contenant des dates, en jours, tout en excluant les week-ends, sans exécuter le calcul / renvoyer un blanc pour n'importe où où la colonne 1 ou 2 serait NaT et entrer les données dans une nouvelle colonne dans le dataframe. J'essaye sans succès depuis des heures.

Frustrant, si je n'avais pas à ignorer les week-ends, tout cela peut être fait très simplement en faisant simplement

df['Difference in Days'] = df['Column 2] - df['Column 1']

Pour ce que je veux réaliser, le df initial serait comme ça

Column 1       Column 2
07/10/20       09/10/20
07/10/20       12/10/20
NaT            09/10/20
07/10/20       NaT

Avec le dernier df comme ça

Column 1       Column 2    Difference in Days
07/10/20       09/10/20    2
07/10/20       12/10/20    3
NaT            09/10/20    Blank
07/10/20       NaT         Blank
3
Josh Fox 19 oct. 2020 à 18:02

3 réponses

Meilleure réponse

Vous pouvez créer une fonction personnalisée pour attraper le ValueError que vous obtenez en raison des valeurs NaT:

Commencez par transformer les valeurs au format datetime:

for i in df:
  df[i] = pd.to_datetime(df[i],infer_datetime_format=True,errors='coerce',dayfirst=True)

Fonction personnalisée avec la clause Try / Except pour intercepter les erreurs et renvoyer "Blank".

def diff_days(row):
  try:
    return np.busday_count(row['Column 1'].date(), row['Column 2'].date())
  except ValueError:
    return "Blank"

En utilisant apply:

df['Diff'] = df.apply(lambda x: diff_days(x),axis=1)

Retour:

    Column 1   Column 2   Diff
0 2020-07-10 2020-10-09     2
1 2020-07-10 2020-10-12     3 
2        NaT 2020-09-10  Blank
3 2020-07-10        NaT  Blank
3
Celius Stingher 19 oct. 2020 à 15:39

Je suppose que les deux colonnes ont été converties en datetime .

La première étape consiste à créer wrk - un DataFrame avec des lignes en dehors des week-ends et wrkV - les mêmes dates converties au tableau Numpy , également de datetime mais avec une résolution D :

wrk = df[df['Column 2'].dt.dayofweek.lt(5) & df['Column 1'].dt.dayofweek.lt(5)]
wrkV = wrk.values.astype('<M8[D]')

Et pour générer votre nouvelle colonne, exécutez:

df['Difference in Days'] = pd.Series(np.busday_count(wrkV[:, 0], wrkV[:, 1]), index=wrk.index)
df['Difference in Days'].fillna('Blank', inplace=True)

Le résultat est:

    Column 1   Column 2 Difference in Days
0 2020-10-07 2020-10-09                  2
1 2020-10-07 2020-10-12                  3
2        NaT 2020-10-09              Blank
3 2020-10-07        NaT              Blank
1
Valdi_Bo 19 oct. 2020 à 16:28

Voici une solution vectorisée: vous pouvez filtrer les NaT avant de les envoyer dans np.busday_count:

# If you haven't done so already, convert the columns to Timestamp
cols = ['Column 1', 'Column 2']
df[cols] = df[cols].apply(lambda col: pd.to_datetime(col, dayfirst=True, errors='coerce'))

# Look for the NaTs and remove them
mask = df[cols].notnull().all(axis=1)

# numpy does not like datetime64[ns] so convert to datetime64[D]
c1, c2 = df.loc[mask, cols].T.to_numpy('datetime64[D]')

# And the result
df['Diff'] = pd.Series(np.busday_count(c1, c2), index=mask[mask].index)
1
Code Different 19 oct. 2020 à 18:12