Pandasと日時データ
Pandasはデータの読込や型変換を柔軟に実行してくれる非常に便利なライブラリです。
ただし、intやfloat型と比べると日時型(64bit OSではdatetime64型)は取扱いに注意が必要で、特に引き算はハマりやすい処理です。
日時の引き算
さっそく日時同士の列の引き算を実行してみます。
使用するデータ
A,B
2020-06-02 13:45:16,2020-06-02 13:50:23
2020-06-02 13:50:15,2020-06-02 14:55:19
2020-06-02 13:52:10,2020-06-03 13:57:21
データを読み込んで引き算を実行するコード
pd.read_csv()で読み込む際に、引数を指定しないとdatetime型ではなくstr型で読み込まれるので注意してください。
datetime型の列として読み込む方法はいくつかありますが、下記のように引数parse_datesを指定するのが楽です。
import pandas as pd
df = pd.read_csv('time_diff_test.csv',parse_dates=['A', 'B'])
df['diff'] = df['B'] - df['A']
print(df)
# 0 0 days 00:05:07
# 1 0 days 01:05:04
# 2 1 days 00:05:11
# Name: diff, dtype: timedelta64[ns]
上記のように単純に列同士の引き算をすると、timedelta64型で出力されます
日時の引き算を秒(分、時、日‥)単位で取得
実際の使用時には秒や分単位で取得したい場面が多いかと思います。
うまくいかないコード
timedelta型の変数を秒単位に変換したい場合**.total_seconds()**が有効ですが、
DateFrameの列(Series)にそのまま実行してもうまくいきません
import pandas as pd
df = pd.read_csv('time_diff_test.csv',parse_dates=['A', 'B'])
df['diff'] = df['B'] - df['A']
print(df['diff'].total_seconds())
# 'Series' object has no attribute 'total_seconds'
うまくいくコード
timedelta型のSeriesを秒に変換する方法はいくつかありますが、
下記のようにmapとlambdaを組み合わせると、1行で記述できて楽です
import pandas as pd
df = pd.read_csv('time_diff_test.csv',parse_dates=['A', 'B'])
df['diff'] = df['B'] - df['A']
df['diff_ts'] = df['diff'].map(lambda x: x.total_seconds())
print(df['diff_ts'])
# 0 307.0
# 1 3904.0
# 2 86711.0
# Name: diff_ts, dtype: float64
【追記】Series.dt.total_seconds()を使用
※@nkayさんよりコメント頂きました
上のmap + lambdaよりシンプルに計算でき、ベストチョイスになりそうです。
df['diff_ts'] = df['diff'].dt.total_seconds()
print(df['diff_ts'])
# 0 307.0
# 1 3904.0
# 2 86711.0
# Name: diff, dtype: float64
時間差を分、時単位で
total_minutes()、total_hours()‥なんてメソッドはありません、、笑
total_seconds()を60、3600で割りましょう
print(df['diff'].map(lambda x: x.total_seconds()/60.0))
print(df['diff'].map(lambda x: x.total_seconds()/3600.0))
# 0 5.116667
# 1 65.066667
# 2 1445.183333
# Name: diff, dtype: float64
# 0 0.085278
# 1 1.084444
# 2 24.086389
# Name: diff, dtype: float64
total_seconds()とsecondsの違い
timedeltaを秒単位に変換する方法には、total_seconds()以外にもsecondsがあります。
違いを調べてみます
print(df['diff'].map(lambda x: x.total_seconds()))
# 0 307.0
# 1 3904.0
# 2 86711.0
# Name: diff, dtype: float64
print(df['diff'].map(lambda x: x.total_seconds()))
# 0 307
# 1 3904
# 2 311
# Name: diff, dtype: int64
こちらによると、
total_seconds():差分を秒単位で表したもの(float型)
seconds:差分を日数、秒数、マイクロ秒数、ミリ秒数、分、時間、週で分解したうちの秒数(int型)
となっているようです。
いわゆる**「時間差」を表すのはtotal_seconds()**の方みたいですね
本記事は以上です
最後まで見て頂きありがとうございました!