7839

雑草魂エンジニアブログ

【Pandas】UNIX time ⇆ Timestamp、formatなど日付操作のまとめ

Pythonでのデータ分析を効率的に行うためのライブラリ「Pandas」の日付操作で先日少しハマってしまった。自分への戒めとして、Pandasの日付操作をまとめたので、紹介する。

まず、Pandas で処理する場合だけでなく、何をプログラムするにしても、どんな「型」が定義されているのかを確認することはきほんの「き」であると実感した。これは、こういう感じのタイプだろうな、ぐらいの曖昧な理解をしてると、私のように見事にハマる可能性が高いのでご注意ください。

今回は、データ分析でよくある CSV データを読み込む場合を想定する。CSV データには、UNIX時間が含まれるデータがあることとする。

pandas.read_csv — pandas 1.0.5 documentation

pandas.read_csv を利用することで、pandas.DataFrame として読み込むことができる。(Pandas には2つの主要なデータ構造があり、Series が1次元のデータ、DataFrame が2次元のデータである。)

>>> import pandas as pd
>>> df = pd.read_csv('./testcsv')
>>> print(df)
   timestamp
0 1594589999
1 1594632119
2 1594810919

読み込んだ時点では、列の dtype は Object 型であり、各要素は str 型である。

文字列からTimestamp型に変換

まず、日付の操作をするために、UNIX time の文字列データを日付のデータに変換する。

pandas.to_datetime — pandas 1.0.5 documentation

pandas.to_datetime() 関数を使うことで、日時を表した文字列の列データを、列の dtype が datetime64[ns] 型、各要素が Timestamp 型である列データに変換することができる。(Timestamp 型はPythonの標準ライブラリ datetime の datetime 型を継承し拡張した型である。)

様々なパラメータを設定可能であるが、以下は注意しておくべきかと思われる。(設定していないことで、予期していない変換になることがある。)

params default 説明
utc None 文字列にtimezoneがきちんと入っていない場合、UTCに変換され、tz属性がNoneとなる。タイムゾーンが設定されていないので、注意が必要である。UNIX timeの文字列の場合は、utc=Trueを必ず設定することをお勧めする。
format None 標準的な書式でない場合は、書式文字列を指定する。
例)%Y/%m/%d %H:%M:%S
書式化コード
unit 'ns' UNIX timeが「ns」でない場合には s, ms の指定をする必要がある。
# オプションパラメータを設定しなかった場合
>>> x = pd.to_datetime(df['datetime'])
>>> print(x)
0   1970-01-01 00:00:01.594589999
1   1970-01-01 00:00:01.594632119
2   1970-01-01 00:00:01.594810919
Name: datetime, dtype: datetime64[ns]
# 単位のオプションパラメータを追加した場合
>>> x = pd.to_datetime(df['datetime'], unit='s')
>>> print(x)
0   2020-07-12 21:39:59
1   2020-07-13 09:21:59
2   2020-07-15 11:01:59
Name: datetime, dtype: datetime64[ns]
# 単位とタイムゾーンのオプションパラメータを追加した場合
>>> x = pd.to_datetime(df['datetime'], unit='s', utc=True)
>>> print(x)
0   2020-07-12 21:39:59+00:00
1   2020-07-13 09:21:59+00:00
2   2020-07-15 11:01:59+00:00
Name: datetime, dtype: datetime64[ns, UTC]

タイムゾーンの確認をしたい場合は、以下の通りである。(Pandas で列全体を一括処理したい場合は、 dtアクセサリ を使う。 )

>>> x.dt.tz
<UTC>

UTCJST に変換する

次に、時間表記はやはり日本時間にしたいので、タイムゾーンを日本( Asia/Tokyo )に設定する。

pandas.Series.dt.tz_convert — pandas 1.0.5 documentation

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

>>> x = x.dt.tz_convert('Asia/Tokyo')
>>> print(x)
0   2020-07-13 06:39:59+09:00
1   2020-07-13 18:21:59+09:00
2   2020-07-15 20:01:59+09:00
Name: datetime, dtype: datetime64[ns, Asia/Tokyo]

もしタイムゾーンの設定を忘れていた場合は、以下のエラーが発生する。

>>> x = x.dt.tz_convert('Asia/Tokyo')
TypeError: Cannot convert tz-naive timestamps, use tz_localize to localize

この場合には、エラー文にも記載があるように、タイムゾーン情報が設定されていない(naiveな)データに新たにタイムゾーンを設定するためのメソッド tz_localize() を使う。

pandas.Series.tz_localize — pandas 1.0.5 documentation

今回の例では、UNIX time を使っているので、UTCに設定する。(to_datetime() でパラメータ utc=True を忘れた場合に、まずは UTC に設定して、タイムゾーンを東京に変更する必要がある。)

>>> x = x.dt.tz_localize('UTC').dt.tz_convert('Asia/Tokyo')
>>> print(x)
0   2020-07-13 06:39:59+09:00
1   2020-07-13 18:21:59+09:00
2   2020-07-15 20:01:59+09:00
Name: datetime, dtype: datetime64[ns, Asia/Tokyo]

Timestampから文字列にフォーマットする

Timestamp 型を所定の形式の文字列に変換したい場合は、Python標準ライブラリの datetime 型と同様に strftime() で任意のフォーマットの文字列に変換することが可能である。列データを一括で変換することがほとんどだと思うので、dtアクセサリを使う。

pandas.Series.dt.strftime — pandas 1.0.5 documentation

>>> x = x.dt.strftime('%Y/%m/%d %H:%M')
>>> print(x)
0    2020/07/13 06:39
1    2020/07/13 18:21
2    2020/07/15 20:01
Name: datetime, dtype: object

Python の日付文字列フォーマット

TimestampからUNIX timeに変換する

Timestamp 型を UNIX time にしたい場合は、Timestamp 型のメソッド timestamp() を使う。ただし、timestamp()Timestamp 型にはあるが、dtアクセサには用意されていないため、列での一括処理を行う場合は、map() を使う。

>>> print(x.map(lambda x: x.timestamp()))
0    1.594590e+09
1    1.594632e+09
2    1.594811e+09
Name: datetime, dtype: float64

timestamp() の返り値は、浮動小数float 型となっている。整数にしたい場合は、 int() を用いる。

>>> print(x.map(lambda x: int(x.timestamp())))
0    1594589999
1    1594632119
2    1594810919
Name: datetime, dtype: int64

まとめ

Pandas の日付操作に関して、整理を行なった。基本的な操作であるが、どのデータを操作しているのかをしっかりと区別して、メソッドの使い分けが必要である。

それでは、ステキな開発ライフを。