4
votes

Les pandas vérifient la continuité des séries chronologiques

J'ai un DataFrame avec un index mensuel. Je veux examiner si l'indice de temps est continu sur la fréquence mensuelle et, si possible, les endroits où il devient discontinu, par exemple. a certains «mois d'intervalle» entre deux mois qui sont adjacents dans son index.

Exemple: les données de séries chronologiques suivantes

1964-07-31    100.00
1964-08-31     98.81
1964-09-30    101.21
1964-11-30    101.42
1964-12-31    101.45
1965-03-31     91.49
1965-04-30     90.33
1965-05-31     85.23
1965-06-30     86.10
1965-08-31     84.26

manque 1964/10, 1965 / [1 , 2,7].


0 commentaires

3 Réponses :


2
votes

En supposant un dataframe comme dans votre entrée (les premières colonnes sont des dates), vous pouvez faire ce qui suit:

3    1964-10-31
6    1965-01-31
7    1965-02-28
12   1965-07-31
dtype: datetime64[ns]

Sortie

all = pd.Series(data=pd.date_range(start=df[0].min(), end=df[0].max(), freq='M'))
mask = all.isin(df[0].values)
print(all[~mask])

L'idée est de créer une plage de dates avec une fréquence mensuelle à partir de la première date jusqu'à la dernière date, puis de vérifier ces valeurs par rapport à votre première colonne.


1 commentaires

J'aime beaucoup cette réponse, car elle est flexible car elle ne repose pas sur un index mais peut plutôt prendre n'importe quelle colonne.



4
votes

Utilisez asfreq par mois pour ajouter des dates-heures manquantes, filtrer sur une nouvelle série et si nécessaire regrouper par année avec créer une liste de mois:

s = pd.Series({pd.Timestamp('1964-07-31 00:00:00'): 100.0, 
               pd.Timestamp('1964-08-31 00:00:00'): 98.81, 
               pd.Timestamp('1964-09-01 00:00:00'): 101.21, 
               pd.Timestamp('1964-11-02 00:00:00'): 101.42, 
               pd.Timestamp('1964-12-05 00:00:00'): 101.45,
               pd.Timestamp('1965-03-31 00:00:00'): 91.49, 
               pd.Timestamp('1965-04-30 00:00:00'): 90.33, 
               pd.Timestamp('1965-05-31 00:00:00'): 85.23, 
               pd.Timestamp('1965-06-30 00:00:00'): 86.1, 
               pd.Timestamp('1965-08-31 00:00:00'): 84.26})
print (s)
1964-07-31    100.00
1964-08-31     98.81
1964-09-01    101.21
1964-11-02    101.42
1964-12-05    101.45
1965-03-31     91.49
1965-04-30     90.33
1965-05-31     85.23
1965-06-30     86.10
1965-08-31     84.26
dtype: float64

#convert all months to first day
s.index = s.index.to_period('m').to_timestamp()
#MS is start month frequency
s = s.asfreq('MS')
s1 = pd.Series(s[s.isnull()].index)
print (s1)
0   1964-10-01
1   1965-01-01
2   1965-02-01
3   1965-07-01
dtype: datetime64[ns]

Configuration :

s = pd.Series({pd.Timestamp('1964-07-31 00:00:00'): 100.0, 
               pd.Timestamp('1964-08-31 00:00:00'): 98.81, 
               pd.Timestamp('1964-09-30 00:00:00'): 101.21, 
               pd.Timestamp('1964-11-30 00:00:00'): 101.42, 
               pd.Timestamp('1964-12-31 00:00:00'): 101.45,
               pd.Timestamp('1965-03-31 00:00:00'): 91.49, 
               pd.Timestamp('1965-04-30 00:00:00'): 90.33, 
               pd.Timestamp('1965-05-31 00:00:00'): 85.23, 
               pd.Timestamp('1965-06-30 00:00:00'): 86.1, 
               pd.Timestamp('1965-08-31 00:00:00'): 84.26})

print (s)
1964-07-31    100.00
1964-08-31     98.81
1964-09-30    101.21
1964-11-30    101.42
1964-12-31    101.45
1965-03-31     91.49
1965-04-30     90.33
1965-05-31     85.23
1965-06-30     86.10
1965-08-31     84.26
dtype: float64

EDIT:

Si les dates ne sont pas toujours le dernier jour des mois:

s = s.asfreq('m')
s1 = pd.Series(s[s.isnull()].index)
print (s1)
0   1964-10-31
1   1965-01-31
2   1965-02-28
3   1965-07-31
Name: 0, dtype: datetime64[ns]

out = s1.dt.month.groupby(s1.dt.year).apply(list)
print (out)
0
1964         [10]
1965    [1, 2, 7]
Name: 0, dtype: object


5 commentaires

Ok, maintenant je l'ai


Merci. Malheureusement, .asfreq repose sur les dates étant le dernier jour d'un mois, ce qui n'est cependant pas garanti dans mon problème. Par exemple, je peux avoir des dates comme 2001/1/15 , 2001/2/1 , 2001/3/31 , 2001/5/14 et je souhaite toujours identifier 2001/4 comme manquant. Le fait est que je ne me soucie pas (et ne peux pas) de la date, mais seulement du mois. Existe-t-il un ajustement facile de votre code qui peut le faire fonctionner dans ce cas?


@Vim - J'ai une idée, mais testez-la plutôt d'abord.


@jezrael, vous allez certainement le craquer :-)


@Vim - La solution est de le convertir en premier jour du mois, puis d'utiliser MS pour la fréquence de début du mois, comme s.index = s.index.to_period ('m'). To_timestamp () < / code> puis s = s.asfreq ('MS')



3
votes

Je fais souvent cela en calculant l'écart entre chaque valeur d'index.

times_gaps[times_gaps> threshold]

Ensuite, vous pouvez les tracer:

times_gaps.plot()

S'il y a sont des lacunes, vous verrez rapidement où. S'il n'y a pas d'écart, vous verrez une ligne horizontale droite.

Vous pouvez également sélectionner les intervalles de temps en faisant:

times_gaps = df.index - df.index.shift(1)


2 commentaires

Merci mais ce n'est peut-être pas ce que je veux. J'aimerais voir une approche programmatique pour qu'elle ne repose pas sur une inspection humaine.


alors vous pouvez sélectionner le temps d'index, lorsque le seuil> 32 jours. Vous aurez une liste de temps de halètement et la taille de ces lacunes.