UTCのタイムスタンプ付きのデータがあります。このタイムスタンプのタイムゾーンを「US/Pacific」に変換し、階層インデックスとしてpandas DataFrameに追加します。タイムスタンプをインデックスとして変換することができました。 、ただし、列またはインデックスとしてDataFrameに追加しようとすると、タイムゾーンの書式設定が失われます。
>>> 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
これで、シリーズを直接変換しようとすると、エラーが発生します。
>>> 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
インデックスに変換すると、時系列として操作できます。インデックスに太平洋時間帯が追加されたことに注意してください。
>>> 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
ただし、タイムゾーンのフォーマットが失われるため、データフレームにインデックスを追加し直す際に問題が発生します。
>>> 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
インデックスは、変換された太平洋タイムゾーンではなくUTCタイムゾーンに戻っています。
タイムゾーンを変更し、インデックスとしてDataFrameに追加するにはどうすればよいですか?
これで修正されました。たとえば、次のように呼び出すことができます。
dataframe.tz_localize('UTC', level=0)
ただし、指定された例では2回呼び出す必要があります。 (つまり、各レベルに1回です。)
インデックスとして設定すると、自動的にインデックスに変換されます:
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
次に、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
次に、ラベル列をインデックスに追加できます。
うーん、これは間違いなくバグです!
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
ハッキングの回避策は、(datetime)レベルを直接変換することです(既に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
pandas 0.13.1で動作し、FrozenListを解決する他の回避策は問題を割り当てることができません:
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は、他の多くの条件でもtzを失います。
階層インデックスのインデックスレベルは不変である(FrozenListは不変である)ため、回避策は機能しないようです。
特異なインデックスから始めて追加することもできません。
Timestampとしてキャストし、to_datetime()によって返されたSeriesの各メンバーを変換するラムダ関数の作成も機能しません。
タイムゾーン対応シリーズを作成し、それらをデータフレームに挿入する/インデックスにする方法はありますか?
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)