[python] pandasの日付データ.変換,読み込み,図示まで

pandasで日付データを操作する際に必要な知識をまとめた.
初めに,pythonにおける日付を取り扱うデータ型に代表的なものが3種類あり(datetime.datetime, np.datetime64, Timestamp),それぞれの相互変換の方法を説明する.その後,エクセルからpd.read_excel でデータを読み込む際にセルの設定やカラムに何が入るかによってデータ型が異なる点の指摘とTimestamp 型への変換方法.最後に,日付データの図示方法を説明する.

目的としては,pandasにおいて日付データを処理出来るようになることである.pandasではTimestamp 型を用いて内部処理しているため,如何にしてTimestamp型に変換していくかがポイントである.

本記事で使用したコードは,git clone https://github.com/akitoshiblog/datetime_usage.git で手に入る.

下準備

以下のライブラリーをimportし,変数の値,オブジェクト表示,データ型を確認する用の関数を定義する.

import datetime 
import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
%matplotlib inline

def print_variable(v,s):
    """Print variabels with text, value, object representation, type. 
    """
    print(f"{s} : {v}, {repr(v)}, {type(v)}") 

日付に関連したオブジェクト3種類の生成

ここでは,3つの日付データの型を宣言している.
ある特定の日付以前を取り出したいといったときに,特にTimestamp型の宣言方法を知っておく必要がある.

d1 = datetime.datetime(2020,1,2) # datetime object
d2 = np.datetime64("2020-01-02") # np.datetime64 object
d3 = pd.Timestamp(2020,1,2) # Timestamp object

print_variable(d1,"d1")
print_variable(d2,"d2")
print_variable(d3,"d3")
d1 : 2020-01-02 00:00:00, datetime.datetime(2020, 1, 2, 0, 0), <class 'datetime.datetime'>
d2 : 2020-01-02, numpy.datetime64('2020-01-02'), <class 'numpy.datetime64'>
d3 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>

3つの型の相互変換

以下のコードにより全ての型同士の変換パターンが網羅されている. 
結果は全て, 2020/01/02が保持されていることを確認出来る. 

# datetime.datetime to np.datetime64
d1_2 = np.datetime64(d1)
# datetime.datetime to Timestamp
d1_3 = pd.Timestamp(d1)
# np.datetime64 to datetime.datetime
d2_1 = d2.astype(datetime.datetime)
# np.datetime64 to Timestamp 
d2_3 = pd.Timestamp(d2)
# Timestamp to datetime.datetime
d3_1 = d3.to_pydatetime()
# Timestamp to np.datetime64
d3_2 = d3.to_datetime64()

print_variable(d1_2,"d1_2")
print_variable(d1_3,"d1_3")
print_variable(d2_1,"d2_1")
print_variable(d2_3,"d2_3")
print_variable(d3_1,"d3_1")
print_variable(d3_2,"d3_2")
d1_2 : 2020-01-02T00:00:00.000000, numpy.datetime64('2020-01-02T00:00:00.000000'), <class 'numpy.datetime64'>
d1_3 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
d2_1 : 2020-01-02, datetime.date(2020, 1, 2), <class 'datetime.date'>
d2_3 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
d3_1 : 2020-01-02 00:00:00, datetime.datetime(2020, 1, 2, 0, 0), <class 'datetime.datetime'>
d3_2 : 2020-01-02T00:00:00.000000000, numpy.datetime64('2020-01-02T00:00:00.000000000'), <class 'numpy.datetime64'>

文字列からTimestampに変換する

pd.to_datetime 関数はかなり広い幅の変換を可能にする.
以下のパターンは全て正常にTimestamp オブジェクトへ変換することが可能.

ex1 = pd.to_datetime("20200102")
ex2 = pd.to_datetime("2020-01-02")
ex3 = pd.to_datetime("2020 01 02")
ex4 = pd.to_datetime("2020-1 2")
ex5 = pd.to_datetime("2020/01/02")
ex6 = pd.to_datetime("2020/01/02", format='%Y/%m/%d')
ex7 = pd.to_datetime(1577923200000000000, unit="ns")
ex8 = pd.to_datetime(1577923200, unit="s")

print_variable(ex1, "ex1")
print_variable(ex2, "ex2")
print_variable(ex3, "ex3")
print_variable(ex4, "ex4")
print_variable(ex5, "ex5")
print_variable(ex6, "ex6")
print_variable(ex7, "ex7")
print_variable(ex8, "ex8")
ex1 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex2 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex3 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex4 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex5 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex6 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex7 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
ex8 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>

エクセルファイルからの読み込み,Timestampへデータを変換

サンプルのエクセルデータはgithub上に上がっている.
このデータを読み込むと以下のようになる.

df = pd.read_excel("./sample_datetime.xlsx")
display(df)
print(df.dtypes)

カラムA,Bはdatetime64[ns]となり,これがpandasにおけるTimestampの型である.

カラムCはエクセルの設定上で,文字列として登録した.そのためデータフレームの見た目上では日付データの用に見えるがこれは文字列として保存されている.日付型として取り扱うためには日付型への変換が必要である特定.

カラムDは日付型と文字列が混じっている場合である.
各データセルに入っているデータの型を確認してみる.

for c in df.columns:
    v  = df[c].iloc[0]
    print_variable(v,f"{c}0")
A0 : 2020-01-05 00:00:00, Timestamp('2020-01-05 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
B0 : 2020-01-02 00:00:00, Timestamp('2020-01-02 00:00:00'), <class 'pandas._libs.tslibs.timestamps.Timestamp'>
C0 : 2020-01-02, '2020-01-02', <class 'str'>
D0 : 2020-01-02 00:00:00, datetime.datetime(2020, 1, 2, 0, 0), <class 'datetime.datetime'>
E0 : 10, 10, <class 'numpy.int64'>

すると,カラムDの0インデックスの場所にはpythonの組み込みオブジェクトであるdatetime.datetime 型が入力されていることが分かる.また,カラムCには改めて文字列が入力されていることが確認出来る.

次に以下のコードによって,カラムC,DをTimestamp型に変換することが出来る.
errors="coerce" を指定すると変換出来なかった値がNaTに置換され,カラム全体としてはTimestamp型として処理出来るようになる.

また,Timestamp同士の引き算を行うとTimedelta型のオブジェクトとなる.
このデータ型の取り扱いの1つの工夫としては単位日数もしくは単位時間などで割り,数値型として処理することである.すると,日付データ特有の処理に困らなくて済む.

df = pd.read_excel("./sample_datetime.xlsx")
df["C"] = pd.to_datetime(df["C"])
df["D"] = pd.to_datetime(df["D"], errors="coerce")

df["diff"] = df["A"] - df["B"]
df["diff_f"] = (df["A"] - df["B"])/pd.Timedelta(1,"D")
display(df)
print(df.dtypes)

図示

x軸に日付データを取った際の図示の方法にはmatplotlibの機能を使ったものと,pandasの機能を使ったものがある.個人的には,pandasの機能を使うと予期せぬx軸の設定が適用されたりするため,matplotlibの機能のみを用いて図を作成しておくのが良いと考える.

単純な図示方法は,シリーズをx軸,y軸に渡す.

plt.plot(df["A"], df["E"])

x軸の角度を変えたり,表記のフォーマットを変えたりするには以下のようにする.
日付のフォーマットの指定方法としては,strftime() and strptime() Format Codes の公式ドキュメントを参照のこと.

fig = plt.figure(figsize=(5,3))
ax = fig.add_subplot(111)
ax.plot(df["A"],df["E"])
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%b-%d"))
plt.xticks(rotation=30)
plt.show()

pandasを用いた図示方法も載せておく.
x軸の日付の表記方法が違うことが分かる.

df.plot(x="A", y ="E")

———-雑感(`・ω・´)———-
pandas.to_datetime, pandas official API reference のAPIリファレンスからpandasのメソッドを確認しておくと発見がある.
特に,Seriesに対する .dtの中にはシリーズ全体に対してTimestampオブジェクトに対する操作を同時に行えるメソッド群が存在しているのでいくつか眺めておくと良いかもしれない.

また以下の本で詳細にdatetime objectに関する説明が書いてある.

参考文献

コメント

タイトルとURLをコピーしました