本コンペティションでは、ニューヨークの79地区におけるタクシーの乗車実績(乗車時の時刻や位置座標を含む)をもとに、各地区での将来需要を予測するモデルの開発に挑戦していただきます。
タクシー会社にとって、需要が発生するタイミングや場所を正確に予測することは大変重要です。これを見逃すと、売上の損失、顧客の待ち時間の増加、およびサービスの満足度の低下などの問題が生じる可能性があります。
近年、タクシー業界はこの需要を把握するために、ビッグデータを活用してリアルタイムの需要予測アプリを開発しています。2018年以降、JapanTaxiは「配車支援システム」というシステムを開発中で、これは天気、近隣のイベント、時間帯などの情報をもとに需要を予測し、タクシードライバーにそのデータを提供しています。
今回のコンペティションでは、上述の「配車支援システム」のような実例を参考に、ニューヨーク市の過去の乗車実績から将来の乗車数を予測するタスクを設計しました。
2017年1月1日から2019年11月30日まで30分間隔で提供される乗車実績データを基に、2019年12月1日から一週間の乗車需要を予測してください。
提供されるデータセットは、各地点の乗車実績や天候データを中心に構成されています。タクシーの需要予測をより精緻に行うためには、近隣のイベントや交通・インフラの情報も重要ですが、範囲が広がりすぎることを考慮し、今回のコンペティションのスコープからは除外しております。
100,000円
提出締切 2023年12月17日 22:00 JST
LB公開 2023年12月17日 24:00 JST
データをダウンロードするにはログインまたはユーザー登録して下さい
コンペティションに使用するデータは3種類あります。
本コンペティションでは訓練データを用いて将来予測を行うため、テストデータは提供されません。
提出ファイルのファイル形式に関しては、評価方法タブよりご確認ください。
79地区のタクシー乗車実績が、2017年1月1日の0時0分から2019年11月30日23時30分まで、30分間隔で51072期分のデータが記載されています。
例えば、0時0分のカラムには0時0分から0時30分までの時間の各地区の乗車実績数が記載されています。
0 | 1 | ... | 78 | |
---|---|---|---|---|
2017/01/01 00:00:00 | 53 | 16 | ... | 201 |
2017/01/01 00:30:00 | 83 | 62 | ... | 349 |
ニューヨーク州のロングアイランドに関するState Plane Coordinate Systemの座標系が記載されています。
地区データのインデックスは訓練データのカラムと一致します。
2017/1/1 - 2019/12/7における、ニューヨーク市の気象情報が約一時間刻みで格納されています。
各カラムの定義については、下記リンクをご参照ください。
参考:Local Climatological Data (LCD) Dataset Documentation
https://www.ncei.noaa.gov/data/local-climatological-data/doc/LCD_documentation.pdf
出典:
「TLC Trip Record Data」(NYC.gov)(https://www.nyc.gov/site/tlc/about/tlc-trip-record-data.page)
「U.S. Local Climatological Data」 (USA.gov)(https://www.ncei.noaa.gov/metadata/geoportal/rest/metadata/item/gov.noaa.ncdc:C00684/html)
乗車実績データにもとづき、2019-12-01 00:00:00から2019-12-07 23:30:00までの期間のタクシー乗車数を予測してください。
なお、2019-12-01 00:00:00の乗車数とは、2019-12-01 00:00:00 - 00:30:00までの30分間における合計を示すものとします。
提出ファイルは以下の列のみを必ず含んでください:
以下は提出ファイルの例です。
tpep_pickup_datetime,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78
2019-12-01 00:00:00,16,6,-1,9,3,0,1,17,7,19,9,193,67,0,3,0,100,14,20,268,14,8,59,5,70,103,62,138,6,17,1,196,42,160,38,63,185,21,61,7,4,166,16,3,70,150,68,107,131,15,66,1,6,88,1,8,42,1,3,6,61,226,45,13,30,115,44,74,52,70,5,49,175,11,8,1,8,17,59
2019-12-01 00:30:00,17,6,-2,6,3,0,1,13,6,3,10,172,51,0,2,0,103,10,13,265,9,7,50,5,54,85,51,135,5,16,2,163,34,121,20,40,113,11,61,6,4,192,8,2,76,82,48,83,110,11,53,1,6,107,2,8,35,0,0,5,44,194,36,14,17,83,21,38,34,50,4,46,159,11,9,1,4,0,45
提出ファイルには、
2019-12-01 00:00:00から2019-12-07 23:30:00まで、336期分のレコードをご記載ください。
提出されたファイルに余分な行や列が含まれていた場合はエラーとなりますので、ご注意ください。
本コンペでは、開催期間終了後 賞金対象者のコードを公開し、ユーザーの皆様にチーティング有無をレビューしていただき順位確定させる、オープンレビュー方式のコンペティションを行います。
コード公開後1週間:
レビュアー(ユーザー)より、チーティングの疑いに関するコメントがある場合は、ご回答をお願いいたします。
※チーティングとは無関係のコメント(ノウハウに関する質疑 等)についてもご回答いただけると幸いですが、順位確定の判断材料とは致しません。
レビュアーからの質疑と、回答状況をふまえて、最終的に運営側で順位確定を判断します。
開始日 2023/9/12 0:00 JST
提出締切 2023/12/17 22:00 JST
終了日 2023/12/17 24:00 JST
エントリー締め切り なし
※コンペ期間中であっても、不正が疑われる場合は、運営より確認のためメール連絡させていただくことがございます。一週間以内にご回答いただけない場合も、不正と判断させていただきます。
原則外部データ/学習済みモデルの使用は禁止としておりますが、正解データの入手につながらない場合は、下記承認プロセスにより使用できることといたします。
1.トピックを作成し、取得元情報とデータ(格納先URLも可)を添付
2.運営にて判断・承認
注)ただし、コンペ終了まで7日をきってからの申請は禁止とします。
公平性の担保、チーティング等の不正防止のため、予告なくルールの追加・変更を行う場合がございます。
ご不便をおかけすることもあるかと思いますが、サービス向上のためご了承ください。
はい。
最も精度の高い学習モデルを作成した優勝者には、賞金を贈呈します。
順位確定までのプロセスについては、ルール「Open Review Competition」を参照ください。
可能です。チームページから作成いただけます。
こちらから作成いただけます。
コンペティション参加にはアカウント登録が必要となりますのでご注意ください。
Seed を固定することが推奨です。
ただし、Seed を固定しなくても提出用コードとしては認められます。
このチュートリアルでは、時系列のタクシーの需要データに対して
を行います。
#環境確認
import pandas as pd
import numpy as np
import statsmodels
!python3 --version
print(pd.__version__)
print(np.__version__)
print(statsmodels.__version__)
import matplotlib
print(matplotlib.__version__)
Python 3.11.4
1.5.2
1.23.5
0.14.0
3.6.3
まずはデータを読み込んで見ましょう。csvデータの読み込みは複数のやり方がありえますが、pandas
のread_csv
関数はその中でも機能が豊富で、扱いやすいためこれを使います。
これを使うと、csvデータを読み込み、pandas.DataFrame
にして返してくれます。
','.join(['tpep_pickup_datetime'] + list(map(str, range(79))))
'tpep_pickup_datetime,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78'
#データの読み込みと前処理
import pandas as pd
train_data = pd.read_csv("train_data.csv", index_col='tpep_pickup_datetime')
print(train_data.shape)
(51072, 79)
また、DataFrame
には.head()
というメソッドが定義されており、これを呼び出すとDataFrame
の先頭の数行を確認できます。
train_data.head()
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ... | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
tpep_pickup_datetime | |||||||||||||||||||||
2017-01-01 00:00:00 | 53.0 | 16.0 | 45.0 | 38.0 | 12.0 | 6.0 | 2.0 | 47.0 | 31.0 | 238.0 | ... | 260.0 | 12.0 | 139.0 | 253.0 | 17.0 | 33.0 | 5.0 | 14.0 | 92.0 | 201.0 |
2017-01-01 00:30:00 | 83.0 | 62.0 | 59.0 | 56.0 | 19.0 | 26.0 | 8.0 | 91.0 | 48.0 | 165.0 | ... | 357.0 | 45.0 | 159.0 | 280.0 | 46.0 | 50.0 | 10.0 | 30.0 | 110.0 | 349.0 |
2017-01-01 01:00:00 | 69.0 | 83.0 | 58.0 | 45.0 | 21.0 | 27.0 | 23.0 | 102.0 | 62.0 | 113.0 | ... | 355.0 | 74.0 | 193.0 | 232.0 | 71.0 | 54.0 | 10.0 | 34.0 | 124.0 | 386.0 |
2017-01-01 01:30:00 | 76.0 | 87.0 | 56.0 | 36.0 | 27.0 | 18.0 | 25.0 | 84.0 | 87.0 | 81.0 | ... | 328.0 | 61.0 | 137.0 | 208.0 | 68.0 | 75.0 | 12.0 | 44.0 | 91.0 | 373.0 |
2017-01-01 02:00:00 | 101.0 | 113.0 | 43.0 | 33.0 | 32.0 | 24.0 | 14.0 | 88.0 | 69.0 | 68.0 | ... | 320.0 | 63.0 | 125.0 | 179.0 | 87.0 | 78.0 | 22.0 | 53.0 | 85.0 | 341.0 |
5 rows × 79 columns
いくつかのデータを可視化してみましょう。時系列データの可視化にはmatplotlib
を用います。
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots(8, 2, figsize=(12, 16))
for i in range(16):
ax[i//2, i%2].plot(train_data.iloc[:, i])
plt.plot(train_data.iloc[:48*30, 0])
[<matplotlib.lines.Line2D at 0x65e37ba00>]
30日の需要数をプロットしてみました。一週間ごとに大きな需要があるようです。また一日の中でも需要の波がありそうです。
from statsmodels.tsa.seasonal import seasonal_decompose
Y = seasonal_decompose(train_data.iloc[:, 0], period=48*365)
T = Y.trend
S = Y.seasonal
e = Y.resid
plt.plot(T[::1000])
[<matplotlib.lines.Line2D at 0x668405840>]
plt.plot(S[:48*30])
[<matplotlib.lines.Line2D at 0x668460850>]
続いて、下記のコードを使用して使用するデータ全体の概観を確認します。
train_data.dtypes
0 float64
1 float64
2 float64
3 float64
4 float64
...
74 float64
75 float64
76 float64
77 float64
78 float64
Length: 79, dtype: object
データの形式を見ると、すべてのデータはfloat64
型になっているようです。
all(train_data.dropna() == train_data)
True
欠損値は存在しないようです。
VAR
の引数に回帰したいデータ、model.fit
の引数には何期前までのデータを利用して回帰をするかを与えます。
from statsmodels.tsa.api import VAR
model = VAR(train_data.values)
results = model.fit(5)
また、コンペの評価指標となるrmse
についても計算できます。
正解データを用いてrmse
を計算するために最終期のデータを除いて学習を行い、最終期のデータを予測したいと思います。
モデルを元にした予測値は、model.forecast('説明変数')
で表します。
eval_model = VAR(train_data.values[:-1])
eval_results = eval_model.fit(5)
eval_pred = eval_results.forecast(train_data.values[:-1], 1)
print(np.sqrt(np.mean((eval_pred - train_data.values[-1])**2)))
30.588294045337044
今回作成したモデルの平均平方二乗誤差は30.14程度でした。
最後に、作成したモデルを使用して提出データを作成します。forecast
メソッドを用いて学習データの1期先のデータを予測します。
pred = results.forecast(train_data.values, 48*7)
submit_df = pd.DataFrame(pred, columns=train_data.columns)
submit_df = submit_df.astype(int)
submit_df.columns = train_data.columns
submit_df.index = pd.date_range(start='2019/12/01 00:00:00', end='2019/12/07 23:30:00', freq='30T')
submit_df.index.name = 'tpep_pickup_datetime'
submit_df.to_csv('submission.csv')
コンペティションへの参加に際しては、ProbSpace利用規約(以下、「利用規約」といいます。)に加え、本ProbSpace参加規約(以下「本規約」といいます。)に同意いただく必要があります。利用規約にて定義された用語は、本規約においても同様の意味で用いられるものとします。
第1条(適用)
第2条(定義)
本規約において次の各用語の定義は、それぞれ以下に定めるとおりとします。
第3条(権利の帰属)
第4条(入賞者の義務)
第5条(禁止事項)
第6条(本コンペの変更、中断、終了等)
第7条(損害賠償)
第8条(本規約の変更)
当社は、必要と判断した場合には、参加者に対して事前に通知する(本コンペにかかる当社ウェブサイト上での告知その他当社が適当と認める方法を含みます。)ことにより、いつでも本規約を変更することができるものとします。なお、変更内容の通知後、参加者が当社の定める期間内に本コンペへの参加を取り消す手続をとらなかった場合には、当該参加者は変更後の規約に同意したものとみなされます。当社は、本規約の変更により参加者に生じたすべての損害について一切の責任を負いません。
第9条(その他)
本契約の準拠法は日本法とし、本契約に起因し又は関連する一切の紛争については、当社の本店所在地を管轄する裁判所を第一審の専属的合意管轄裁判所とします。
(制定)2020年6月22日