Blow Up by Black Swan

PythonーpandasでUNIXタイムスタンプを解析し、特定のタイムゾーンの時刻へと変換する

このブログでも何度かPythonのパッケージpandasですが、今回はUNIXタイムスタンプから特定のタイムゾーンの時間への変換の流れについて学習したので、それについてまとめようと思います。

まずUNIXタイムとは何かということですが、コンピュータでの時刻表現の一種で、協定世界時(ロンドンの時刻)の1970年1月1日0時0分からの経過秒数で時間を表すものです。

UNIX時間ーWikipedia

多くのシステムでこれを軸に時刻が表示されるようになっており、APIなどで情報を取るときにも「~年~月~月~:~」という表記でなく、単に「1344554586」のような数字(または文字列)で返ってくることもあります。今回、まさにAPIからとった時の情報が単なる文字列で返ってきた四苦八苦したのが、今回の学習をした理由です。

1. 全体の流れ

まず、全体までの変換の流れは以下のようになります。時刻オブジェクトがインデックスとなる場合と一つの列として処理する場合の2つの場合に分けています。色々とパターンをやってみるとpandasでは時刻データの取り扱いがインデックスの方が対処しやすいように設計されているように感じたため、このような場合分けをしました。

<流れ>
unixタイムスタンプを表す文字列
-> to_datetimeメソッドで解析かつUTCを設定(->pandas.timestampオブジェクト)

1 インデックスで処理する場合
  -> DataFrameオブジェクト自体にtz_convertメソッドを適用
  -> 完了

2 一つの列で処理する場合
  -> リスト内包表記で各要素を取り出し、tz_convert()でタイムゾーンを変換
  -> 完了

違い: インデックスであればDataFrameオブジェクト全体にtz_convertメソッドを適用すれば良いが、一つの列として処理する場合は、
それぞれのバリューを取り出してtz_convertを適用する必要がある

最初の部分で説明したように、違いは全体に適用するか個別に適用するかどうかという点のみです。

2. 実際のコード

ここからは実際のコードになります。

2-1. インデックスで利用する場合

インデックスで対処する場合のコードは以下になります。ただし、時刻をインデックスにするにはset_indexメソッドを使ったりもできます。今回は、read_csvメソッドでデータを読み込んだ時点で時刻部分をインデックスに設定しています。なお、coinchartsというサイトのAPIからコインチェックすの過去の取引情報をとってきているのですが、何も設定しないと2万件のデータが返ってくるので、返されるデータ量が少なくなるよう調整しています。

#インデックスに設定された時刻オブジェクトの取り扱い
import pandas as pd
import time
csv_file=pd.read_csv("http://api.bitcoincharts.com/v1/trades.csv?symbol=coincheckJPY&start="
                       + str(now_time-10),               #データ量調整用の文字列
                       names=("time","price","amount"),  #カラムの名称リスト
                       index_col=0)                      #インデックスに設定
#->DataFrame型(下が各要素のデータ型)
    # index -> str型(unixtime)
    # price -> numpy.float64
    # amount -> numpy.float64


#UNIXタイプスタンプの解析
csv_file.index = pd.to_datetime(csv_file.index,  #args:対象ファイル
                                utc=True,        #TrueでTZ情報を持たせられる
                                unit="s")        #解析する時刻の単位。解析対象のデータに依存


#東京の時刻に変換 -> DataFrameオブジェクト自体にtz_convertメソッドを適用
csv_file.tz_convert('Asia/Tokyo')

csv_file

そして、取得し、pandasのオブジェクト(DataFrameオブジェクト)で生成されたデータの中にある、UNIXタイムスタンプをpd.to_datetimeメソッドで解析します。pandasのto_datetimeメソッドは非常に汎用性が高く、今回もunit="s"という引数を設定することで正確に時刻を解析してくれています。UNIXタイムスタンプでなく、一般的な時刻フォーマットで表示されているデータについても解析できるようです。また、この解析時点でutc=Trueと設定して、タイムゾーン情報を持たせています。

※ ここでタイムゾーン情報を付与できない場合、tz_localizeメソッドを利用して、一旦タイムゾーン情報を付与する必要があるので、この点もto_datetimeメソッドが便利だと感じるところです。

そして、最後にタイムゾーン情報をtz_convertメソッドで変更します。この時の1番のポイントがDataFrameオブジェクト全体にこのメソッドを適用しているところです。これで、設定したタイムゾーンで時刻が表示されるようになります。戻り値は以下のようなDataFrameオブジェクトになります。

 priceamount
time  
2018-08-19 02:03:27+09:00702457.00.005000
2018-08-19 02:03:27+09:00702497.00.010000
2018-08-19 02:03:27+09:00702497.00.010000
2018-08-19 02:03:27+09:00702501.00.030000
2018-08-19 02:03:27+09:00702502.00.033797
2018-08-19 02:03:29+09:00702558.00.005000
2018-08-19 02:03:29+09:00702505.00.021022
2018-08-19 02:03:29+09:00702383.00.010000
2018-08-19 02:03:29+09:00702379.00.136178
2018-08-19 02:03:43+09:00702349.00.005000
2018-08-19 02:03:44+09:00702251.00.005000
2018-08-19 02:03:45+09:00702160.00.005000
2018-08-19 02:03:50+09:00702001.00.005000
2018-08-19 02:03:50+09:00702001.00.005000
2018-08-19 02:03:50+09:00702001.00.027400
2018-08-19 02:03:50+09:00702001.00.108701
2018-08-19 02:03:50+09:00701996.00.010000
2018-08-19 02:03:50+09:00702001.00.177999
2018-08-19 02:03:50+09:00702488.00.020600
2018-08-19 02:03:50+09:00702499.00.005000
2018-08-19 02:03:50+09:00702652.00.081917
2018-08-19 02:03:51+09:00702652.00.099980
2018-08-19 02:03:51+09:00702652.00.099978
2018-08-19 02:03:51+09:00702251.00.005000
2018-08-19 02:04:05+09:00702001.00.011492
2018-08-19 02:04:05+09:00702001.00.003508
2018-08-19 02:04:10+09:00702176.00.005000
2018-08-19 02:04:11+09:00702249.00.005000
2018-08-19 02:04:24+09:00702373.00.005000
2018-08-19 02:04:25+09:00702378.00.024400
2018-08-19 02:04:26+09:00702383.00.010000
2018-08-19 02:04:34+09:00702499.00.005000
2018-08-19 02:04:38+09:00702622.00.005000
2018-08-19 02:04:38+09:00702416.00.005000
2018-08-19 02:04:38+09:00702331.00.019100
2018-08-19 02:04:42+09:00702424.00.010000
2018-08-19 02:04:43+09:00702419.00.005000
2018-08-19 02:04:44+09:00702423.00.005000
2018-08-19 02:04:45+09:00702423.00.010000
2018-08-19 02:04:45+09:00702428.00.121028
2018-08-19 02:04:47+09:00702428.00.100046
2018-08-19 02:04:49+09:00702428.00.369026
2018-08-19 02:04:55+09:00702525.00.005000
2018-08-19 02:04:58+09:00702380.00.005000
2018-08-19 02:05:15+09:00702555.00.010000

以上が時刻データがインデックスの場合の処理コードです。

2-2. 一つの列として処理する場合

次は一つの列で時刻情報を保持し、処理する場合です。ときにはこのようにデータを格納しておく方が便利なこともあると思います。以下が具体的なコードです。

import pandas as pd
import time
now_time = int(time.time())
#実験用DataFrameの生成(実験しやすいようにデータ量を調整している)
csv_file=pd.read_csv("http://api.bitcoincharts.com/v1/trades.csv?symbol=coincheckJPY&start="
                       + str(now_time-10),
                       names=("time","price","amount"))
#->DataFrame型(下が各要素のデータ型)
    #index -> 指定せず(数列)
    # unixtime -> str
    # price -> numpy.float64
    # amount -> numpy.float64

    
#time列の解析 -> TZがUTCに設定された時刻オブジェクトに変換(tz_time列)
csv_file['tz_time'] = pd.to_datetime(csv_file["time"],  #args:対象ファイル
                                      utc=True,         #TrueでTZ情報を持たせられる
                                      unit="s")         #解析する時刻の単位。解析対象のデータに依存

#tz_time列の時刻を東京時刻に変換 -> tz_time列の各要素にアクセス
csv_file["tz_time"] = [x.tz_convert('Asia/Tokyo') for x in csv_file.tz_time]

csv_file

最初のデータ取得は基本同じになりますが、時刻データ(str型のUNIXタイムスタンプ)を今回はインデックスに設定していません(index_col引数を設定していません)。その次も同様で、to_datetimeメソッドで時刻を解析しています。そして、最後にtz_convertメソッドを利用します。

なんども書いていますが、この時の処理がインデックスに時刻が設定されている場合との1番の違いになりますが、時刻データの列のバリューに個別にアクセスし、このメソッドを適用しているところです。今回は、リスト内包表記を利用して一文で処理を完結させています。戻り値は以下のようなDataFrameオブジェクトです。

 timepriceamounttz_time
01534611807702457.00.0050002018-08-19 02:03:27+09:00
11534611807702497.00.0100002018-08-19 02:03:27+09:00
21534611807702497.00.0100002018-08-19 02:03:27+09:00
31534611807702501.00.0300002018-08-19 02:03:27+09:00
41534611807702502.00.0337972018-08-19 02:03:27+09:00
51534611809702558.00.0050002018-08-19 02:03:29+09:00
61534611809702505.00.0210222018-08-19 02:03:29+09:00
71534611809702383.00.0100002018-08-19 02:03:29+09:00
81534611809702379.00.1361782018-08-19 02:03:29+09:00

3. まとめ

以上が今回学習した点です。個別か全体化という違いですが、この点は案外悩ましく解決するのに地味に時間がかかりました。インターネットにも的確に欲しい情報はなく、同じ悩みを持つ方には有用ではないかなと思います。

読んでくださった方、ありがとうございました。

4. 参考サイト等

以前書いたpandaの記事も貼っておきます。