日付のフォーマットが混在するDataFrameを扱う
はじめに
今回は日付のフォーマットに関する試行錯誤のメモです。
"Zuerich monthly sunspot numbers 1749-1983" データセット
時系列データで遊びたくて "Zuerich monthly sunspot numbers 1749-1983" というデータセットをcsvでダウンロードしてみました。
https://datamarket.com/data/set/22ti/zuerich-monthly-sunspot-numbers-1749-1983#!ds=22ti&display=line
データの末尾に余計な要素が入っていたので、手動で削除して、pandasで読み込みます。
import matplotlib.pyplot as plt %matplotlib inline import pandas as pd df = pd.read_csv( 'zuerich-monthly-sunspot-numbers-.csv', )
ごく普通のフォーマット。。。かと思ったら、どこかのタイミングから日付のフォーマットが変わっている???
pandasはかなり優秀で、フォーマットが混在していても普通にplotで可視化してくれました。
df['Zuerich_monthly_sunspot_numbers_1749-1983'].plot()
日付から特徴量を作る
ここからが本題です。
日付は文字列型で格納されており、機械学習の特徴量として扱うため、値をdatetime型に変換して年や月などを取り出したいです。しかし、このDataFrameでは日付のフォーマットが混在しているため、例えば単純に次のようにしてもエラーが発生してしまいます。これは、フォーマットの指定が一部で正しくないためです。
df['datetime'] = pd.to_datetime(df['Month'], format='%Y-%m')
ValueError: time data 'Jan-00' doesn't match format specified
フォーマット指定をなくせば、よしなに処理してくれるかと期待しましたが、あまり一般的なフォーマットでないためか、エラーとなりました。
df['datetime'] = pd.to_datetime(df['Month'])
ValueError: day is out of range for month
結局今回は、try~exceptを使い、フォーマットごとに処理する関数を作成しました。この関数をmapの引数として、DataFrameを処理します。
def convert_to_datetime(date): try: return pd.to_datetime(date, format='%Y-%m') except: return pd.to_datetime(date, format='%b-%y') df['datetime'] = df['Month'].map(convert_to_datetime)
フォーマットの指定に当たっては、公式の「ディレクティブ」を確認しました。
datetime — Basic date and time types — Python 3.8.0 documentation
この 'datetime' を用いることで、年や月などの特徴量を作成できました。
df['year'] = df['datetime'].dt.year df['month'] = df['datetime'].dt.month
おまけ
世紀の指定がない2桁の年を処理する際に、自動補完される世紀が正しくない値になっていました。
例えば「1934年」を意味する「34」が、「2034年」として扱われていました。
df['year'].plot()
今回は暫定的に次の処理で回避しましたが、この辺りの仕様はきちんと確認しておきたいです。
df['year'] = [y if y < 2000 else (y - 100) for y in df['year']]