KNIMEとか倉庫

KNIMEやEXCELなどの備忘録です。

【Python】日付の揺れを統一したい

・お題:PandasのDataframeで日付を含む表を入手したものの、日付の表記が様々ある。統一したい。

 

・DataFrameを作成する。

import pandas as pd
a1=["2022/1/1","2022/01/01","2022.1.1","2022.01.01","2022-1-1","2022-01-01"]
df1=pd.DataFrame(a1,columns=["a1"])

・4桁年月日になっている。

・pd.to_datetimeを使う。DataFrameを放り込むのは難しく、SeriesならOK見たい。

pd.to_datetime(df1["a1"])

で、以下が返ってくる。

0   2022-01-01
1   2022-01-01
2   2022-01-01
3   2022-01-01
4   2022-01-01
5   2022-01-01
Name: a1, dtype: datetime64[ns]

・df1を統一したいなら、以下のような感じ。

df1["a1"]=pd.to_datetime(df1["a1"])

・一応はこれでうまくいった。だが、実際にデータを眺めてみると、日付の表記にもっとバリエーションがあった。

import pandas as pd
a2=["2022/1/1","2022/01/01","2022.1.1","2022.01.01","2022-1-1","2022-01-01","2022年1月1日","2022年01月01日","2022年1月1日","2022年01月01日","22/1/1","22/01/01","22.1.1","22.01.01","22-1-1","22-01-01","22年1月1日","22年01月01日","22年1月1日","22年01月01日","20220101","220101"]
df2=pd.DataFrame(a2,columns=["a2"])

・4桁年月日、だけではなく、2桁年月日、全角半角のバリエーションも想定される。

・まず、これを先ほどの関数に入れると、エラーが返ってくる。

ParserError: Unknown string format: 2022年1月1日

・年、月、日がエラーになる。いったんエラーを無視する。

pd.to_datetime(df2["a2"],errors="coerce")

0    2022-01-01
1    2022-01-01
2    2022-01-01
3    2022-01-01
4    2022-01-01
5    2022-01-01
6           NaT
7           NaT
8           NaT
9           NaT
10   2001-01-22
11   2001-01-22
12   2001-01-22
13   2001-01-22
14   2001-01-22
15   2001-01-22
16          NaT
17          NaT
18          NaT
19          NaT
20   2022-01-01
21   2001-01-22
Name: a2, dtype: datetime64[ns]

・先ほどうまくいったものは今回もうまくいった。先ほどエラーになりそうなものは、NaTになった。一見うまくいきそうでうまくいかなかったのが、2桁年月日のパターンで、日付が変わってしまった。これは2桁年月日が年月日の順番で読み込まれていないことが原因ぽい。

pd.to_datetime(df2["a2"],yearfirst=True,errors='coerce')

0    2022-01-01
1    2022-01-01
2    2022-01-01
3    2022-01-01
4    2022-01-01
5    2022-01-01
6           NaT
7           NaT
8           NaT
9           NaT
10   2022-01-01
11   2022-01-01
12   2022-01-01
13   2022-01-01
14   2022-01-01
15   2022-01-01
16          NaT
17          NaT
18          NaT
19          NaT
20   2022-01-01
21   2022-01-01
Name: a2, dtype: datetime64[ns]

・次に、NaTを処理する。

pd.to_datetime(df2["a2"],format="%Y年%m月%d日",errors='coerce')

0           NaT
1           NaT
2           NaT
3           NaT
4           NaT
5           NaT
6    2022-01-01
7    2022-01-01
8           NaT
9           NaT
10          NaT
11          NaT
12          NaT
13          NaT
14          NaT
15          NaT
16          NaT
17          NaT
18          NaT
19          NaT
20          NaT
21          NaT
Name: a2, dtype: datetime64[ns]

・日付が全角になっている場合はうまくいかない。全角を半角に変換したい。以下の記事を参考にさせて頂いた。

qiita.com

・全角英数字を半角にする。

ZenHan=lambda x:x.translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))

df2["a2"]=df2["a2"].apply(ZenHan)

・これで、NaTの4桁年月日は解決しそう。まだ2桁年月日は解決していない。2桁年月日を処理したい場合は、以下のようにformatの年のYをyに変える。

pd.to_datetime(df2["a2"],format="%y年%m月%d日",errors='coerce')

・以上を組み合わせて処理してみる。方針としては、①とりあえず半角に変換、②デフォルトのフォーマットで処理できそうなところは処理、③エラーで弾かれた4桁年月日を処理、④さらにエラーで弾かれた2桁年月日を処理、という感じでいってみた。

 

#全角英数を半角にする。
ZenHan=lambda x:x.translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))
df2["a2"]=df2["a2"].apply(ZenHan)

#df3を変換後のDataFrameとして利用
df3=df2.copy()

#デフォルトの処理
df3["a2"]=pd.to_datetime(df2["a2"],yearfirst=True,errors='coerce')

#df3でエラーが出ているところに、df2のフォーマットを指定して処理した結果を挿入×2回
df3["a2"]=df3["a2"].fillna(pd.to_datetime(df2["a2"],format="%Y年%m月%d日", errors="coerce"))
df3["a2"]=df3["a2"].fillna(pd.to_datetime(df2["a2"],format="%y年%m月%d日", errors="coerce"))

#df3をdf2に代入
df2=df3.copy()

 

・どうやらうまくいったらしい。

 

おわり。