web-dev-qa-db-fra.com

Pandas rééchantillonner les données de série temporelle à 15 min et 45 min - en utilisant plusieurs index ou colonne

J'ai des données de série temporelle sous la forme d'un Pandas dataframe qui commence par des observations à 15 minutes après l'heure et 45 minutes après (intervalles de 30 minutes), puis change de fréquence à chaque minute. Je veux rééchantillonner les données de manière à ce qu'elles aient une fréquence régulière toutes les 30 minutes, à 15 heures et 45 heures pour l'ensemble de la trame de données.

J'ai pensé à deux façons d'y parvenir.
1. Il suffit de filtrer la trame de données pour toutes les observations à 15 min et 45 min, en utilisant les données de série chronologique sous forme de colonne dans la trame de données.
2. Réinitialisez l'index pour que les données de série chronologique fassent partie d'un multi-index (le 0ème niveau de l'index est la station météo, le 1er niveau est l'heure de l'observation) et utilisez le Pandas fonctionnalité de série temporelle date-heure telle que resample().

La trame de données d'origine, la météo, ressemble à ceci:

                  parsed_time           Pressure  Temp    Hum
Station   (index)   
Bow       1        2018-04-15 14:15:00   1012     20.0    87
          2        2018-04-15 14:45:00   1013     20.0    87
          3        2018-04-15 15:15:00   1012     21.0    87
          4        2018-04-15 15:45:00   1014     22.0    86
          5        2018-04-15 16:00:00   1015     22.0    86
          6        2018-04-15 16:01:00   1012     25.0    86
          7        2018-04-15 16:02:00   1012     25.0    86
Stratford 8        2018-04-15 14:15:00   1011     18.0    87
          9        2018-04-15 14:45:00   1011     18.0    87
          10       2018-04-15 15:15:00   1012     18.0    87
          11       2018-04-15 15:45:00   1014     19.0    86
          12       2018-04-15 16:00:00   1014     19.0    86
          13       2018-04-15 16:01:00   1015     19.0    86
          14       2018-04-15 16:02:00   1016     20.0    86
          15       2018-04-15 16:04:00   1016     20.0    86

Avec la méthode 1, j'ai le problème que mes opérations de sélection booléenne ne semblent pas fonctionner comme prévu. Par exemple

weather_test = weather[weather['parsed_time'].dt.minute == (15 & 45)]

donne des valeurs parsed_time comme ceci:

2018-04-15 14:13:00
2018-04-15 15:13:00

weather_test = weather[weather['parsed_time'].dt.minute == (15 | 45)]

entraîne des valeurs parsed_time comme ceci:

2018-04-15 14:47:00
2018-04-15 14:47:00

Je ne trouve rien dans les documents pour expliquer ce comportement. Ce que je veux, c'est la pression, la température, l'humidité par station aux heures suivantes:

2018-04-15 14:45:00    
2018-04-15 15:15:00  
2018-04-15 15:45:00
2018-04-15 16:15:00

etc.

Avec la méthode 2, j'ai pensé à rééchantillonner les données afin que les observations pour lesquelles j'ai des données minute par minute soient remplacées par la moyenne des 30 minutes précédentes. Cette fonctionnalité ne semble fonctionner que si la colonne parsed_time fait partie de l'index, j'ai donc utilisé le code suivant pour définir parsed_time dans le cadre d'un multi-index:

weather.set_index('parsed_time', append=True, inplace=True)
weather.index.set_names('station', level=0, inplace=True)
weather = weather.reset_index(level=1, drop=True)

pour finir avec une trame de données qui ressemble à ceci:

                                  Pressure   Temp    Hum
Station    parsed_time
Bow            2018-04-15 14:15:00    1012       20.0    87
           2018-04-15 14:45:00    1013       20.0    87
           2018-04-15 15:15:00    1012       21.0    87
           2018-04-15 15:45:00    1014       22.0    86
           2018-04-15 16:00:00    1015       22.0    86
           2018-04-15 16:01:00    1012       25.0    86
           2018-04-15 16:02:00    1012       25.0    86
Stratford  2018-04-15 14:15:00    1011       18.0    87
           2018-04-15 14:45:00    1011       18.0    87
           2018-04-15 15:15:00    1012       18.0    87
           2018-04-15 15:45:00    1014       19.0    86
           2018-04-15 16:00:00    1014       19.0    86
           2018-04-15 16:01:00    1015       19.0    86
           2018-04-15 16:02:00    1016       20.0    86
           2018-04-15 16:04:00    1016       20.0    86

Notez que l'échantillonnage des observations varie de toutes les 30 minutes à: 15 passé et: 45 passé à chaque minute (par exemple: 01,: 02,: 14, etc.), et il varie également selon la station - toutes les stations n'ont pas toutes les observations.

J'ai essayé ceci:

weather_test = weather.resample('30min', level=1).mean()

mais cela rééchantillonne sans décalage et supprime également le niveau de la station dans le multi-index.

Le résultat souhaité est le suivant:

                              Pressure   Temp    Hum
Station    parsed_time
Bow            2018-04-15 14:15:00    1012       20.0    87
           2018-04-15 14:45:00    1013       20.0    87
           2018-04-15 15:15:00    1012       21.0    87
           2018-04-15 15:45:00    1014       22.0    86
           2018-04-15 16:15:00    1013       24.0    86
Stratford  2018-04-15 14:15:00    1011       18.0    87
           2018-04-15 14:45:00    1011       18.0    87
           2018-04-15 15:15:00    1012       18.0    87
           2018-04-15 15:45:00    1014       19.0    86
           2018-04-15 16:15:00    1015       19.5    86

où les observations minute par minute ont été rééchantillonnées comme la moyenne sur un intervalle de 30 minutes à: 15 et: 45 après l'heure.

Garder la station comme niveau dans le multi-index est essentiel. Je ne peux pas utiliser l'index de temps comme un index à lui seul car les valeurs se répètent pour chaque station (et ne sont pas uniques).

Toute l'aide a été appréciée car je tourne en rond avec celui-ci depuis un moment maintenant. Merci!

J'ai regardé pas mal de messages précédents, notamment: filtre booléen utilisant une valeur d'horodatage sur une trame de données en Python
Comment arrondir la colonne datetime au quart d'heure le plus proche
et: Rééchantillonnage d'un pandas dataframe avec multi-index contenant des séries temporelles ce qui semble un peu compliqué pour quelque chose qui devrait être assez simple ...

et les documents: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.resample.html Merci!

7
LucieCBurgess

À partir de votre avant-dernière trame de données (après avoir utilisé weather.reset_index(Station, inplace=True)):

                           Station  Pressure  Temp   Hum
parsed_time                                         
2018-04-15 14:15:00        Bow    1012.0  20.0  87.0
2018-04-15 14:45:00        Bow    1013.0  20.0  87.0
2018-04-15 15:15:00        Bow    1012.0  21.0  87.0
2018-04-15 15:45:00        Bow    1014.0  22.0  86.0
2018-04-15 16:00:00        Bow    1015.0  22.0  86.0
2018-04-15 16:01:00        Bow    1012.0  25.0  86.0
2018-04-15 16:02:00        Bow    1012.0  25.0  86.0
2018-04-15 14:15:00  Stratford    1011.0  18.0  87.0
2018-04-15 14:45:00  Stratford    1011.0  18.0  87.0
2018-04-15 15:15:00  Stratford    1012.0  18.0  87.0
2018-04-15 15:45:00  Stratford    1014.0  19.0  86.0
2018-04-15 16:00:00  Stratford    1014.0  19.0  86.0
2018-04-15 16:01:00  Stratford    1015.0  19.0  86.0
2018-04-15 16:02:00  Stratford    1016.0  20.0  86.0
2018-04-15 16:04:00  Stratford    1016.0  20.0  86.0

vous pouvez utiliser une combinaison de groupby et resample:

res = weather.groupby('Station').resample('30min').mean().reset_index('Station')

Par défaut, resample choisit les intervalles de bac [16:00, 16:30) et [16:30, 17:00). Comme vous l'avez déjà remarqué, l'index de temps est rééchantillonné sans décalage, mais vous pouvez l'ajouter par la suite en utilisant DateOffset:

res.index = res.index + pd.DateOffset(minutes=15)

ce qui donne:

                           Station  Pressure  Temp   Hum
parsed_time                                         
2018-04-15 14:15:00        Bow   1012.00  20.0  87.0
2018-04-15 14:45:00        Bow   1013.00  20.0  87.0
2018-04-15 15:15:00        Bow   1012.00  21.0  87.0
2018-04-15 15:45:00        Bow   1014.00  22.0  86.0
2018-04-15 16:15:00        Bow   1013.00  24.0  86.0
2018-04-15 14:15:00  Stratford   1011.00  18.0  87.0
2018-04-15 14:45:00  Stratford   1011.00  18.0  87.0
2018-04-15 15:15:00  Stratford   1012.00  18.0  87.0
2018-04-15 15:45:00  Stratford   1014.00  19.0  86.0
2018-04-15 16:15:00  Stratford   1015.25  19.5  86.0

Vous pouvez également spécifier le décalage directement dans la méthode de rééchantillonnage:

weather.groupby('Station').resample('30min', loffset=pd.Timedelta('15min')).mean()
2
chuni0r

Je n'ai pas vos données, je ne peux donc pas l'examiner directement, mais essayez la syntaxe suivante pour l'option que vous appelez l'option 1:

weather_test = weather[(weather['parsed_time'].dt.minute == 15) | (weather['parsed_time'].dt.minute == 45)]
1
BossaNova

Si vous commencez sans index (sauf pour un index de ligne), vous pouvez effectuer les opérations suivantes:

# Create a rounded timestamp
df['parsed_time_rounded'] = (df['parsed_time'] - pd.Timedelta('15min')).dt.round('30min') + pd.Timedelta('15min')
# Group by the station, and the rounded timestamp instead of the raw timestamp
df.groupby(['Station', 'parsed_time_rounded']).mean()
1
PMende