Python:Pandasの日付処理はクセが凄いので迷わない為の備忘録

Python:Pandasの日付処理はクセが凄いので迷わない為の備忘録

Python:Pandasの日付処理はクセが凄いので迷わない為の備忘録

最近調べる回数が多いPandasの日付処理。
毎回違う事で悩んでいるのですが「こんな悩みを生む仕組みってある意味凄い」と思っています。
と言う事で、Pandasでの日付処理について迷わない為の基本事項をまとめておきます。

まず頭に入れておかないといけないのはコレです。

DataFrameに格納するとカラムの値はSeriesになり文字列として格納される

※datetime64[ns]型のDataFrameで日付をIndexとした場合DatetimeIndexとなり様々な機能を使えるようになりますが今回は触れません。

DataFrameに変換すると文字列になるがSeriesは普通の文字列とは違う

文字列の日付をdatetime型に変換するコード

これをDataFrameに対して実行するとエラーが発生します。

cannot convert the series to <class ‘int’>
訳:系列を <class ‘int’> に変換することはできません。 ※系列=Series

と言う事でPandasに格納した時点でdatetime関数は利用できません。
同じ文字列ではありますがSeriesというタグ付きの文字列でありピュアな文字列とは違います。
これが地味に痛い…。

Seriesにある日付はto_datetime関数でDatetimeもどきに変換する

to_datetime関数はDataFrameに入っている日付データをDatetimeLikeに扱えるように変換してくれます。

ただし、あくまでもDatatimeLikeであって完全一致で同じ処理はできません。
【もどき】である事の理解が重要です。

Printで日付や月を取り出せるのだからdatetime.dateにすることもできるんじゃないかと思いテストしてみました。

descriptor ‘date’ for ‘datetime.datetime’ objects doesn’t apply to a ‘Series’ object
訳:datetime.datetime’オブジェクトのディスクリプタ’date’は’Series’オブジェクトには適用されません。

やはりSeriesオブジェクトである点がネックとなりdate型への変換は失敗しました。
今回使いたかった差分の月数を計算する関数【monthmod】はdatetime型である必要があるため撃沈。
この事例のように、Datatimeを使ってゴニュゴニョする関数系は大きな影響があります。

Seriesオブジェクトはto_datetimeなしでも『なぜか』日付の差分計算は行う

この動作が私を誤解させて長考のきっかけになってました。

DataFrameに格納するとカラムの値はSeriesになり文字列として格納される

原則から考えれば文字列なので減算処理なんて出来ないハズ。
でもできるんですよね。なんででしょう。

「計算できるならdtオプションで【 .dt.year 】とか個別取得できるんじゃね?」と思い実験。

Can only use .dt accessor with datetimelike values
訳:datetimelike 値を持つ .dt アクセサのみを使用できます。

やっぱりできない。まぁこれが標準ですよね。
で「計算結果をDataFrameに格納した後にtd.daysで取得すると失敗するだろう」と思いきや、これは通ります。

forループするとto_datetimeなしでdatetimeとして扱うことができる

「折角DataFrameにしたのをForループでリストに戻すの?」というご意見があるのは重々承知してます。
なのでこれも実験と言う事で。
先に振れたように、monthmodというdatetimeを利用した経過月数計算関数があります。

pip install MonthDelta
Useは from monthdelta import monthmod

これをForループなしで使ってみます。

start and end must be dates
訳:開始と終了は日付でなければなりません

こんなエラーが出てきます。これはto_datetimeを利用しても同じ結果です。
では、forループを使って走らせてみます。

通りましたね。
それも文字列⇒datetime変換をしない状態で通ってます。
う~ん、文字列として格納されるとか言っといて不思議な動きです。

Pandasの日付操作でよく使うコマンド

今回はDataFrame内の日付データの基本的な動きとしてまとめてみました。

最後にコマンドとしてよく使うものをまとめてみます。

  1. Seriesの日付変| pd.to_datetime(df[‘date’]) ※import pandas as pd
  2. 「年」だけ取得| pd.to_datetime(df[‘date’]).dt.year ※ dt.month⇒「月」取得 / dt.day⇒「日」取得
  3. 曜日の取得| pd.to_datetime(df[‘date’]).dt.dayofweek ※ 月曜を0として0~6までの数字で曜日を返す 6=日曜日
  4. 日数の加減算_1| pd.tseries.offsets.Day(31) ※ 20日前はpd.tseries.offsets.Day(-20)
  5. 日数の加減算_2| dt + relativedelta(days=3) ※ dt=元の日付 / use :from dateutil.relativedelta import relativedelta
  6. 週数で加減算| pd.tseries.offsets.Week(weekday=2)
  7. 日付の置き換え| dt + relativedelta(day=3) ※ days=3と【s】を付けると3日後を計算するので要注意
  8. 2つの間の期間| (dt_A – dt_B).dt.days ※ dt.daysを付けない時、20 days 00:00:00 のような形が返ってくる
  9. forループで値を取る| for index, item in df.iterrows(): ※index不要の時は変数1つだけでOK

dtオプションの細かい情報はこちらにまとまってました。

まとめ

「Aだと出来てBだと出来ない」というのがあると慣れて覚えるしかない。
処理を書く数が多いので、まぁ嫌でも覚えていくことでしょう。

最初簡単に日付操作ができたのは『DatetimeIndexにしてたから』だったようです。