note.nkmk.me

pandasの時系列データのタイムゾーンを処理(tz_convert, tz_localize)

Date: 2018-08-14 / tags: Python, pandas, 時系列データ

pandasにおいて時系列データのタイムゾーンを処理するにはtz_convert(), tz_localize()を使う。

ここでは、まず単独の要素を例にtz_convert(), tz_localize()の処理内容を説明し、その後にデータ列に対する扱いを説明する。

  • 文字列からTimestamp型に変換: pd.to_datetime()
  • タイムゾーンを変換: tz_convert()
  • タイムゾーンを新たに設定: tz_localize()
  • タイムゾーンを削除する際の注意点
  • データ列に対する処理

pandas.DataFrame, pandas.Seriesを時系列データとして扱う方法については以下の記事を参照。

スポンサーリンク

文字列からTimestamp型に変換: pd.to_datetime()

文字列をTimestamp型に変換するにはpd.to_datetime()関数を使う。

以下のようにTのあとに時刻、さらにそのあとに+09:00というタイムゾーンの情報が含まれている文字列を例とする。このフォーマットはISO 8601で規定されている。

import pandas as pd

s = '2018-01-01T12:00+09:00'

print(s)
# 2018-01-01T12:00+09:00

print(type(s))
# <class 'str'>

これをpd.to_datetime()に渡すと、タイムゾーンが考慮されUTC(協定世界時)に変換された時刻のTimestamp型オブジェクトが返る。

Timestamp型オブジェクトはtz属性でタイムゾーンを取得できるが、この場合はなにも設定されていない。

ts = pd.to_datetime(s)

print(ts)
# 2018-01-01 03:00:00

print(type(ts))
# <class 'pandas._libs.tslibs.timestamps.Timestamp'>

print(ts.tz)
# None

pd.to_datetime()の引数utcTrueとするとタイムゾーンがUTCに設定される。

ts_utc = pd.to_datetime(s, utc=True)

print(ts_utc)
# 2018-01-01 03:00:00+00:00

print(ts_utc.tz)
# UTC

タイムゾーンを変換: tz_convert()

タイムゾーンを変換するにはtz_convert()メソッドを使う。

第一引数にタイムゾーン名を指定する。

ts_jst = ts_utc.tz_convert('Asia/Tokyo')

print(ts_jst)
# 2018-01-01 12:00:00+09:00

print(ts_jst.tz)
# Asia/Tokyo

タイムゾーンが変換されても同時刻を指しているので、エポック秒(UNIX time)はtz_convert()前後で変わらない。Timestamp型オブジェクトのエポック秒はvalue属性で取得できる。

print(ts_utc.value)
# 1514775600000000000

print(ts_jst.value)
# 1514775600000000000

print(ts_utc == ts_jst)
# True

他のタイムゾーンへの変換も同じ。

ts_pst = ts_utc.tz_convert('US/Pacific')

print(ts_pst)
# 2017-12-31 19:00:00-08:00

print(ts_pst.tz)
# US/Pacific

同じ時差を表す複数のタイムゾーン名が存在する。

print(ts_utc.tz_convert('America/Los_Angeles'))
# 2017-12-31 19:00:00-08:00

タイムゾーン名の一覧は以下のページなどを参照。

タイムゾーンを新たに設定: tz_localize()

タイムゾーン情報が設定されていないTimestamp型オブジェクトに新たにタイムゾーン情報を設定する場合、tz_convert()を使うとエラーになる。

print(ts)
# 2018-01-01 03:00:00

print(ts.tz)
# None

# print(ts.tz_convert('Asia/Tokyo'))
# TypeError: Cannot convert tz-naive Timestamp, use tz_localize to localize

新たにタイムゾーン情報を設定する場合はtz_localize()を使う。

ts_jst_localize = ts.tz_localize('Asia/Tokyo')

print(ts_jst_localize)
# 2018-01-01 03:00:00+09:00

print(ts_jst_localize.tz)
# Asia/Tokyo

tz_localize()はタイムゾーンの変換ではないので、同じオブジェクトに異なるタイムゾーンを設定すると、違う時刻を示すオブジェクトとなる。

print(ts.tz_localize('US/Pacific'))
# 2018-01-01 03:00:00-08:00

print(ts.tz_localize('Asia/Tokyo').value == ts.tz_localize('US/Pacific').value)
# False

すでにタイムゾーンが設定されているオブジェクトに対してtz_localize()で新たなタイムゾーンを上書きすることはできない。

print(ts_jst)
# 2018-01-01 12:00:00+09:00

# ts_jst.tz_localize('US/Pacific')
# TypeError: Cannot localize tz-aware Timestamp, use tz_convert for conversions

タイムゾーンを削除する際の注意点

タイムゾーン情報を削除したい場合は、tz_convert()またはtz_localize()の第一引数にNoneを指定すればよいが、それぞれ結果が異なる。

tz_convert()の第一引数にNoneを指定すると、UTCに変換された上でタイムゾーン情報が削除され、tz_localize()の第一引数にNoneを指定すると、現地時刻のままタイムゾーン情報が削除される。

print(ts_jst)
# 2018-01-01 12:00:00+09:00

print(ts_jst.tz)
# Asia/Tokyo

print(ts_jst.tz_convert(None))
# 2018-01-01 03:00:00

print(ts_jst.tz_localize(None))
# 2018-01-01 12:00:00

データ列に対する処理

これまでの例は単体の要素に対する処理だったが、pandas.DataFrameの列に対する場合は注意が必要。

以下のpandas.DataFrameを例とする。

df = pd.DataFrame({'date': ['2018-01-01T12:00+09:00',
                            '2018-01-02T00:00+09:00',
                            '2018-01-03T10:00-05:00',
                            '2018-01-03T19:00-08:00'],
                   'value': [0, 1, 2, 3]})

print(df)
#                      date  value
# 0  2018-01-01T12:00+09:00      0
# 1  2018-01-02T00:00+09:00      1
# 2  2018-01-03T10:00-05:00      2
# 3  2018-01-03T19:00-08:00      3

日時の文字列を含む列をpd.to_datetime()で変換すると、データ型(dtype)がdatetime64[ns]となる。引数utcを指定することも可能。いずれの場合もUTCの時刻に変換される。

print(pd.to_datetime(df['date']))
# 0   2018-01-01 03:00:00
# 1   2018-01-01 15:00:00
# 2   2018-01-03 15:00:00
# 3   2018-01-04 03:00:00
# Name: date, dtype: datetime64[ns]

print(pd.to_datetime(df['date'], utc=True))
# 0   2018-01-01 03:00:00+00:00
# 1   2018-01-01 15:00:00+00:00
# 2   2018-01-03 15:00:00+00:00
# 3   2018-01-04 03:00:00+00:00
# Name: date, dtype: datetime64[ns, UTC]

この列に対してtz_convert()tz_localize()でタイムゾーンを処理しようとするとエラーとなる。

# print(pd.to_datetime(df['date'], utc=True).tz_convert('Asia/Tokyo'))
# TypeError: index is not a valid DatetimeIndex or PeriodIndex

tz_convert(), tz_localize()が使えるのは列がインデックスに指定されている場合のみ。

df_ts = df.set_index('date')

print(df_ts)
#                         value
# date                         
# 2018-01-01T12:00+09:00      0
# 2018-01-02T00:00+09:00      1
# 2018-01-03T10:00-05:00      2
# 2018-01-03T19:00-08:00      3

print(df_ts.index)
# Index(['2018-01-01T12:00+09:00', '2018-01-02T00:00+09:00',
#        '2018-01-03T10:00-05:00', '2018-01-03T19:00-08:00'],
#       dtype='object', name='date')

print(pd.to_datetime(df_ts.index, utc=True))
# DatetimeIndex(['2018-01-01 03:00:00+00:00', '2018-01-01 15:00:00+00:00',
#                '2018-01-03 15:00:00+00:00', '2018-01-04 03:00:00+00:00'],
#               dtype='datetime64[ns, UTC]', name='date', freq=None)

print(pd.to_datetime(df_ts.index, utc=True).tz_convert('Asia/Tokyo'))
# DatetimeIndex(['2018-01-01 12:00:00+09:00', '2018-01-02 00:00:00+09:00',
#                '2018-01-04 00:00:00+09:00', '2018-01-04 12:00:00+09:00'],
#               dtype='datetime64[ns, Asia/Tokyo]', name='date', freq=None)

print(pd.to_datetime(df_ts.index, utc=True).tz_convert('Asia/Tokyo').tz_localize(None))
# DatetimeIndex(['2018-01-01 12:00:00', '2018-01-02 00:00:00',
#                '2018-01-04 00:00:00', '2018-01-04 12:00:00'],
#               dtype='datetime64[ns]', name='date', freq=None)

タイムゾーンを処理した上でインデックスに指定するには、indexを上書きすればOK。ここでは日本標準時に統一した上でタイムゾーン情報を削除している。

df_ts.index = pd.to_datetime(df_ts.index, utc=True).tz_convert('Asia/Tokyo').tz_localize(None)

print(df_ts)
#                      value
# date                      
# 2018-01-01 12:00:00      0
# 2018-01-02 00:00:00      1
# 2018-01-04 00:00:00      2
# 2018-01-04 12:00:00      3

print(df_ts.index)
# DatetimeIndex(['2018-01-01 12:00:00', '2018-01-02 00:00:00',
#                '2018-01-04 00:00:00', '2018-01-04 12:00:00'],
#               dtype='datetime64[ns]', name='date', freq=None)

print(df_ts['2018-01-04'])
#                      value
# date                      
# 2018-01-04 00:00:00      2
# 2018-01-04 12:00:00      3
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事