maruyama
Nishika開催された同様のコンペ (※1) では、予測値として 前年同月 or 同年前月 の価格を使うだけ (※2) で4位/1046人でした。本コンペでも同様の方法が使えるのではないかと思い試してみましたので、ご紹介します。
※1 https://competition.nishika.com/competitions/yasai/summary※2 https://competition.nishika.com/competitions/yasai/topics/353
(2023-07-25更新) RMSLEの定義がsklearnと異なっていたため修正しました。また、予測方法に前年翌月を追加しました。その他、不要なコードを一部削りました。
import numpy as np import pandas as pd
train_data = pd.read_csv('data/train_data.csv', index_col=0, parse_dates=[0]) sample_submission = pd.read_csv('data/submission.csv')
あらかじめ価格を対数変換しておきます。
train_data = np.log1p(train_data)
また、この後の処理を書きやすくするため、行と列に分かりやすい名前を付けておきます。
train_data = train_data.rename_axis(index='date', columns='vegetable')
train_data.head()
5 rows × 340 columns
まず、予測値として前年翌月/前年同月/同年前月の価格を出力する方法を使って学習データに対して予測します。
train_data_pred = pd.concat( # 前年翌月の価格を予測値として使う。 [ pd.DataFrame({ 'id': train_data.columns, 'year': year, 'method': 'lynm', 'y': train_data.loc[f'{year}-12-01', :], 'y_pred': train_data.loc[f'{year - 1}-01-01', :] }) for year in [2018, 2017] ] + # 前年同月の価格を予測値として使う。 [ pd.DataFrame({ 'id': train_data.columns, 'year': year, 'method': 'lycm', 'y': train_data.loc[f'{year}-12-01', :], 'y_pred': train_data.loc[f'{year - 1}-12-01', :] }) for year in [2018, 2017] ] + # 同年前月の価格を予測値として使う。 [ pd.DataFrame({ 'id': train_data.columns, 'year': year, 'method': 'cylm', 'y': train_data.loc[f'{year}-12-01', :], 'y_pred': train_data.loc[f'{year}-11-01', :] }) for year in [2018, 2017, 2016] ], ignore_index=True )
train_data_pred.head()
次に、野菜と地域の組み合わせそれぞれについて、最もRMLSEが小さくなる方を最適な予測方法として選びます。
best_pred_method = ( train_data_pred .assign(rmsle = lambda df: df['y'] - df['y_pred']) .groupby(['id', 'method'], as_index=False)['rmsle'].agg(lambda s: np.sqrt(np.mean(s ** 2))) .loc[lambda df: df['rmsle'] == df.groupby('id')['rmsle'].transform(np.min), ['id', 'method']] .reset_index(drop = True) )
best_pred_method.head()
最適な予測方法を使った場合の、学習データに対する予測精度を確認します。
( train_data_pred .loc[lambda df: df['year'] >= 2017, :] .merge(best_pred_method, how='inner', on=['id', 'method']) .assign(rmsle = lambda df: df['y'] - df['y_pred']) .groupby(['year'], as_index=False)['rmsle'].agg(lambda s: np.sqrt(np.mean(s ** 2))) )
最後に、2019年12月の価格を予測し、提出ファイルを作ります。
submission = ( pd.concat( [ # 前年翌月の価格を予測値として使う。 pd.DataFrame({ 'id': train_data.columns, 'method': 'lynm', 'y': train_data.loc[f'2018-01-01', :] }), # 前年同月の価格を予測値として使う。 pd.DataFrame({ 'id': train_data.columns, 'method': 'lycm', 'y': train_data.loc[f'2018-12-01', :] }), # 同年前月の価格を予測値として使う。 pd.DataFrame({ 'id': train_data.columns, 'method': 'cylm', 'y': train_data.loc[f'2019-11-01', :], }) ], ignore_index=True ) # 最適な予測方法で予測した結果だけ抽出する。 .merge(best_pred_method, how='inner', on=['id', 'method']) .drop(columns=['method']) # 対数変換してあるので、元に戻す。 .assign(y = lambda df: np.expm1(df['y'])) # 予測結果を指定された順序に並び替える。 .merge(sample_submission[['id']], how='right', on='id') )
submission.to_csv('submission/submission_20230725_01.csv', index=False, header=True)