今回はPandasにおいて文字列データや数値データを日付データであるdatetime64型に変換する方法についてまとめていきます。

datetime64型はPythonにあるtimestamp型を継承したクラスとなっています。Pandasでの日付の扱いは、時系列データを分析する上で役に立つので覚えておくと良いでしょう。

to_datetime関数を使って文字列や数値と日付との変換していきたいと思います。

to_datetime関数

文字列からフォーマットを指定して変換する

まずは"2019/04/07"のようにフォーマットが定まっている場合についてです。

基本的なフォーマットなら関数が検知してくれる

この関数はある程度ならフォーマットを検知してくれるのでとりあえず入れてみてうまく行かなかったらフォーマットを個別に指定するという形で使っても問題ありません。

例えば"2019/04/07"の例だと

In [1]: import pandas as pd

In [2]: str_1 = '2019/04/07'

In [3]: pd.to_datetime(str_1)
Out[3]: Timestamp('2019-04-07 00:00:00')

のように正しく認識してくれます。

他の例でもみてみます。

In [4]: t_str = '20190407'

In [5]: pd.to_datetime(t_str)
Out[5]: Timestamp('2019-04-07 00:00:00')

ですが、このような例の場合、フォーマットを関数が内部で判断する必要があるため、大規模なデータを一括でdatetime64型に変換しようとすると処理の時間にかなりの差が出てきますのでデータ数が多いほどフォーマットを指定することをオススメします。

フォーマットの指定の仕方

フォーマットの指定の仕方ですが、

format引数で指定できます。

先ほどの"2019/04/07"ですと、format='%Y/%m/%d'のように指定します。ここの'%Y'は4桁の年数となり、小文字の'%y'は2桁の年数となります。

以下の表にフォーマットとの対応関係を記載しておきます。

大文字と小文字とで違うだけで大きな違いが出てきてしまうので注意が必要です。

表記 説明
%Y 4桁の年数 (例 2018,1996…)
%y 2桁の年数 (例 18, 96..)
%m 2桁の月 [01,12] (例 01, 07, 12..)
%d 2桁の日付 [01,31] (例 02, 28, 31..)
%H 24時間表記の時間 [00,23] (例 00, 12, 21..)
%I 12時間表記の時間 [01,12] (例 01, 07, 12..)
%M 2桁の分 [00, 59] (例 00, 05, 38, 59..)
%S 秒 [00, 61] (例 00, 15, 39, 60, 61..)
60,61は00,01と同じ
%w 整数表記された曜日 [0(日曜), 6] (例 1(月曜), 4(木曜), 6(土曜)…)
%U 週番号 [00,53] 日曜が週の始めとしてカウントされる。年を通しての週の番号 (例 00, 03, 04, 52..)
%W 週番号 [00,53] 月曜が週の始めとしてカウントされる、年を通しての週の番号
%z UTC タイムゾーンからのオフセット +HHMMまたは-HHMMの形
(例 +0800, -0925,…)

実際に変換してみます。

In [6]: time_sr = pd.Series([20181024, 20200915, 20210111])

In [7]: convert_time = pd.to_datetime(time_sr, format='%Y%m%d')

In [8]: convert_time
Out[8]:
0   2018-10-24
1   2020-09-15
2   2021-01-11
dtype: datetime64[ns]

In [10]: time_sr_2 = pd.Series(['181024 13:24', '200915 07:59', '210111 23:45'])

In [11]: pd.to_datetime(time_sr_2, format='%y%m%d %H:%M') # 2桁の年数なので小文字の%y 時刻は%H:%Mで指定可能
Out[11]:
0   2018-10-24 13:24:00
1   2020-09-15 07:59:00
2   2021-01-11 23:45:00
dtype: datetime64[ns]

日本語表記が入っても変換できます。

In [18]: time_j = "2018年12月12日 05時25分"

In [20]: pd.to_datetime(time_j, format='%Y年%m月%d日 %H時%M分')
Out[20]: Timestamp('2018-12-12 05:25:00')

UNIX時間からの変換

今度は世界標準時(UTC)で1970年1月1日 0時0分からの経過時間を表示するUNIX時間を変換します。 試しに2018年9月20日13時25分00秒(日本時間)のUNIX時間である”1537417500”を変換してみます。ここでの表記は秒数なので、 unit='s'として表記を秒単位にします。

In [22]: pd.to_datetime(1537417500, unit='s') # UNIX時間を変換
Out[22]: Timestamp('2018-09-20 04:25:00')

日本時間に変換してみます。一旦tz_localize('utc')で現在時刻の基準点がUTCであることを示してからtz_convert関数で変換します。 utc=Trueにしておけば関数の処理を1つ省略できます。

In [25]: pd.to_datetime(1537417500, unit='s').tz_localize('utc').tz_convert('Asia/Tokyo') # UNIX時間を変換
Out[25]: Timestamp('2018-09-20 13:25:00+0900', tz='Asia/Tokyo')  

In [26]: utc_time = pd.to_datetime(1537417500,utc=True,unit='s') # utc=TrueにすることでタイムゾーンをUTCに設定できる

In [27]: utc_time
Out[27]: Timestamp('2018-09-20 04:25:00+0000', tz='UTC')

In [28]: utc_time.tz_convert('Asia/Tokyo')
Out[28]: Timestamp('2018-09-20 13:25:00+0900', tz='Asia/Tokyo')

デフォルトではunit='ns'となっておりナノ秒まで表記します(10の-9乘)。

In [29]: pd.to_datetime(1537417500293410982, unit='ns')
Out[29]: Timestamp('2018-09-20 04:25:00.293410982')

ミリ秒の場合はuint='ms'で指定できます。

In [30]: pd.to_datetime(1537417500293, unit='ms')
Out[30]: Timestamp('2018-09-20 04:25:00.293000')

パフォーマンス

パフォーマンスアップのためにはフォーマットを予め指定しておくもしくはinfer_datetime_format=Trueにしておくと高速化できます。

特に、フォーマット指定に当てはまらない形式(例えば月/日が’3/11’のように月が1桁になっている時など)の時に効力を発揮します。

In [37]: long_t = pd.Series(['3/11/2000','3/12/2000','3/13/2000']*2000)

In [38]: %timeit pd.to_datetime(long_t, infer_datetime_format=False) # デフォルト
1.45 s ± 20 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [39]: %timeit pd.to_datetime(long_t, infer_datetime_format=True) # True
24.4 ms ± 414 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [40]: %timeit pd.to_datetime(long_t, format='%d/%m/%Y') # フォーマット指定
---------------------------------------------------------------------------
(エラーメッセージが表示される)

ValueError: time data '3/13/2000' does not match format '%d/%m/%Y' (match)

複数列のデータから作成

列データのラベルを指定しておくとそれらを組み合わせてdatetime64型のデータを作ることができます。

In [50]: df = pd.DataFrame({'year': [1998, 2012, 1990, 2018],
    ...:                    'month':[10, 1, 10, 12],
    ...:                    'day': [10, 11, 21, 1],
    ...:                   'hour': [12, 23, 14, 1],
    ...:                    'minute': [29, 3, 30, 59]})
    ...:                    

In [51]: pd.to_datetime(df)
Out[51]:
0   1998-10-10 12:29:00
1   2012-01-11 23:03:00
2   1990-10-21 14:30:00
3   2018-12-01 01:59:00
dtype: datetime64[ns]

まとめ

今回は色々なデータを日付データに変換してみました。to_datetime関数はかなり柔軟に日付データに変換してくれるのでかなり使い勝手が良いと思います。

参考