あ…ありのまま 今 起こった事を話すぜ!
pandasのデータフレームにdatetime値を入れたと思ったら、いつのまにか数値になっていた。
催眠術とか超スピードでは断じてないので、紹介してみる。
datetimeが数値に変わってしまう
datetimeが数値に変わってしまう現象をコードを用いながら説明する。
初期設定
まずはpandasのデータフレームを定義する。
import pandas as pd import numpy as np import datetime cols = ["c1", "c2"] vals = np.array([[1,2], [4,5]]) df = pd.DataFrame(vals, columns=cols) print(df) # c1 c2 # 0 1 2 # 1 4 5
そしてdatetime値をセットする為の新規カラムを追加する。
# Add new column df["hoge"] = None print(df) # c1 c2 hoge # 0 1 2 None # 1 4 5 None
(失敗例)切り出したデータフレームで更新する
データフレームを切り出して、作成したカラムにdatetime値(2019/11/28)をセットして元のデータフレームに対してupdateすると、datetime値をセットしたはずの項目に 1574899200000000000
なる数値が入ってしまった。
# Update by sliced data df_slice = df[df["c1"] > 3] df_slice["hoge"] = datetime.datetime(2019,11,28) df["hoge"].update(df_slice["hoge"]) print(df) # c1 c2 hoge # 0 1 2 None # 1 4 5 1574899200000000000
(対策1)カラム全体をdatetime変換する
datetimeが数値に変わってしまった原因を考えて、まず思いついたのがカラムの型。
元のデータフレームの型がdatetime型ではないので、更新時に値が変換されてしまったのではないか。
その仮説を検証する為に、 pd.to_datetime()
で元データのカラムごとdatetime型に変換してから更新をするとちゃんと日付が入ったが、datetime型というよりdate型のように見える。
# Convert column before update df["hoge"] = pd.to_datetime(df["hoge"]) df_slice = df[df["c1"] > 3] df_slice["hoge"] = datetime.datetime(2019,11,28) df["hoge"].update(df_slice["hoge"]) print(df) # c1 c2 hoge # 0 1 2 NaT # 1 4 5 2019-11-28
(対策2)updateの代わりにindexとlocを用いる
Pythonが「カラム全体に値をセットしないで loc
を使いなさい」と言ってくるので、 update
の代わりに loc
を使うとキレイにdatetime値をセットできる。
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
# Use index and loc instead of update df_slice_index = df[df["c1"] > 3].index df.loc[df_slice_index,"hoge"] = datetime.datetime(2019,11,28) print(df) # c1 c2 hoge # 0 1 2 None # 1 4 5 2019-11-28 00:00:00
まとめ
pandasでdatetimeが数値になってしまう原因は、 datetime値をセットしようとしているカラムの型がdatetimeではない から update時に型変換されてしまう。
対策としては
- カラムごとdatetime型に変換する
update
の代わりにloc
を使う