概要
ローデータ(生データ)を取り込むと、年月日が独立して入っている感じの嫌なデータになっていることがあります。
年,月,日 1996,8,1 1998,12,2 2012,05,3
こういうのは嬉しくないので、できるだけ単一のdatetime風の型に変換しておきたいのですが、意外と難しかったりします。
文字列操作として考える
以下のように読み込みます(io.StringIOを使っていますが実際はCSVファイルだと思ってください)。
import io import pandas as pd data = """ 年,月,日 1996,8,1 1998,12,2 2012,05,3 """ df = pd.read_csv(io.StringIO(data), dtype={k:object for k in "年月日"})
型をobject型にしておくのがミソで、整数型にされると文字列操作で変換できません。読み込んでからastypeで変換してもいいですが、二度手間ですね。
df["DateTime"] = pd.to_datetime(df["年"].str.cat([df["月"], df["日"]], sep=" ")) print(df) """ => 年 月 日 DateTime 0 1996 8 1 1996-08-01 1 1998 12 2 1998-12-02 2 2012 05 3 2012-05-03 """
これはこれでできるのですが、文字列を介すると二度手間感が否めません。
時刻もある場合
とにかくそれっぽいフォーマットに無理矢理仕立てれば、この方法でできます(というかできるはずです)。
import io import pandas as pd data = """ 年,月,日,時,分 1996,8,1,12,5 1998,12,2,4,12 2012,05,3,23,56 """ df = pd.read_csv(io.StringIO(data), dtype={k:object for k in "年月日時分"}) df["DateTime"] = pd.to_datetime(df["年"].str.cat([df["月"], df["日"], df["時"]], sep=" ").str.cat(df["分"], sep=":")) print(df) """ => 年 月 日 時 分 DateTime 0 1996 8 1 12 5 1996-08-01 12:05:00 1 1998 12 2 4 12 1998-12-02 04:12:00 2 2012 05 3 23 56 2012-05-03 23:56:00 """
やはりスマートではない。
内包表記でdatetimeっぽい型のリストにすればいいんだよ
そう、普通はそうしたいところ。
型で迷うと思いますが、たぶんTimestampでいいと思います。
pandas.Timestamp — pandas 0.25.3 documentation
import io import pandas as pd data = """ 年,月,日,時,分 1996,8,1,12,5 1998,12,2,4,12 2012,05,3,23,56 """ df = pd.read_csv(io.StringIO(data)) df["DateTime"] = [ pd.Timestamp( year=row["年"], month=row["月"], day=row["日"], hour=row["時"], minute=row["分"]) for i, row in df.iterrows()] print(df) """ => 年 月 日 時 分 DateTime 0 1996 8 1 12 5 1996-08-01 12:05:00 1 1998 12 2 4 12 1998-12-02 04:12:00 2 2012 5 3 23 56 2012-05-03 23:56:00 """
読み込みで文字列にしないといけない、二度手間、といった微妙さがなくなりました。わーい。
これはこれで上手くいきます。が、スマートなはずなのにスマートに見えない。キーワード引数の指定が汚すぎるからですね。
ダブルアスタリスクのアンパックを使えば……とか一瞬は思いましたが、そのためには列名を変えたdfをコピーして作らないといけません。
import io import pandas as pd data = """ 年,月,日,時,分 1996,8,1,12,5 1998,12,2,4,12 2012,05,3,23,56 """ df = pd.read_csv(io.StringIO(data)) df_d = df[["年", "月", "日", "時", "分"]].copy() df_d.columns = ["year", "month", "day", "hour", "minute"] df["DateTime"] = [pd.Timestamp(**row) for i, row in df_d.iterrows()] print(df) """ => 年 月 日 時 分 DateTime 0 1996 8 1 12 5 1996-08-01 12:05:00 1 1998 12 2 4 12 1998-12-02 04:12:00 2 2012 5 3 23 56 2012-05-03 23:56:00 """
こっちの方が多少スマートかな。上の書き方でも別に困ることはないです。
まとめ
普通にTimestampのiterableを突っ込めばいいだけだけど、このやり方が調べても出てこなくて、できないのかなとか思って焦りつつやってみたらできたので記事にしました。
日付時刻の扱いは割と面倒ですが、けっきょくのところ素直に組んでいけば良いはず。
参考
Pandasでの日付・時間周りのちょっとしたチートシート - Qiita
これと同じようなことをやっています。