it-swarm.com.de

Ändern Sie die Zeitzone der Datum/Uhrzeit-Spalte in Pandas und fügen Sie sie als hierarchischen Index hinzu

Ich habe Daten mit einem Zeitstempel in UTC. Ich möchte die Zeitzone dieses Zeitstempels in 'US/Pacific' umwandeln und als hierarchischen Index einem Pandas-DataFrame hinzufügen. Ich konnte den Zeitstempel als Index konvertieren, er verliert jedoch die Formatierung der Zeitzone, wenn ich versuche, ihn wieder in den DataFrame einzufügen, entweder als Spalte oder als 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

Wenn ich jetzt versuche, die Serie direkt zu konvertieren, stoße ich auf einen Fehler.

>>> 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

Wenn ich es in einen Index konvertiere, kann ich es als Zeitserie bearbeiten. Beachten Sie, dass der Index jetzt die Pazifikzeitzone hat.

>>> 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

Nun habe ich jedoch Probleme beim Hinzufügen des Index zum Datenrahmen, da er seine Zeitzonenformatierung verliert:

>>> 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

Sie werden feststellen, dass der Index wieder in der UTC-Zeitzone und nicht in der konvertierten pazifischen Zeitzone liegt.

Wie kann ich die Zeitzone ändern und einem DataFrame als Index hinzufügen?

26
Erik Shilts

Inzwischen wurde dies behoben. Zum Beispiel können Sie jetzt anrufen:

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

Sie müssen es jedoch zweimal für das gegebene Beispiel aufrufen. (Das heißt, einmal für jedes Level.)

9
mweerden

Wenn Sie ihn als Index festlegen, wird er automatisch in einen Index konvertiert:

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

Dann mache den 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

Und dann können Sie die Beschriftungsspalte an den Index anhängen:

Hmmm das ist definitiv ein Fehler!

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

Eine gehackte Problemumgehung besteht darin, die Ebene (datetime) direkt zu konvertieren (wenn es bereits ein MultiIndex ist):

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
22
Andy Hayden

Eine andere Problemumgehung, die in Pandas 0.13.1 funktioniert und die FrozenList löst, kann keinem Problem zugewiesen werden:

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

MultiIndex kämpft viel mit diesem Problem und verliert tz auch unter vielen anderen Bedingungen.

1
Mark Horvath

Die Problemumgehung scheint nicht zu funktionieren, da die Indexniveaus eines hierarchischen Indexes unveränderlich scheinen (FrozenList ist unveränderlich).

Mit einem einzigen Index zu beginnen und anzufügen funktioniert ebenfalls nicht.

Das Erstellen einer Lambda-Funktion, die als Zeitstempel wirkt und jedes von to_datetime () zurückgegebene Mitglied der Serie konvertiert, funktioniert ebenfalls nicht.

Gibt es eine Möglichkeit, Zeitzonen-fähige Serien zu erstellen und sie dann in einen Datenrahmen einzufügen/sie zu einem Index zu machen? 

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
ivrin