Changer le fuseau horaire de la colonne date-heure dans pandas et ajouter comme index hiérarchique

j'ai des données avec un horodatage en UTC. J'aimerais convertir le fuseau horaire de cette mise à jour en 'US/Pacific' et l'ajouter comme un index hiérarchique à une base de données pandas. J'ai été capable de convertir l'horodatage comme un Index, mais il perd le formatage du fuseau horaire quand j'essaie de l'ajouter de nouveau dans la DataFrame, soit comme une colonne ou comme un index.

>>> import pandas as pd
>>> dat = pd.DataFrame({'label':['a', 'a', 'a', 'b', 'b', 'b'], 'datetime':['2011-07-19 07:00:00', '2011-07-19 08:00:00', '2011-07-19 09:00:00', '2011-07-19 07:00:00', '2011-07-19 08:00:00', '2011-07-19 09:00:00'], 'value':range(6)})
>>> dat.dtypes
#datetime    object
#label       object
#value        int64
#dtype: object

Maintenant, si j'essaie de convertir la Série, j'ai une erreur.

>>> times = pd.to_datetime(dat['datetime'])
>>> times.tz_localize('UTC')
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#  File "/Users/erikshilts/workspace/schedule-detection/python/pysched/env/lib/python2.7/site-packages/pandas/core/series.py", line 3170, in tz_localize
#    raise Exception('Cannot tz-localize non-time series')
#Exception: Cannot tz-localize non-time series

si je le convertis en Index, alors je peut le manipuler comme une série temporelle. Notez que l'index a maintenant le fuseau horaire du Pacifique.

>>> times_index = pd.Index(times)
>>> times_index_pacific = times_index.tz_localize('UTC').tz_convert('US/Pacific')
>>> times_index_pacific
#<class 'pandas.tseries.index.DatetimeIndex'>
#[2011-07-19 00:00:00, ..., 2011-07-19 02:00:00]
#Length: 6, Freq: None, Timezone: US/Pacific

cependant, j'ai maintenant des problèmes à ajouter l'index à la dataframe car il perd son formatage timezone:

>>> dat_index = dat.set_index([dat['label'], times_index_pacific])
>>> dat_index
#                                      datetime label  value
#label                                                      
#a     2011-07-19 07:00:00  2011-07-19 07:00:00     a      0
#      2011-07-19 08:00:00  2011-07-19 08:00:00     a      1
#      2011-07-19 09:00:00  2011-07-19 09:00:00     a      2
#b     2011-07-19 07:00:00  2011-07-19 07:00:00     b      3
#      2011-07-19 08:00:00  2011-07-19 08:00:00     b      4
#      2011-07-19 09:00:00  2011-07-19 09:00:00     b      5

vous remarquerez que l'index est de retour sur le fuseau horaire UTC au lieu du fuseau horaire Pacific converti.

Comment puis-je changer le fuseau horaire et l'ajouter comme index à une DataFrame?

23
demandé sur Erik Shilts 2013-06-18 05:11:03

4 réponses

à ce jour, cela a été corrigé. Par exemple, vous pouvez maintenant appeler:

dataframe.tz_localize('UTC', level=0)

Vous aurez à appeler deux fois pour l'exemple donné, si. (I. e., une fois pour chaque niveau.)

8
répondu mweerden 2016-07-29 12:18:11

Si vous le définissez comme l'index, il est automatiquement converti en Indice:

In [11]: dat.index = pd.to_datetime(dat.pop('datetime'), utc=True)

In [12]: dat
Out[12]:
                    label  value
datetime
2011-07-19 07:00:00     a      0
2011-07-19 08:00:00     a      1
2011-07-19 09:00:00     a      2
2011-07-19 07:00:00     b      3
2011-07-19 08:00:00     b      4
2011-07-19 09:00:00     b      5

alors faites le tz_localize:

In [12]: dat.index = dat.index.tz_localize('UTC').tz_convert('US/Pacific')

In [13]: dat
Out[13]:
                          label  value
datetime
2011-07-19 00:00:00-07:00     a      0
2011-07-19 01:00:00-07:00     a      1
2011-07-19 02:00:00-07:00     a      2
2011-07-19 00:00:00-07:00     b      3
2011-07-19 01:00:00-07:00     b      4
2011-07-19 02:00:00-07:00     b      5

Et puis vous pouvez ajouter l'étiquette de la colonne de l'index:

Hmmm c'est définitivement un bug!

In [14]: dat.set_index('label', append=True).swaplevel(0, 1)
Out[14]:
                           value
label datetime
a     2011-07-19 07:00:00      0
      2011-07-19 08:00:00      1
      2011-07-19 09:00:00      2
b     2011-07-19 07:00:00      3
      2011-07-19 08:00:00      4
      2011-07-19 09:00:00      5

une solution de contournement est de convertir directement le niveau (datetime) (alors qu'il S'agit déjà d'un MultiIndex):

In [15]: dat.index.levels[1] = dat.index.get_level_values(1).tz_localize('UTC').tz_convert('US/Pacific')

In [16]: dat1
Out[16]:
                                 value
label datetime
a     2011-07-19 00:00:00-07:00      0
      2011-07-19 01:00:00-07:00      1
      2011-07-19 02:00:00-07:00      2
b     2011-07-19 00:00:00-07:00      3
      2011-07-19 01:00:00-07:00      4
      2011-07-19 02:00:00-07:00      5
19
répondu Andy Hayden 2013-06-18 20:55:08

une autre solution qui fonctionne dans pandas 0.13.1, et résout le problème FrozenList ne peut pas être assignée:

index.levels = pandas.core.base.FrozenList([
    index.levels[0].tz_localize('UTC').tz_convert(tz),
    index.levels[1].tz_localize('UTC').tz_convert(tz)
])

aux prises avec ce problème, MultiIndex perd tz dans beaucoup d'autres conditions aussi.

1
répondu Mark Horvath 2014-07-14 20:08:13

la solution ne semble pas fonctionner car les niveaux d'index d'un index hiérarchique semblent immuables (FrozenList est immuable).

en commençant par un index singulier et en ajoutant ne fonctionne pas non plus.

créer une fonction lambda qui projette comme horodatage et convertit chaque membre de la série retourné par to_datetime() ne fonctionne pas non plus.

y a-t-il un moyen de créer des séries de conscience de fuseau horaire et de les insérer dans une dataframe/en faire une index?

joined_event_df = joined_event_df.set_index(['pandasTime'])
joined_event_df.index = joined_event_df.index.get_level_values(1).tz_localize('UTC').tz_convert('US/Central')
# we have tz-awareness above this line
joined_event_df = joined_event_df.set_index('sequence', append = True)
# we lose tz-awareness in the index as soon as we add another index
joined_event_df = joined_event_df.swaplevel(0,1)
0
répondu ivrin 2014-05-30 00:11:45