野菜取引価格の予測

野菜価格に影響する要因を探り当てよう!

賞金: 100,000 参加ユーザー数: 302 1年以上前に終了

1st place solution

参加者の皆様お疲れさまでした。
運営様、コンペの開催ありがとうございました。
1st place solutionを共有します。

GitHubのリンクはコチラ

https://github.com/TTakumi-git/vegetable_price_predict.git

参考にした主なサイト

生鮮野菜の価格予測 1位 解法 & 振り返り
https://qiita.com/aji-pandas/items/4cb941a7ea9020a501de
Fieldman Research | 野菜の市場価格を調べよう!
https://hatakemon.com/
農業ビジネス | 今年の市場相場を読む
https://agri-biz.jp/item/search?item_type=1&title_by_item_id=5155&sub_category_type=1

from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive
! pip install -U -q matplotlib
! pip install -U -q japanize-matplotlib
! pip install -q catboost
2K     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.6/11.6 MB 17.1 MB/s eta 0:00:00
2K     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 98.3/98.3 kB 10.2 MB/s eta 0:00:00
2K     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.1/4.1 MB 13.8 MB/s eta 0:00:00
etadata (setup.py) ... ?25latplotlib (setup.py) ... ?25l?25hdone
2K     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 98.6/98.6 MB 9.1 MB/s eta 0:00:00
?25h
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
%matplotlib inline

plt.rcParams['font.family'] = 'IPAexGothic'

import warnings
warnings.simplefilter('ignore')
# dataを読み込み
train_data = pd.read_csv('/content/drive/MyDrive/share/competition/野菜取引価格の予測/data/train_data.csv', index_col='id')
weather = pd.read_csv('/content/drive/MyDrive/share/competition/野菜取引価格の予測/data/weather.csv', index_col=0, header=[0,1,2])
submission = pd.read_csv('/content/drive/MyDrive/share/competition/野菜取引価格の予測/data/submission.csv')

# 処理しやすいように天候データの列名をアンダースコアで繋げる
weather.columns = ["_".join(cols) for cols in weather.columns]
weather.columns = weather.columns.str.replace('\(', '_')
weather.columns = weather.columns.str.replace('\)', '')
# 処理しやすいように北海道の地域に"北海道_"を追加
weather.columns = weather.columns.str.replace('宗谷', '北海道_宗谷')
weather.columns = weather.columns.str.replace('留萌', '北海道_留萌')
weather.columns = weather.columns.str.replace('上川', '北海道_上川')
weather.columns = weather.columns.str.replace('網走', '北海道_網走')
weather.columns = weather.columns.str.replace('空知', '北海道_空知')
weather.columns = weather.columns.str.replace('後志', '北海道_後志')
weather.columns = weather.columns.str.replace('石狩', '北海道_石狩')
weather.columns = weather.columns.str.replace('日高', '北海道_日高')
weather.columns = weather.columns.str.replace('十勝', '北海道_十勝')
weather.columns = weather.columns.str.replace('根室', '北海道_根室')
weather.columns = weather.columns.str.replace('檜山', '北海道_檜山')
weather.columns = weather.columns.str.replace('胆振', '北海道_胆振')
weather.columns = weather.columns.str.replace('釧路', '北海道_釧路')
weather.columns = weather.columns.str.replace('渡島', '北海道_渡島')

#インデックスを振り直す。年月は後で使うのでdropしない
weather = weather.reset_index()
# ノイズになる地域を除外(北海道の一部地域と離島)
## 宗谷は98%が畜産部門、https://www.souya.pref.hokkaido.lg.jp/fs/2/1/7/9/5/3/7/_/souyanonougyo1.pdf
## 根室は95%が酪農、https://www.nemuro.pref.hokkaido.lg.jp/fs/8/2/3/0/6/8/9/_/R5%E6%A6%82%E8%A6%81%E7%B7%A8.pdf
ignore_place = ['宗谷', '根室',
                '大島', '三宅島', '八丈島', '父島', '南鳥島', '沖永良部', '屋久島', '種子島', '名瀬'
                '西表島', '与那国島', '南大東']
filtered_cols = [elem for elem in weather.columns.tolist() if not any(local in elem for local in ignore_place)]
weather = weather[filtered_cols]

# ノイズになる気候データを除去(あとで使用するデータを選択するので除去しなくてもよかった)
## 12月の価格を予測するので、秋冬のデータに出現しづらい'25℃以上'データを除去
## 情報が平滑化されてしまう'降水量の合計'データを除去
ignore_weather_info = ['25℃以上', '降水量の合計']
filtered_cols = [elem for elem in weather.columns.tolist() if not any(info in elem for info in ignore_weather_info)]
weather = weather[filtered_cols]

# 天候データの項目リストを作成
weather_cols = weather.columns.tolist()

# エリアごとの平均的な天候データを生成
area_list = ['AREA_北海道', 'AREA_東北', 'AREA_関東', 'AREA_北陸', 'AREA_東海', 'AREA_近畿', 'AREA_中国', 'AREA_四国', 'AREA_九州',]
area_dic = {
            'AREA_北海道':['北海道'],
            'AREA_東北':['青森', '岩手', '宮城', '秋田', '山形', '福島'],
            'AREA_関東':['茨城', '栃木', '群馬', '埼玉', '千葉', '東京', '神奈川'],
            'AREA_北陸':['新潟', '富山', '石川', '福井', '長野'],
            'AREA_東海':['愛知', '岐阜', '三重', '静岡',  '山梨'],
            'AREA_近畿':['和歌山','奈良', '兵庫', '大阪', '京都', '滋賀' ],
            'AREA_中国':['広島', '岡山', '島根', '鳥取', ],
            'AREA_四国':['高知', '愛媛', '香川', '徳島'],
            'AREA_九州':['山口', '福岡', '大分', '佐賀', '長崎', '熊本', '宮崎', '鹿児島', '沖縄'],
            }
mean_weather = ['日照時間0.1時間未満日数', '日降水量の最大', '日照時間', '降水量の合計', '降雪量合計', '日最高気温の平均', '日最高気温25℃以上日数',
                   '最深積雪', '平均気温', '日平均気温0℃未満日数', '最高気温', '日最低気温の平均', '日最高気温0℃未満日数', '最低気温', '日平均気温25℃以上日探数',
                    '日最低気温25℃以上日数', '日最低気温0℃未満日数']

area_weather = pd.DataFrame()
for temp_area in area_list:
  if area_dic.get(temp_area) is not None:
    sample_point = area_dic[temp_area]
    for tepmp_weather in mean_weather:
      spot_weather_cols = [elem for elem in weather_cols if any(elem.startswith(prefix) for prefix in sample_point) and (tepmp_weather in elem)]
      area_weather[f'{temp_area}_{tepmp_weather}_mean'] = weather[spot_weather_cols].mean(axis=1)

# trainデータとtestデータを作成
train_df = pd.concat([weather.iloc[11:-1, :].fillna(0).reset_index(drop=True), area_weather.iloc[11:-1, :].fillna(0).reset_index(drop=True), train_data.reset_index(drop=True)], axis=1)
test_df = pd.DataFrame(weather.iloc[-1:, :].fillna(0).values, columns = weather.columns.tolist())
test_df = pd.concat([test_df.reset_index(drop=True), area_weather.iloc[-1:, :].reset_index(drop=True)],  axis=1)

# 前処理のためにtrainとtestを結合
train_df['train_flag'] = 1
test_df['train_flag'] = 0
df = pd.concat([train_df, test_df], ignore_index=True, axis=0)

# 年月を使いやすいように加工
df['年月'] = pd.to_datetime(df['年月'])
df['year'] = df['年月'].dt.year
df['month'] = df['年月'].dt.month
df['day'] = df['年月'].dt.day
df['day_of_year'] = df['年月'].dt.dayofyear

# 野菜のリストを作成
vegetable_list = np.unique([element.split("_")[0] for element in train_data.columns])
# 各野菜ごとに機械学習用のパラメータを設定
## predict_type : single_year(単独の年を使ってモデルを評価)、all_year(すべての年を使ってモデルを評価)、rule_based(機械学習を使わず、ルールベースで予測)
## shift_num : 学習にどの月まで含めるかの定義。
##              0の場合は10~12月の値と1ヶ月前の値の計1つの組み合わせで一番いい評価値が出る説明変数を見つける、
##                       1の場合は10~12月の値, 9~12月の値, 1ヶ月前の値,1~2ヶ月前の値の計4つの組み合わせで一番いい評価値が出る説明変数を見つける。
##              半年や1年遡る方法も試したが、基本的に遡る月数が増えるごとに評価値が悪くなる傾向があったため、9~12月に落ち着いた。
##               きのこ類は遡る月数が増えるごとに評価結果が悪くなる傾向があったので、実行時間短縮のため、0にした
##              ルールベースで予測する野菜はゼロ固定
## drop_year : 例年と異なる価格変動が生じた年は予測から除外する(主観で判断)
vegetable_params = {
    'えのきだけ' :
    {'predict_type' : 'single_year', 'shift_num' : 0, 'drop_year' : 2018,},
    'かぶ' :
    {'predict_type' : 'all_year',    'shift_num' : 1, 'drop_year' : 2017,},
    'かぼちゃ' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 0,},
    'かんしょ' :
    {'predict_type' : 'all_year',    'shift_num' : 1, 'drop_year' : 0,},
    'きゅうり' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'こまつな' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2018,},
    'ごぼう' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'さといも' :
    {'predict_type' : 'rule_based',   'shift_num' : 0, 'drop_year' : 0,},
    'さやいんげん' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 2017,},
    'さやえんどう' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 2017,},
    'ししとうがらし' :
    {'predict_type' : 'rule_based', 'shift_num' : 1, 'drop_year' : 0,},
    'しめじ' :
    {'predict_type' : 'single_year', 'shift_num' : 0, 'drop_year' : 0,},
    'しゅんぎく' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2018,},
    'しょうが' :
    {'predict_type' : 'all_year',   'shift_num' : 1, 'drop_year' : 0,},
    'その他の菜類' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 0,},
    'その他の野菜' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 0,},
    'たまねぎ' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2018,},
    'だいこん' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    'ちんげんさい' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'なす' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'なめこ' :
    {'predict_type' : 'single_year', 'shift_num' : 0, 'drop_year' : 0,},
    'にら' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'にんじん' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    'にんにく' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'ねぎ' :
    {'predict_type' : 'all_year',   'shift_num' : 1, 'drop_year' : 2017,},
    'はくさい' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    'ばれいしょ' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2016,},
    'ほうれんそう' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 0,},
    'みずな' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    'みつば' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'やまのいも' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2016,},
    'れんこん' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'カリフラワー' :
    {'predict_type' : 'single_year', 'shift_num' : 1, 'drop_year' : 2017,},
    'キャベツ' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    'セルリー' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'トマト' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2016,},
    'パセリ' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2018,},
    'ピーマン' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2016,},
    'ブロッコリー' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    'ミニトマト' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 0,},
    'レタス' :
    {'predict_type' : 'rule_based', 'shift_num' : 0, 'drop_year' : 2017,},
    '生しいたけ' :
    {'predict_type' : 'single_year', 'shift_num' : 0, 'drop_year' : 0,},
}
# クリスマス需要のサラダ野菜や、正月需要のおせち野菜は業務用途が価格を牽引する
# 貯蔵性の良い野菜は流通量で価格をコントロールしている
## 参考サイト : ばれいしょの生産・流通における基盤強化の取り組み(https://www.alic.go.jp/joho-s/joho07_002188.html)

def rule_based_predict(df, vegetable_local, test):
# ルールベースで算出される価格を使用して予測
  mean_price_vegetable = ['こまつな', 'ごぼう', 'さといも', 'たまねぎ', 'だいこん', 'ちんげんさい', 'なす',
                            'にら', 'にんにく', 'はくさい', 'ばれいしょ', 'やまのいも', 'れんこん', 'キャベツ', ]
# 月平均価格を使用して予測
  month_mean_price_vegetable = ['ししとうがらし', 'にんじん', 'みつば', 'セルリー',]
# 価格変動が最も近い年の価格を使用して予測
  anual_wave_price_vegetable = ['きゅうり', 'トマト', 'ミニトマト']
# 前月の値+その年のプラス側の変動値を使用して予測
  max_std_price_vegetable = ['みずな', 'パセリ', 'ピーマン']
# 前月の値+その年のマイナス側の変動値を使用して予測
  min_std_price_vegetable = ['レタス', 'ブロッコリー',]
# しゅんぎく特有の価格変動を使用して予測
  shungiku = 'しゅんぎく'

  predict_value = [0]

# ルールベースで算出される価格を使用して予測
  if any(vegetable_local.startswith(veg) for veg in mean_price_vegetable):
    predict_value[0] = test[f'{vegetable_local}_rule_based_price'].values[0]
# 月平均価格を使用して予測
  if any(vegetable_local.startswith(veg) for veg in month_mean_price_vegetable):
    predict_value[0] = test[f'{vegetable_local}_month_mean'].values[0]
# 価格変動が最も近い年の価格を使用して予測
  if any(vegetable_local.startswith(veg) for veg in anual_wave_price_vegetable):
    temp = df.copy()
    col = vegetable_local
    temp[f'{col}_year_min'] = temp.groupby(('year'))[col].transform('min')
    temp[f'{col}_year_max'] = temp.groupby(('year'))[col].transform('max')
    temp[f'{col}_anual_wave'] = (temp[col] - temp[f'{col}_year_min']) / (temp[f'{col}_year_max'] - temp[f'{col}_year_min'])
    anual_wave_2016 = temp[(temp['year']==2016) & (temp['month']>=8) & (temp['month']<=10)][f'{vegetable_local}_anual_wave'].values
    anual_wave_2017 = temp[(temp['year']==2017) & (temp['month']>=8) & (temp['month']<=10)][f'{vegetable_local}_anual_wave'].values
    anual_wave_2018 = temp[(temp['year']==2018) & (temp['month']>=8) & (temp['month']<=10)][f'{vegetable_local}_anual_wave'].values
    anual_wave_2019 = temp[(temp['year']==2019) & (temp['month']>=8) & (temp['month']<=10)][f'{vegetable_local}_anual_wave'].values
    diff_2016 = 0
    diff_2017 = 0
    diff_2018 = 0
    for index in range(len(anual_wave_2019)):
      diff_2016 = diff_2016 + abs(anual_wave_2016[index] - anual_wave_2019[index])
      diff_2017 = diff_2017 + abs(anual_wave_2017[index] - anual_wave_2019[index])
      diff_2018 = diff_2018 + abs(anual_wave_2018[index] - anual_wave_2019[index])
    diff_list = [diff_2016, diff_2017, diff_2018]
    base_year = diff_list.index(min(diff_list))
    predict_value[0] = df[(df['year']==(base_year+2016)) & (df['month']==11)][vegetable_local].mean()
# 前月の値+その年の価格変動で起こりうる範囲(SD値)のプラス側を使用して予測
  if any(vegetable_local.startswith(veg) for veg in max_std_price_vegetable):
    df_diff = df[(df['year']==2019)]
    df_diff[f'{vegetable_local}_diff'] = df_diff[vegetable_local].diff(1)
    predict_value[0] = df_diff[df_diff['month']==10][vegetable_local].values[0] + df_diff[f'{vegetable_local}_diff'].std()
# 前月の値+その年の価格変動で起こりうる範囲(SD値)のマイナス側を使用して予測
  if any(vegetable_local.startswith(veg) for veg in min_std_price_vegetable):
    df_diff = df[(df['year']==2019)]
    df_diff[f'{vegetable_local}_diff'] = df_diff[vegetable_local].diff(1)
    predict_value[0] = df_diff[df_diff['month']==10][vegetable_local].values[0] - df_diff[f'{vegetable_local}_diff'].std()
# 11月の東北と関東のしゅんぎくは北海道の価格にけん引される傾向にある
## 原因は特定できず(食文化の違い?)
## 参考サイト : 業務関連情報「春菊(しゅんぎく)と菊菜(きくな) 」(https://www.alic.go.jp/koho/kikaku03_000654.html)
  if vegetable_local.startswith(shungiku):
    local = vegetable_local.split('_')[-1]
    if ('東北' in local) or ('関東' in local):
      col = 'しゅんぎく_北海道'
      temp_df = df.copy()
      temp_df[f'{col}_month_mean'] = temp_df.groupby(('month'))[col].transform('mean')
      temp_df[f'{col}_price_rate'] = temp_df[col].shift(1) / temp_df[f'{col}_month_mean'].shift(1)
      # ルールベースで算出される価格
      temp_df[f'{col}_rule_base_price'] = temp_df[f'{col}_month_mean'] * temp_df[f'{col}_price_rate']
      predict_value[0] = temp_df[f'{col}_rule_base_price'].values[-1] * 0.95
    else:
      col = vegetable_local
      temp_df = df.copy()
      temp_df[f'{col}_month_mean'] = temp_df.groupby(('month'))[col].transform('mean')
      temp_df[f'{col}_price_rate'] = temp_df[col].shift(1) / temp_df[f'{col}_month_mean'].shift(1)
      # ルールベースで算出される価格
      temp_df[f'{col}_rule_base_price'] = temp_df[f'{col}_month_mean'] * temp_df[f'{col}_price_rate']
      predict_value[0] = temp_df[f'{col}_rule_base_price'].values[-1]

  return predict_value
# 東京中央卸売市場以外の情報を使って細かく産地を分類しないとimportanceが自分の感覚と合わなかった(例:九州のほうれんそうは群馬県の降水量で決まる)
## 参考サイト:全国の中央卸売市場へのリンク(https://www.maff.go.jp/j/shokusan/sijyo/info/link.html)
# きのこ類、施設園芸される野菜、備蓄されたものが流通する野菜、その他の野菜は産地を指定しない
local_dic = {
             'かぶ_北海道':['千葉', '埼玉'], 'かぶ_北陸':['石川', '富山', '新潟'], 'かぶ_東北':['千葉', '青森', '埼玉'],
             'かぶ_東海':['岐阜', '愛知', '三重'], 'かぶ_近畿':['京都', '徳島', '福岡'], 'かぶ_関東':['千葉','埼玉','青森'],
             'かんしょ_中国':['徳島', '熊本', '宮崎'], 'かんしょ_九州':['宮崎', '熊本', '鹿児島'], 'かんしょ_北海道':['茨城'],
             'かんしょ_北陸':['茨城', '石川', '新潟'], 'かんしょ_四国':['徳島'],   'かんしょ_東北':['茨城', '千葉',],
             'かんしょ_東海':['茨城', '徳島'], 'かんしょ_近畿':['茨城', '徳島', '大分'],   'かんしょ_関東':['千葉', '茨城', '徳島'],
             'ねぎ_中国':['島根', '広島', '岡山'], 'ねぎ_九州':['熊本', '鹿児島', '大分'], 'ねぎ_北海道':['埼玉','茨城','北海道'],
             'ねぎ_北陸':['新潟', '石川', '福井'], 'ねぎ_四国':['鳥取','高知','徳島'],   'ねぎ_東北':['宮城', '福島', '青森'],
             'ねぎ_東海':['長野', '静岡', '鳥取'], 'ねぎ_近畿':['群馬', '鳥取', '長野'],   'ねぎ_関東':['茨城', '千葉','埼玉'],
             'ほうれんそう_中国':['福岡', '広島', '岡山'], 'ほうれんそう_九州':['熊本', '福岡'], 'ほうれんそう_北海道':['北海道','茨城','群馬'],
             'ほうれんそう_北陸':['群馬','福岡'], 'ほうれんそう_四国':['愛媛','徳島'],   'ほうれんそう_東北':['宮城','茨城','群馬'],
             'ほうれんそう_東海':['岐阜', '愛知'], 'ほうれんそう_近畿':['徳島', '福岡'],   'ほうれんそう_関東':['茨城', '群馬','埼玉'],
             'カリフラワー_中国':['熊本'],
             'カリフラワー_北陸':['新潟'], 'カリフラワー_東北':['埼玉','愛知','熊本'],
             'カリフラワー_東海':['徳島','愛知'], 'カリフラワー_近畿':['徳島'],   'カリフラワー_関東':['千葉','愛知','熊本'],
             }

# 生産量の推論に使用する天候情報を抽出
## 推論期間は収穫時期のため、成長に関係する日照時間は除外。雨や雪が降っていなければ収穫するのでは?
## 情報が平滑化されてしまう'平均気温'は除外
sample_weather = ['最高気温','最低気温','降水量', '降雪量','最深積雪']
# 消費量の推論に使用する天候情報を抽出
## 気温が高いと鍋物需要が減り、それに関連する野菜の消費量が影響を受ける
## 参考サイト スーパーマーケット白書 2022年版(http://www.super.or.jp/wp-content/uploads/2022/10/NSAJ-Supermarket-hakusho2022fix1.pdf)
## 他の気候データも微量ながら影響を与えているようだった(1st place solutionは'平均気温'と'降雪量'を特徴量としたもの)
### (提出1) publicLB : 0.08124, privateLB : 0.07293, mean_weather = ['平均気温',]
### (提出2) publicLB : 0.08065, privateLB : 0.07290,  mean_weather = ['平均気温', '降雪量']
### (未提出) publicLB : 0.08180, privateLB : 0.07196, mean_weather = ['平均気温', '降雪量', '降水量']
mean_weather = ['平均気温', '降雪量']

def preprocessing(df, vegetable, vegetable_local, back_month, shift_time, drop_year = 0):
  # 価格変動が例年と著しく異なる年を除外
  df = df[~(df['year'] == drop_year)]

  # 産地を取得
  if local_dic.get(vegetable_local) is not None:
    sample_local = local_dic[vegetable_local]
  else:
    sample_local = []

  # 推論に使用する天候情報を抽出
  weather_cols = weather.columns.tolist()
  drop_weather_cols = [elem for elem in weather_cols if not any(elem.startswith(prefix) for prefix in sample_local) or not any(keyword in elem for keyword in sample_weather)]
  spot_weather_cols = [elem for elem in weather_cols if any(elem.startswith(prefix) for prefix in sample_local) and any(keyword in elem for keyword in sample_weather)]
  df = df.drop(drop_weather_cols, axis=1)
  area_weather_cols = area_weather.columns.tolist()

  target_area = vegetable_local.split('_')[-1]
  target_area = f'AREA_{target_area}'
  filtered_weather_cols = [elem for elem in area_weather_cols if not target_area in elem or not any(keyword in elem for keyword in mean_weather)]
  spot_mean_weather_cols = [elem for elem in area_weather_cols if target_area in elem and any(keyword in elem for keyword in mean_weather)]
  df = df.drop(filtered_weather_cols, axis=1)

  # 価格に関する特徴量を追加
  target_cols = train_data.columns[train_data.columns.str.startswith(vegetable_local)].tolist()
  for col in target_cols:
    # 月、年の平均価格、分散
    df[f'{col}_month_mean'] = df.groupby(('month'))[col].transform('mean')
    df[f'{col}_year_mean'] = df.groupby(('year'))[col].transform('mean')
    df[f'{col}_mean'] = df[col].mean()
    df[f'{col}_month_std'] = df.groupby(('month'))[col].transform('std')
    df[f'{col}_year_std'] = df.groupby(('year'))[col].transform('std')
    # その野菜の価格帯
    df[f'{col}_std'] = df[col].std()
    # 一年間の価格周期
    df[f'{col}_year_min'] = df.groupby(('year'))[col].transform('min')
    df[f'{col}_year_max'] = df.groupby(('year'))[col].transform('max')
    df[f'{col}_anual_wave'] = (df[col] - df[f'{col}_year_min']) / (df[f'{col}_year_max'] - df[f'{col}_year_min'])
    df[f'{col}_wave_mean'] = df.groupby(('month'))[f'{col}_anual_wave'].transform('mean')
    # 計算に使用した要素は削除
    df = df.drop([f'{col}_year_min', f'{col}_year_max', f'{col}_anual_wave'], axis=1)

    # 'その他'の場合は、不特定多数の構成要素があるため、価格変動率やルールベースは適用できないと想定
    if ('その他の菜類' in vegetable_local) or ('その他の野菜' in vegetable_local):
      pass
    else:
    # 価格変動率
      df[f'{col}_price_rate'] = df[f'{col}_month_mean'] / df[f'{col}_month_mean'].shift(1)
    # ルールベースで算出される価格
      df[f'{col}_rule_based_price'] = df[col].shift(1) * df[f'{col}_price_rate']

  #1ヶ月前+shift_time前までの価格を特徴量として追加
  for index in range(1, 2 + shift_time):
    df = pd.concat([df, df[target_cols].shift(index).add_suffix(f'_s{index}')], axis=1)
    diff_cols = [item + f'_s{index}' for item in target_cols]
    df = pd.concat([df, df[diff_cols].diff(index).add_suffix(f'_sd{index}')], axis=1)
  if spot_weather_cols:
    weather_mean_cols = []
    for col in spot_weather_cols:
      df[f'{col}_month_mean'] = df.groupby(('month'))[col].transform('mean')
      weather_mean_cols.append(f'{col}_month_mean')

    #1ヶ月前+shift_time前までの天候を特徴量として追加
    for index in range(1, 2 + shift_time):
      df = pd.concat([df, df[spot_weather_cols].shift(index).add_suffix(f'_s{index}')], axis=1)
      df = pd.concat([df, df[weather_mean_cols].shift(index).add_suffix(f'_s{index}')], axis=1)

  # back_month以前のデータを除去
  df = df[(df['month'] >= 10-back_month)]

  # trainとtestに分割
  train = df[df['train_flag']==1]
  train = train.drop(['train_flag'], axis=1)
  test  = df[df['train_flag']==0]
  test = test.drop(['train_flag'], axis=1)
  # testからtrainでのみ使用する列を除去
  target_cols = train_data.columns.tolist()
  test = test.drop(target_cols, axis=1)

  # すべての列をfloatに変換
  train = train.astype(float)
  test = test.astype(float)

  return train, test
from xgboost import XGBRegressor
import lightgbm as lgb
from catboost import Pool
from catboost import CatBoostRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_log_error

def predict(train, test, vegetable, vegetable_local, val_year=2017, seed_variation=1):

# 念の為NAをゼロ埋め
  train = train.fillna(0)
  test = test.fillna(0)

# rule_based_priceを特徴量から除外したほうがLBの結果が良かった
  if ('その他の菜類' in vegetable_local) or ('その他の野菜' in vegetable_local):
    pass
  else:
    train = train.drop([f'{vegetable_local}_rule_based_price'], axis=1)
    test = test.drop([f'{vegetable_local}_rule_based_price'], axis=1)

  target_cols = train_data.columns.tolist()

# 2019を指定した場合、2016~2018の3つのデータを評価データとする
  if val_year == 2019:
    self_train = train[~(train['month']==11)]
    self_val = train[(train['month']==11)]
  else:
    self_train = train[~((train['year']==val_year) & (train['month']==11))]
    self_val = train[(train['year']==val_year) & (train['month']==11)]

  self_train = self_train.drop(['year', 'month', 'day', 'day_of_year'], axis=1)
  self_val = self_val.drop(['year', 'month', 'day', 'day_of_year'], axis=1)
  test = test.drop(['year', 'month', 'day', 'day_of_year'], axis=1)

  X_train = self_train.drop(target_cols,axis=1).copy()    # 学習用のデータフレームから説明変数を抽出
  y_train = self_train[vegetable_local].copy()    # 学習用のデータフレームから目的変数を抽出(選択した野菜)
  X_val = self_val.drop(target_cols,axis=1).copy()    # 学習用のデータフレームから説明変数を抽出
  y_val = self_val[vegetable_local].copy()    # 学習用のデータフレームから目的変数を抽出(選択した野菜)

  # 目的変数を対数変換
  y_train = np.log(y_train)
  y_val = np.log(y_val)

  eval_set = [(X_val, y_val)]

  final_val_list = []
  final_predict_list = []

  for seed in range(seed_variation):
    SEED = 42 + seed
  # #xg boost
    xgb_model = XGBRegressor(seed=SEED)
    xgb_model = xgb_model.fit(X_train, y_train, eval_set=eval_set, verbose=False)
    xgb_val = xgb_model.predict(X_val)
    xgb_predict = xgb_model.predict(test)

  # #light gbm
    # 注意:動作確認をしたところ、'verbose=-1'が使えなくなったのでモデルを修正(7月末までは'verbose=-1'で実行できていました)。
    ## (修正前) publicLB : 0.08065, privateLB : 0.07290
    ## (修正後) publicLB : 0.08063, privateLB : 0.07290
    ## verboseが使える最後のバージョンを指定することで1st place solutionの完全なコードを再現できると思われます(バージョン指定の方法がわかりませんでした。スミマセン)
    # lgb_model = lgb.LGBMRegressor(seed=SEED)
    # lgb_model = lgb_model.fit(X_train, y_train,eval_set=[(X_val, y_val), (X_train, y_train)],verbose=-1)
    lgb_model = lgb.LGBMRegressor(verbosity=-1, seed=SEED)
    lgb_model = lgb_model.fit(X_train, y_train,eval_set=[(X_val, y_val), (X_train, y_train)],)
    lgb_val = lgb_model.predict(X_val)
    lgb_predict = lgb_model.predict(test)

  # #catboost
    train_pool = Pool(X_train, y_train)
    validate_pool = Pool(X_val, y_val)
    cat_params = {'logging_level':'Silent' , 'random_seed':SEED}
    cat_model = CatBoostRegressor(**cat_params)
    cat_model = cat_model.fit(train_pool, eval_set=validate_pool)
    cat_val = cat_model.predict(X_val)
    cat_predict = cat_model.predict(test)

  # #random forest
    rg = RandomForestRegressor(n_jobs=-1, random_state=SEED)
    rg = rg.fit(X_train,y_train)
    rg_val = rg.predict(X_val)
    rg_predict = rg.predict(test)

  # ensemble
    final_val = (xgb_val + lgb_val + cat_val + rg_val) / 4
    final_predict = (xgb_predict + lgb_predict + cat_predict + rg_predict) / 4
    final_val_list.append(final_val)
    final_predict_list.append(final_predict)
  final_val = np.mean(final_val_list, axis=0)
  final_predict = np.mean(final_predict_list, axis=0)

  val_rmsle = np.sqrt(mean_squared_log_error(y_val.values, final_val))

  # 予測値を元の値に戻す
  final_predict = np.exp(final_predict)

  return final_predict, val_rmsle,
def afterprocessing(df, vegetable_local, final_predict, val_rmsle, test):
  # 参考サイトの「生鮮野菜の価格予測 1位 解法 & 振り返り」を参考に直近の価格±SD値でキャップを設定
  ## ただし、年間通して値動きが少なくSD値でキャップすると精度低下すると想定されるキノコ類、大きな価格変動が想定される露地裁倍の冬野菜、その他野菜は除外
  ignore_vegetable = ['えのきだけ','しめじ', '生しいたけ', 'かぶ', 'ねぎ', 'カリフラワー', 'その他の菜類', 'その他の野菜']

  if any(vegetable_local.startswith(veg) for veg in ignore_vegetable):
    pass
  else:
    df_diff = df[(df['year']==2019)]
    df_diff[f'{vegetable_local}_diff'] = df_diff[vegetable_local].diff(1)

    max_cap = df_diff[df['month']==10][vegetable_local].mean() + df_diff[f'{vegetable_local}_diff'].std()
    min_cap = df_diff[df['month']==10][vegetable_local].mean() - df_diff[f'{vegetable_local}_diff'].std()
    if max_cap < final_predict[0]:
      final_predict[0] = max_cap
    elif min_cap > final_predict[0]:
      final_predict[0] = min_cap

  return final_predict, val_rmsle,
# 価格予想の実行
output_id = []
output_list = []

for vegetable in vegetable_list:
  best_rmsle_mean = []
  sampling = vegetable_params[vegetable]['shift_num']
  drop_year = vegetable_params[vegetable]['drop_year']
  if vegetable_params[vegetable]['predict_type'] == 'all_year':
    start = 3
    end = 4
  else:
    start = 0
    end = 3
  target_cols = train_data.columns[train_data.columns.str.startswith(vegetable)].tolist()
  for cols in target_cols:
    if vegetable_params[vegetable]['predict_type'] == 'rule_based':
      train, test = preprocessing(df, vegetable, df[cols].name, 1, 1, drop_year)
      predict_result = rule_based_predict(df, df[cols].name, test)
      final_predict = predict_result[0]
      best_rmsle = 0
    else:
      search_best = []
      for index in range(start,end):
        rms_list = []
        val_year = 2016+index
        if val_year == drop_year:
          continue
        best_rmsle = np.inf
        best_month = sampling
        best_shift = sampling

        # 最適な説明変数の組み合わせを網羅的に探索
        for back_month in range(sampling+1):
          for shift_value in range(sampling+1):
            train, test = preprocessing(df, vegetable, df[cols].name, back_month, shift_value, drop_year)
            predict_result, rmsle = predict(train, test, vegetable, df[cols].name, val_year, 1)
            rms_list.append(rmsle)
            if rmsle < best_rmsle:
              best_rmsle = rmsle
              best_month = back_month
              best_shift = shift_value

        # 最もrmsleが小さかった条件を推論結果の候補として実行
        train, test = preprocessing(df, vegetable, df[cols].name, best_month, best_shift, drop_year)
        # 推論結果の候補はSEED値違いを5回やって精度を高める
        predict_result, rmsle = predict(train, test, vegetable, df[cols].name, val_year, 5)
        predict_result, rmsle = afterprocessing(df, df[cols].name, predict_result, rmsle, test)
        search_best.append([predict_result[0], rmsle])

      # 推論結果の候補の中で最もrmsleが小さかったものを、最終的な推論結果として採用
      min_item = min(search_best, key=lambda x: x[1])
      final_predict = min_item[0]
      best_rmsle = min_item[1]

    output_id.append(df[cols].name)
    output_list.append(final_predict)
    best_rmsle_mean.append(best_rmsle)
  print(f'{vegetable},{np.mean(best_rmsle_mean)}')
submit_df = pd.concat([pd.Series(output_id).rename('id'), pd.Series(output_list).rename('y')], axis=1)
submit_df.to_csv(f'/content/drive/MyDrive/share/competition/野菜取引価格の予測/output/1st_place_solution.csv',index=False)
えのきだけ,0.00545146274221548
かぶ,0.028456610187304183
かぼちゃ,0.0015619669716817608
かんしょ,0.01014035824791077
きゅうり,0.0
こまつな,0.0
ごぼう,0.0
さといも,0.0
さやいんげん,0.0019966826356267453
さやえんどう,0.0007089079808857424
ししとうがらし,0.0
しめじ,0.002462619115155452
しゅんぎく,0.0
しょうが,0.0058740684539366865
その他の菜類,0.0027851406513893506
その他の野菜,0.003832212901724875
たまねぎ,0.0
だいこん,0.0
ちんげんさい,0.0
なす,0.0
なめこ,0.004151630001872982
にら,0.0
にんじん,0.0
にんにく,0.0
ねぎ,0.010230319886603495
はくさい,0.0
ばれいしょ,0.0
ほうれんそう,0.015295670132915242
みずな,0.0
みつば,0.0
やまのいも,0.0
れんこん,0.0
カリフラワー,0.012794341513820529
キャベツ,0.0
セルリー,0.0
トマト,0.0
パセリ,0.0
ピーマン,0.0
ブロッコリー,0.0
ミニトマト,0.0
レタス,0.0
生しいたけ,0.002228537535477532

添付データ

  • Aws4 request&x amz signedheaders=host&x amz signature=28f78368f2e1d4fc8da92f237ecc488ddb551216c0aeca8471cd6203ad3ec824
    ProbSpace_official

    T.T様

    お世話になっております。ProbSpace運営事務局です。
    1st place solutionのご公開、ありがとうございます。

    Open Review期間につきましては、8/29までと設定させていただきます。
    質疑対応等お手数おかけいたしますが、よろしくお願いいたします。

    Icon5
    marble

    1位獲得おめでとうございます!
    ルールベース(27野菜)と機械学習(15野菜)のハイブリッドモデルとして理解しました。
    とても複雑なモデルで選択すべき項目も多いと思いますので、そのあたりの質問になりますが、
    どのあたりを根拠にして各野菜をルールベースと機械学習にグループ分けていますでしょうか?
    またrule_based_predictの設定(月平均価格を使用して予測、価格変動が最も近い年の価格を使用して予測、前月の値+その年のプラス側の変動値を使用して予測等)もどのように選択していますでしょうか?
    ご回答宜しくお願い致します。

    Icon18
    T.T

    ありがとうございます!

    基本的に天候の影響を受けにくく生産が安定すると予想される冬野菜以外の野菜はルールベースにしました。
    一方、きのこ類やかぼちゃ等の一部野菜は機械学習でも評価値がよかったため、機械学習のコンペなので機械学習を採用しました。
    ルールベースの設定については、価格変動を周期性を有する信号波形と捉え、ひとつ前の月の価格と価格変動率をかけ合わせたもの(基本ルール)で一旦値を算出し、描画したグラフを見ながら前年までの傾向と異なるものは平均値、上ブレ、下ブレ、最も傾向が類似した年の値に置き換えました。
    それでも傾向に近い値を出せなかった’しゅんぎく’は専用のルールを用意して予測しました。

    あとは、本コンペ初期のトピックで’「LBを参考にある特定の野菜にのみ後処理を加える」という行為は許容される’ということで、
    スコアを参考にしてモデルを最適化するらしいと考え、基本ルールから他のルールに変更したり、機械学習とルールベースを入れ替えたりして提出し、スコアが上がったら、そのルールを採用しました。

    よろしくお願いします。

    Icon5
    marble

    ご回答ありがとうございます。
    最終的にLBのスコアを参考にしてモデルを最適化したということ、理解しました。
    私もCVのスコアは役に立たなかったのでLBのスコアを参考に最適化しましたが、
    少ないパラメータの最適化でもかなりの試行回数が必要となりました。
    T.Tさんのモデルは見た感じpredict_type, shift_num, drop_year, mean_price_vegetable, month_mean_price_vegetable, anual_wave_price_vegetable, max_std_price_vegetable, ...
    と選択すべきパラメータが多いので、どのように対象を絞って最適化できたのかに興味があります。
    こちらの部分について、各野菜ごとどのような手順にてスコアを上げたのかご説明を頂けると助かりますが可能でしょうか?
    (各野菜について、主観的に選択したもの、過去のデータから統計的に決定するもの、LBのスコアを参照にしたもの。その辺りの戦略を知りたいと思っています)
    よろしくお願い致します。

    Icon18
    T.T

    回答イメージはあるのですが、資料作成に時間を要しておりますので少しずつ回答させてください。
    また、途中経過を残しておりませんでしたので、スコアを上げた手順については記憶している範囲でご回答します。
    ご了承ください。
    コンペ自体のお作法も勉強中の身ですので、自身で戦略と呼べるものはまだ持っていないと考えていますが、
    少しでも参考になりましたら幸いです。

    ルールベースの数式の解説と、drop_yearの選択理由をまとめた資料をつくりましたので共有します。
    (気力があったら清書します。。。)
    https://probspace-stg.s3-ap-northeast-1.amazonaws.com/uploads/user/693d5e5a107b597d336d06d4c3810a4e/files/2023-08-24-0330/%E9%87%8E%E8%8F%9C%E5%8F%96%E5%BC%95%E4%BE%A1%E6%A0%BC%E3%81%AE%E4%BA%88%E6%B8%AC%E8%A7%A3%E8%AA%AC.pdf

    ルールベースの数式については、表現したい波形を作れているか。を判断基準に、グラフを眺めながらアルゴリズムを考えました。
    それっぽいものができたら提出して、スコアが上がったらよさそう、スコアが下がったらダメそう。という試行を行いました。
    drop_yearについては、ぱっと見で外れ値っぽい年が含まれる野菜についてdrop_yearを設定したところスコアが上がったので、目視で外れ値っぽい場合はdrop_yearに設定することにしました。
    そのため、drop_yearについてはLBのスコアを使った最適化はほぼやらなかったと記憶しています。

    predict_type, shift_numについては、これから資料をまとめていきますが、
    shift_numについては、増やしても最も良い評価値が変わらなかったので、実行時間短縮のため、0 or 1にした背景があります。
    ■かぶ(shift_num=1)
    c563bad2-ce83-4e7e-87d6-403f8deaa364.png
    ■かぶ(shift_num=6)
    da23a549-7d3a-4fa9-b4de-e52a8067d2ed.png
    どちらも最も良い評価値は同じ(だったらshift_num=1でいいのでは?)

    predict_typeのsingle_yearとall_yearの選択については、波形の類似性が予測に影響を与えるイメージがあったため、single_yearのほうが精度良く予測できるという前提はあるものの、精度がよくてもFeature Importanceが自分の感覚とあっていない場合は、all_yearで平滑化させた予測をしようと考えました。
    ■predict_type = single_yearでFeature Importanceが自分の感覚とあっている野菜(ほうれんそう)
    2016年を評価値とした結果
    47c93d40-6471-4678-b139-1edc057b6d37.png
    Feature Importance
    06180997-1e4f-47b6-a938-c791622551f1.png
    その年の平均価格が支配的(それっぽい)

    ■predict_type = single_yearでFeature Importanceが自分の感覚とあっていない野菜(かぶ)
    2016年を評価値とした結果
    3ac8ec66-7d55-4542-85b5-be5da6bd2d4a.png
    Feature Importance
    4449bc21-e96d-4ff7-9e91-d8cda648eca8.png
    勝浦の最大降水量が支配的(本当?)

    predict_type, shift_numの資料できましたら共有します。
    よろしくお願いします。

    Icon5
    marble

    すません。ここまで詳細を要求したつもりはなかったので、手間を取らせて申し訳ございません。
    とても参考になります。他のメンバーも見ていると思いますので、資料のリンクが壊れているのを一旦指摘しておきます。
    https://probspace-stg.s3-ap-northeast-1.amazonaws.com/uploads/user/693d5e5a107b597d336d06d4c3810a4e/files/2023-08-24-0330/%E9%87%8E%E8%8F%9C%E5%8F%96%E5%BC%95%E4%BE%A1%E6%A0%BC%E3%81%AE%E4%BA%88%E6%B8%AC%E8%A7%A3%E8%AA%AC.pdf

    Icon18
    T.T

    ご指摘ありがとうございます。リンク修正しました。
    また、資料に、えのきだけについて、shift_num=6に設定した結果と考察の内容を追加しましたので共有します。
    https://probspace-stg.s3-ap-northeast-1.amazonaws.com/uploads/user/693d5e5a107b597d336d06d4c3810a4e/files/2023-08-24-2326/%E9%87%8E%E8%8F%9C%E5%8F%96%E5%BC%95%E4%BE%A1%E6%A0%BC%E3%81%AE%E4%BA%88%E6%B8%AC%E8%A7%A3%E8%AA%AC.pdf
    他の野菜も同様にshift_numの値を変えて評価値がどのように推移するかを確認しました。
    全体的な結果として、shift_numを増やすと学習データに含める月が増えるのですが、評価値は悪くなる傾向でした。
    コンペ中はshift_numは少ないほうがよさそう。程度の考察でしたが、月をさかのぼりすぎると、季節が変わり、生産地や生産方法、消費行動も変わるので、含める月が多いほどノイズが多くなっているのでは?と今は考えています。
    predict_typeのsingle_yearとall_yearの選択についてはトピック内でも共有しておりますが、改めて資料に落とし込みます。
    (トピックで解説した内容をそのまま資料の一部としてマージするイメージです)

    よろしくお願いします。

    Icon5
    marble

    資料の方ありがとうございました。
    資料の内容より主観的に選択している部分について理解致しました。
    全大抵な流れとしまして下記のような手順で行われたと想像しています。
    1、各野菜ごとのデータを確認し、主観的にdrop_yearを設定。
    2、機械学習で全体調査, validationの結果を見て、shift_numsを決定。
    3、2のshift_numsを使って機械学習(single year)でshift_year、back_month, shift_numsはRMSLEが最小の組み合わせを選ぶ。
    4、feature importanceを確認して感覚と合わなければall_yearに変換して、同様の手順で3,4を実行しfeature importanceを確認。
    5、それでも感覚と合わない場合はルールベースに変更
    6、ルールベースは値動きに合わせてモデルを選択>submitしてスコアを確認
    7、スコアの改善が小さいものはルールベースのモデルを変更
    このような流れで正しいでしょうか。
    これだとsubmit42回x2でルールベース2パターンの確認が取れるとして、現実的な戦略に思えました。
    またvalidationについては、trainingのパラメータを探す意味において有用であるとことも理解できました。
    よって設定パラメータが多いように見えましたが、
    A,機械学習かルールベースのどちらか、
    B、ルールベースの場合、mean_price_vegetable、month_mean_price_vegetable、anual_wave_price_vegetable、max_std_price_vegetable、min_std_price_vegetableのどのルールを適用するか。
    となりデータの動きにより、
    B1:データの変動が特徴的でない場合mean_price_vegetable
    B2:データの変動が特徴的の場合month_mean_price_vegetable、
    B3:データの変動が各年により異なる場合、anual_wave_price_vegetable
    B4:データの変動が増加傾向にある場合、max_std_price_vegetable
    B5:データの変動が減少傾向にある場合、min_std_price_vegetable
    とある程度決まるため、選択の余地はあまりない。と理解しました。

    まとめて、
    feature importanceを参考にしてモデルの選択行うこと、validationをtraingパラメータ設定に使用すること、
    により、時系列の予測が難しい状況でも、パラメータの選択をtrainingデータ内で行うことができることを理解しました。
    (私のモデルの場合validationを別モデルとの比較で使用していましたためvalidationは参考にならないと思っていましたが、T.Tさんのvalidationは同一モデルのパラメータ設定なので、連続的であり、時間変化の影響を受けにくいことから有効であると理解しました)
    とても参考になりました、ありがとうございました。

    Icon18
    T.T

    手順を分解いただき、ありがとうございます。
    機械学習とルールベースについて、ごちゃまぜの状態でコードを作っていましたが、
    スコアを基準としたモデルの選択を知ることができて勉強になりました。

    ルールの選択について補足しますと、
    基本ルールと月平均で予測したグラフを描画してみて、
    どちらかのルールで予測できそうか、
    他のルールが必要そうかを検討しながら進めていました。
    (よくわからないやつは、一番当たりそうな基本ルールにしています)
    ■ごぼうのルール比較
    9c7af2a5-18b7-4c15-8889-d20875bb7571.png
    基本ルールを使えば価格変動を捉えられそう

    ■みつばのルール比較
    212f7b12-a505-4049-9bca-363fcd5bcfec.png
    11月については、基本ルールより月平均のほうがよさそう

    ■トマトのルール比較
    005946de-099b-4b49-ae9a-920161c7c18f.png
    どちらのルールもいまいちあっていない
    → 他のルールを検討したほうがよさそう
    → グラフを眺めてみると、年間の値動きが2018年に近そう
    → 価格変動が一番近い年の値を予測値にできれば自分としては満足

    主観的な話ばかりになってしまい、
    大変恐縮ではございますが、
    よろしくお願いします

    Icon18
    T.T
    Aws4 request&x amz signedheaders=host&x amz signature=28f78368f2e1d4fc8da92f237ecc488ddb551216c0aeca8471cd6203ad3ec824
    ProbSpace_official

    T.T様

    お世話になっております。PROBSPACE運営事務局です。
    大変ご丁寧に質疑に対応いただき、誠にありがとうございました。

    OpenReview期間が終了しましたので、順位確定とさせていただきます。
    コンペティションの優勝、おめでとうございます。

    この後の手続きにつきましては、後ほど個別でご案内差し上げます。
    どうぞよろしくお願いいたします。

    Favicon
    new user
    コメントするには 新規登録 もしくは ログイン が必要です。