コンビニ商品の売上予測

気象シミュレーションデータから、各商品が何個売れるか当ててみよう!

賞金: 100,000 参加ユーザー数: 486 約2年前に終了

テーマの背景

「雨の日には、全体的に売上が落ち込む」
「猛暑日にはビールが人気」
「肌寒くなって来ると、おでんが売れ筋になる」
気温や降雨量等の気象条件が、購買行動に影響を与えることは古くから知られており、発注計画や販促施策に役立てられてきました。

特に小売業界では活用が進んでおり、在庫コストや品不足による機会損失をできる限り抑えることを目的に、殆どの企業が気象情報に基づいた販促計画を実施しています。

さらに近年では、気象情報をもとにより高度な販促支援をするツールが登場し始めました。
例えば、天気予報専門メディア「tenki.jp」では、
ユーザーの位置情報やアプリの利用状況を気象情報とかけ合わせて分析し、天候条件を踏まえて最適なタイミングで商品を広告配信する「天気プッシュ」と呼ばれるサービスを展開しています。

このように、気象データのビジネス活用は、古くから商品販売において重視されている一方で、近年はより一層注目が集まる分野です。

そこで、今回のコンペティションでは、気温や湿度等の気象情報をもとに、あるコンビニで扱う商品について売上数を予測するアルゴリズムを構築していただきます。
コンペティションを通じて、気象情報と商品売上との間にある、隠れた法則を探してみてください。

賞金

1位 100,000円
※ 対象者には、コンペティション終了後、メールにて連絡いたします。

スケジュール

提出締切 2022/11/13 22:00 JST
LB公開 2022/11/13 24:00 JST

ダウンロード

データをダウンロードするにはログインまたはユーザー登録して下さい

概要

コンペでは主に2種類のデータを使用します。

  • 訓練データ(train_data.csv)
  • テストデータ(test_data.csv)
  • サンプル提出データ(sample_submission.csv)  ※参考用

訓練データおよび、テストデータには、それぞれ350、21レコードのサンプルデータが含まれています。
訓練データには、各日の天候情報と各商品売上数が記載されています。機械学習モデルの構築に使用ください。

構築した機械学習モデルを使用して、テストデータセットの対象期間3週間における商品ごとの売上数を予測してください。


データの形式

データセットのカラムは以下の通りになっています。

データ
カラム名 説明
id ユニークキー
date 日付
highest 最高気温
lowest 最低気温
rain 降水量(mm)
ice1 商品ice1の売上数
ice2 商品ice2の売上数
ice3 商品ice3の売上数
oden1 商品oden1の売上数
oden2 商品oden2の売上数
oden3 商品oden3の売上数
oden4 商品oden4の売上数
hot1 商品hot1の売上数
hot2 商品hot2の売上数
hot3 商品hot3の売上数
dessert1 商品dessert1の売上数
dessert2 商品dessert2の売上数
dessert3 商品dessert3の売上数
dessert4 商品dessert4の売上数
dessert5 商品dessert5の売上数
drink1 商品drink1の売上数
drink2 商品drink2の売上数
drink3 商品drink3の売上数
drink4 商品drink4の売上数
drink5 商品drink5の売上数
drink6 商品drink6の売上数
alcol1 商品alcol1の売上数
alcol2 商品alcol2の売上数
alcol3 商品alcol3の売上数
snack1 商品snack1の売上数
snack2 商品snack2の売上数
snack3 商品snack3の売上数
bento1 商品bento1の売上数
bento2 商品bento2の売上数
bento3 商品bento3の売上数
bento4 商品bento4の売上数
tild1 商品tild1の売上数
tild2 商品tild2の売上数
men1 商品men1の売上数
men2 商品men2の売上数
men3 商品men3の売上数
men4 商品men4の売上数
men5 商品men5の売上数
men6 商品men6の売上数
目標

テストデータセットの天候情報から、各商品の売上数。y(売上数)を非負整数で予測してくだい。

評価指標

モデルの予測性能は評価関数”Pinball loss Error”で評価されます。

  (Pinball lossの評価値)

$$
\frac{1}{|q|} \sum_{\tau \in q} L_{\tau}(y, \hat{y})
$$

$$
\begin{array}{ll} L_{\tau}(y,\hat{y}) & = & (y - \hat{y}) \tau & \textrm{ if } y \geq \hat{y} \\ & = & (\hat{y} - y) (1 - \tau) & \textrm{ if } \hat{y} > y \end{array}
$$

  • 評価値は0以上の値をとり、精度が高いほど小さな値となります。
  • $q = (0.01, 0.1, 0.5 0.9 0.99)$とします。

提出ファイルの形式

回答用のsubmission.csvを用意する(エントリーとヘッダー行を含む) 。
提出されたファイルに余分な行や列が含まれていた場合はエラーとなります。

提出ファイルは以下の列のみを必ず含んでください:

  • id(1-21の整数)
  • item_q(商品名itemはtrain_data.csvのカラム順、qは昇順となります。)

以下は提出ファイルの例です。
id,ice1_0.01,ice1_0.1,ice1_0.5,ice1_0.9,ice1_0.99,ice2_0.01,ice2_0.1,ice2_0.5
1,18.517,21.043,27.061,62.297,128.690,63.462,64.212,65.504
2,14.840,17.721,23.035,61.899,141.993,54.360,54.967,56.546
3,4.989,9.192,11.768,37.785,105.411,29.853,30.132,31.939
4,8.009,11.868,14.877,41.923,105.885,37.590,37.927,39.578
5,14.050,17.141,21.883,53.773,119.423,52.465,53.039,54.487
6,13.868,17.204,21.084,40.240,77.116,52.221,52.763,53.896
7,10.020,13.858,17.120,30.913,63.966,42.271,42.763,44.002
8,11.314,14.973,18.608,34.460,69.959,45.492,46.026,47.245
9,14.686,17.894,22.461,42.532,81.912,53.878,54.524,55.661
10,22.174,24.287,31.141,66.414,127.121,72.532,73.416,74.509

コンペティションルール

■Open Review Competition

本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。


賞金対象ユーザー

コンペ終了後1週間以内:
トピックにて、学習過程の分かるコードの公開をお願いいたします。 (簡易解説までつけていただけると助かります。)

コード公開後1週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。


レビュアー(ユーザーの皆様)
コード公開後1週間: 公開コードを確認いただき、チーティングが疑われる場合は、トピックを通して質疑の投稿をお願いいたします。

レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。

■順位決定ロジック
  1. コンペ期間中はPublicリーダーボード(以下LB)により暫定評価を、最終結果についてはPrivate LBにより評価します。
    ※ Private LBはコンペ終了と同時に表示されます。
  2. Private スコア計算に使われるファイルについては、2つまで選択可能です。
    ※ 未選択の場合は、Public スコアの上位ファイルが提出上限まで自動選択されます。
  3. スコアが同値の場合は、早い日時に提出いただいたユーザーが上位となります。
  4. コンペ終了後であっても、不正が発覚の際は、対象ユーザーは失格となり、全体の順位が繰り上がります。
    順位繰上げにより賞金対象者となられた場合は、繰上げ日より一週間以内に、トピックにてコードを公開いただき、「Open Review Competition」と同様のフローにて順位を確定させていただきます。
■タイムライン

開始日 2022/8/16 14:00 JST
提出締切 2022/11/13 22:00 JST
LB公開 2022/11/13 24:00 JST

エントリー締め切り なし

■システム利用
  • 参加者ごとに1つのアカウントでご参加ください
  • チーム参加の場合は、最大5名までエントリー可能です
  • 1日あたり、最大5回までの提出が可能です
■禁止事項
  • ユーザー間での情報共有
    コンペティションに関連するコード・データを、チーム外のユーザーと共有することはできません。全参加者が利用できる場合に限り、共有可能です。

  • 外部データ/学習済みモデルの使用
    本コンペティションの基本情報/データから取得できるデータのみを用いてチャレンジして下さい。コンペ外データを用いて学習されたモデルの使用も禁止とします。

※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。

■運営からのお願い

公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。


FAQ

このコンペティションでは賞金はでますか?

はい。
最も精度の高い学習モデルを作成した優勝者には、賞金10万円を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。

チームで参加できますか?

可能です。チームページから作成いただけます。

どこでアカウントをつくればいいですか?

こちらから作成いただけます。

コンペティション参加にはアカウント登録が必要となりますのでご注意ください。

コードを提出するにあたって Seed を固定する必要はありますか?

Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認めています。

提出回数はいつリセットされますか?

ファイル提出後、23時間ごとにリセットとなります。
グローバル展開していくにあたり、居住国(時差)による有利・不利を最小化するため、一定時間でリセットする仕様としております。

概要

このチュートリアルでは、店舗の売上データに対して

  • データの読み込み
  • データの確認と前処理
  • Statsmodelを用いて回帰モデルの作成、学習
  • 提出用データの作成

を行います。

環境

import pandas as pd
import numpy as np
import statsmodels
!python3 --version
print("Pandas", pd.__version__)
print("Numpy", np.__version__)
print("statsmodels", statsmodels.__version__)
import matplotlib
print("Matplotlib", matplotlib.__version__)
Python 3.9.13
Pandas 1.4.3
Numpy 1.22.4
statsmodels 0.13.2
Matplotlib 3.5.2

データの読み込み

まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありますが、pandasread_csv関数はその中でも機能が豊富で、一般的に使われている関数です。
こちらの関数はcsvデータを読み込み、pandas.DataFrameとして文字列を返してくれます。

#データの読み込み
import pandas as pd
train_data = pd.read_csv("train_data.csv", index_col='id')
print(train_data.shape)
(350, 43)

また、DataFrameには.head()というメソッドが定義されており、これを呼び出すとDataFrameの先頭の数行を確認できます。

columns = train_data.columns
train_data.head()

date highest lowest rain ice1 ice2 ice3 oden1 oden2 oden3 ... bento3 bento4 tild1 tild2 men1 men2 men3 men4 men5 men6
id
1 4/11 21.9 12.4 0.0 25 72 26 10 23 52 ... 70 27 12 12 57 30 41 38 37 35
2 4/12 25.9 13.9 0.0 30 85 33 9 18 42 ... 23 9 5 8 19 9 13 26 4 16
3 4/13 20.9 11.9 0.0 21 68 28 12 22 57 ... 19 6 4 9 23 9 11 33 4 13
4 4/14 18.8 11.4 0.0 19 62 35 13 29 62 ... 74 28 15 17 55 35 46 46 51 46
5 4/15 22.1 13.5 19.0 21 72 32 10 24 44 ... 69 26 4 9 54 33 39 40 41 40

5 rows × 43 columns

データの確認と前処理

訓練データの商品について、価格分を確認してみましょう。

import matplotlib.pyplot as plt
%matplotlib inline
plt.hist(train_data['ice1'], log=True)
(array([295.,  28.,  16.,   9.,   0.,   1.,   0.,   0.,   0.,   1.]),
 array([ 13. ,  74.5, 136. , 197.5, 259. , 320.5, 382. , 443.5, 505. ,
        566.5, 628. ]),
 <a list of 10 Patch objects>)

1a1334eb-a906-4596-bde3-d8133b33008d.png

plt.hist(train_data['ice2'], log=True)
(array([13., 59., 56., 43., 55., 55., 30., 28., 10.,  1.]),
 array([ 16. ,  29.7,  43.4,  57.1,  70.8,  84.5,  98.2, 111.9, 125.6,
        139.3, 153. ]),
 <a list of 10 Patch objects>)

653e2195-06ff-4fa7-aedd-0f5f24a9eb4b.png

外れ値を含むカラムと含まないカラムがあるようです

続いて、下記コードから、使用するデータ全体の概観を確認します。
各項目について欠損値('null')がどの程度含まれているか確認できます。データの形式も判別可能です。

train_data.isnull().sum(axis=0)
date        0
highest     0
lowest      0
rain        0
ice1        0
ice2        0
ice3        0
oden1       0
oden2       0
oden3       0
oden4       0
hot1        0
hot2        0
hot3        0
dessert1    0
dessert2    0
dessert3    0
dessert4    0
dessert5    0
drink1      0
drink2      0
drink3      0
drink4      0
drink5      0
drink6      0
alcol1      0
alcol2      0
alcol3      0
snack1      0
snack2      0
snack3      0
bento1      0
bento2      0
bento3      0
bento4      0
tild1       0
tild2       0
men1        0
men2        0
men3        0
men4        0
men5        0
men6        0
dtype: int64

欠損値が含まれているカラムは特にないようです。

予測モデルの作成、学習

モデルに投入する目的変数(y)、説明変数(X)を作成します。

import statsmodels.api as sm
from statsmodels.regression.quantile_regression import QuantReg

train_columns = ['highest', 'lowest', 'rain']
target_columns = columns[4:]

x = train_data[train_columns]
X = sm.add_constant(x)
Y = train_data[target_columns]

いよいよ予測モデルの作成に入ります。
model.fit('説明変数','目的変数')と記述することでモデルの学習をします。目的変数を説明変数の組み合わせにより説明可能とする回帰モデルを作成できます。

Y

ice1 ice2 ice3 oden1 oden2 oden3 oden4 hot1 hot2 hot3 ... bento3 bento4 tild1 tild2 men1 men2 men3 men4 men5 men6
id
1 25 72 26 10 23 52 35 180 254 270 ... 70 27 12 12 57 30 41 38 37 35
2 30 85 33 9 18 42 26 202 219 235 ... 23 9 5 8 19 9 13 26 4 16
3 21 68 28 12 22 57 31 164 210 223 ... 19 6 4 9 23 9 11 33 4 13
4 19 62 35 13 29 62 33 193 242 251 ... 74 28 15 17 55 35 46 46 51 46
5 21 72 32 10 24 44 33 218 271 274 ... 69 26 4 9 54 33 39 40 41 40
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
346 27 77 30 29 36 77 53 147 197 206 ... 17 9 5 8 23 12 13 35 4 17
347 14 33 32 76 73 159 96 116 221 207 ... 72 26 5 8 51 31 39 40 37 39
348 20 51 34 104 108 185 134 105 193 189 ... 70 28 5 10 51 31 39 37 31 38
349 19 50 33 79 91 160 94 111 211 207 ... 20 8 6 8 21 9 11 27 4 18
350 19 53 31 18 30 69 42 161 232 251 ... 63 27 6 7 52 30 36 41 47 36

350 rows × 39 columns



#回帰モデルのインスタンス化
model = [QuantReg(Y[c], X) for c in target_columns]
qs = np.array([0.01, 0.1, 0.5, 0.9, 0.99])
#予測モデルの作成
[[m.fit(q=q) for q in qs] for m in model]

テストデータに対する出力

最後に、作成したモデルを使用してテストデータでの売上数を予測します。

path_test = "test_data.csv"
test_data = pd.read_csv(path_test, index_col='id')
test_data.head()

date highest lowest rain
id
1 3/27 19.7 7.3 0.0
2 3/28 16.9 9.0 0.0
3 3/29 9.3 6.8 0.0
4 3/30 11.7 7.2 3.5
5 3/31 16.3 7.3 1.5
x = test_data[train_columns]
test_X = sm.add_constant(x)
results = dict({})
for target in target_columns:
    model = QuantReg(Y[target], X)
    for q in qs:
        res = model.fit(q=q)
        pred_y = test_X @ res.params
        #pred_y = model.predict(test_X)
        results[(target, q)] = pred_y
/usr/local/lib/python3.7/site-packages/statsmodels/regression/quantile_regression.py:192: IterationLimitWarning: Maximum number of iterations (1000) reached.
  ") reached.", IterationLimitWarning)
/usr/local/lib/python3.7/site-packages/statsmodels/regression/quantile_regression.py:192: IterationLimitWarning: Maximum number of iterations (1000) reached.
  ") reached.", IterationLimitWarning)
/usr/local/lib/python3.7/site-packages/statsmodels/regression/quantile_regression.py:192: IterationLimitWarning: Maximum number of iterations (1000) reached.
  ") reached.", IterationLimitWarning)
/usr/local/lib/python3.7/site-packages/statsmodels/regression/quantile_regression.py:192: IterationLimitWarning: Maximum number of iterations (1000) reached.
  ") reached.", IterationLimitWarning)
/usr/local/lib/python3.7/site-packages/statsmodels/regression/quantile_regression.py:192: IterationLimitWarning: Maximum number of iterations (1000) reached.
  ") reached.", IterationLimitWarning)
/usr/local/lib/python3.7/site-packages/statsmodels/regression/quantile_regression.py:192: IterationLimitWarning: Maximum number of iterations (1000) reached.
  ") reached.", IterationLimitWarning)
submit_rows = [[f'{k[0]}_{k[1]}']+ list(v.values) for k, v in results.items()]

先ほど使用したmodel.predict('説明変数')の'説明変数'にテストデータの値を代入することで、テストデータの予測値を算出できます。

下記のようにして、提出用のsubmission.csvを出力します。

#テスト結果の出力
submit_df = pd.DataFrame(np.array(submit_rows)[:, 1:], index=np.array(submit_rows)[:, 0])
submit_df.columns = list(range(1, 22))
submit_df = submit_df.transpose()
submit_df.index.name = 'id'
submit_df.to_csv('submission.csv')

「気象情報を利用した、コンビニ商品の売上予測」コンペティション参加規約

コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。

第1条(適用)

  1. 参加者(第2条に定義します。)は、コンペティションに参加した時点で、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に同意したものとみなされます。
  2. 本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールは、コンペティションの終了後も参加者に適用されます。

第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。

  1. 「本コンペ」とは、当社ウェブサイト上で開催されるAI開発又はデータ分析等に関するコンペティションのうち、本規約に紐づく特定のコンペティションを意味します。
  2. 「主催者」とは、当社またはユーザーのうち、本コンペを主催する者を意味します。また、本コンペが、当社の顧客又は提携先の企業、学校その他の団体等がスポンサードするものである場合は、当該団体等も主催者の定義に含まれます。
  3. 「参加者」とは、ユーザーのうち、主催者側以外の立場で本コンペに参加する方を意味します。
  4. 「成果物」とは、本コンペにおいて参加者により開発される学習済みモデル、そのソースコード及び乱数シード等の設定値を意味します。
  5. 「入賞者」とは、当社より本コンペに入賞した旨の通知を受けた参加者を意味します。
  6. 「知的財産権」とは、著作権(著作権法第27条及び第28条に定める権利を含みます。)、特許権、実用新案権、商標権、意匠権、その他のノウハウ及び技術情報等の知的財産権(それらの権利を取得し、又はそれらの権利につき登録等を出願する権利を含みます。)を意味します。

第3条(権利の帰属)

  1. 本コンペで発生した成果物に関する知的財産権は、参加者に帰属します。

第4条(入賞者の義務)

  1. 入賞者は、本コンペで公開した成果物を、MITライセンスを適用し、商用利用の許諾条項及び著作権人格権の包括的不行使条項をライセンス条項に付与した形式で、オープンソースソフトウェアとして公開する義務を負うものとします。その前提として、入賞者は、成果物について本項に基づく方法でオープンソース化する権利を有していることを当社に対して表明保証するものとします。
    ※第三者が、授業・研修・セミナー等で活用できるようにするための規約となります。ご理解のほどよろしくお願いいたします。
  2. 当社は、以下の3点の確認が完了した時点で、本コンペの賞金または商品を、入賞者に対して授与するものとします。
    1. 入賞者が、前項に基づいて成果物のオープンソース化を実施したこと
    2. 入賞者が、本規約、利用規約、その他ご同意いただいた規約のすべて、及びコンペティションサイトに掲載されているコンペティションに関するルールの一切に違反していないこと
    3. 当社が定める方法による本人確認
  3. 当社は、入賞者が第1項に基づいてオープンソース化した成果物を、自由に商用利用することができます。

第5条(禁止事項)

  1. 参加者は、本コンペにおいて、以下の各号のいずれかに該当する行為を行ってはならないものとします。
    1. クラッキングやチート行為、なりすまし、盗用等の不正行為
    2. 第三者の知的財産権その他の権利を侵害する内容ないし態様で、参加者公開事項を公開する行為
    3. 主催者(当社以外の者に限ります。)に対する直接連絡、相談、依頼、勧誘、勧誘対応等の活動(但し、当社を介して当社が認めた方法により行うものは除きます。)
    4. 本コンペにおいて、当該コンペと直接関係のない成果物等を提出すること
    5. 本規約における参加者としての地位又は参加者としての権利義務について、譲渡、移転、担保設定、その他の処分をすること
    6. その他、本規約、参加ルール及び利用規約に違反する行為
  2. 参加者が前項に規定する禁止行為を行ったと当社が認める場合、当社は、当該参加者に事前に通知することなく、当該参加者の本コンペにおける失格処分、当社サービスの全部又は一部の利用停止、ユーザー登録の抹消、その他当社が必要と判断した措置をとることができるものとします。

第6条(本コンペの変更、中断、終了等)

  1. 当社は、参加者に事前の通知をすることなく本規約に基づく本コンペの開催内容の変更、本コンペの一時的な中断又は終了を行うことができます。
  2. 当社は、本条に基づき当社が行った措置により生じた結果及び損害について、一切の責任を負わないものとします。

第7条(損害賠償)

  1. 参加者は、本コンペに関連して、自らの責に帰すべき事由により、当社、主催者その他の第三者に損害を与えた場合には、その一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。
  2. 参加者が本規約の規定に違反したことにより主催者(当社を除きます。)その他の第三者が当社に対して何らかの訴え、異議、請求等がなされた場合において、当社から処理の要請がなされたときは、参加者は自己の責任と費用負担において、当社に代わって当該第三者との紛争を処理するとともに、当社がかかる訴え、異議、請求等により被った一切の損害(逸失利益、弁護士費用を含みます。)を賠償するものとします。

第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。

第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。

(制定)2020年6月22日