---
title: Numerai Tournamentの概要とどう取り組むかの種
tags:  #numeraimeetupjapan  
author: [カレーちゃん](https://convert.docswell.com/user/currypurin)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/54EMYPQ6EW.jpg?width=480
description: NumeraiMeetupJapan2021の発表資料です。 notebookには https://github.com/currypurin/numerai/blob/main/numerai_meetup_japan_2021/README.md からリンクを貼っていますので、データに触ってみたい人はぜひ。
published: December 31, 21
canonical: https://convert.docswell.com/s/currypurin/ZXW7R5-2021-12-31-162041
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/54EMYPQ6EW.jpg)

Numerai Tournamentの概要と
どう取り組むかの種
Numer i Meetup JAPAN2021
a
2021/12/18


# Page. 2

![Page Image](https://bcdn.docswell.com/page/ZPER918NJ9.jpg)

自己紹介
カレーちゃんというアカウントで
twitterやっています
numeraiは11月からはじめました
Kaggleが好き
2


# Page. 3

![Page Image](https://bcdn.docswell.com/page/NP7XQY88EX.jpg)

話すこと
1. Numerai Tournamentの概要
- 神資料を参照しつつ、簡単なまとめ
2. 新データの概要（ Super Massive Data）
3. どう取り組むか考える
• validation
• objective
• custom metics
- validationのcorrでearly stopping
- LihgtGBM、XGBoost、Catboost
• ターゲット、特徴
3


# Page. 4

![Page Image](https://bcdn.docswell.com/page/637K93KL7D.jpg)

1 .Numerai Tournamentの概要


# Page. 5

![Page Image](https://bcdn.docswell.com/page/4LJ3WGZ6J5.jpg)

神まとめありがとうございます
Numerai って何？？
Numerai をはじめるにあたり、次の３つの資料にとてもお世話になりまし
• Numeraiの日本語版DOCS
- 日本語でめちゃくちゃ詳細に書かれている
• Numeraiはいいぞ(2021.5.25)
- 圧倒的にわかりやすく、網羅されている
• 機械学習による株価予測 はじめようNumerai
- numeraiの変化も時系列で書かれている
後からの参加者も、当時の変化を知ることができる
5


# Page. 6

![Page Image](https://bcdn.docswell.com/page/V8JDK1RMEG.jpg)

Numerai って何？？
Numeraiとは
• 2015年に設立されたNumeraiは、毎週データサイエンスのトーナメントを開催して
います。世界中のデータサイエンティストが、難読化されたデータを無料でダウン
ロードし、株式市場の予測モデルを構築することでトーナメントに参加できます。
ダウンロードできるデータは難読化されたいるため、金融の知識がなくても参加す
ることができます。
• 参加者は、自分の予測に賭け金をかけることでトーナメントに参加できます。良い
予測を提出すると、より多くの仮想通貨（NMR）を得ることができ、悪い予測を提
出すると、NMRを没収されます。
Numeraiの日本語版DOCS 新規参加者向けのTipsより
6


# Page. 7

![Page Image](https://bcdn.docswell.com/page/4VEPKQWQ78.jpg)

Numerai って何？？
Numeraiには２種類の種目がある
• トーナメント (Tournament)
- ターゲットと特徴が与えられるので、ターゲットを予想し提出
• シグナルズ (Signals)
- 株式市場の騰落を予測する
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/L27VV58P7Q.jpg)

トーナメントのデータ
トーナメントには旧データと新データがある
• 旧データ
- ターゲット: 1列
- 特徴: 310列 + id列 + era列 + data̲type列
• 新データ (Super Massive Data)
- ターゲット: 21列 （1列は重複）
- 特徴: 1050列 + id列(index) + era列 + data̲type列
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/Z5JGL65Q7L.jpg)

旧データ全般
id
• 重複なし
era
• 時期を表す
data̲type
• train: 訓練データ
• validation: 参加者のための検証データ
• test: Numeraiのための検証データ
• live: テストデータ
feature̲{group}{i}
• 6つの集合からなる310の特徴
• {0, 0.25, 0.5, 0.75, 1}
target
• {0, 0.25, 0.5, 0.75, 1}
Numerai はいいぞ を参考に作成
9


# Page. 10

![Page Image](https://bcdn.docswell.com/page/V47QY4ZWEP.jpg)

旧データ data_type, era
Train : era1 ~ era120
Val1 : era121 ~ era132
Test1: era575 ~ era852
Val2: era197 ~ 212
Test2: 927 ~
Live: 1000
2020年4月にval2が追加されている
Test2、Liveが毎週更新される。
Validation 2 Announcement より引用
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/DKE4WQ31J1.jpg)

サンプルコードを動かせばすぐにsubmitできました
ベースライン
旧データ：ベースライン
• 公式example
- xgboost
• Numerai tournamentベースライン
- KATSU1110さんのベースライン。とてもわかりやすい。日本語。
- LightGBM
• How to get started with Numerai
- CARLO LEPELAARS さんのベースライン。特徴作成やパラメータサーチも。
- LightGBM
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/PL71YP15JG.jpg)

Numerai tournament - validationの評価
旧データをsubmitすると、左の情報がメールで送られてくる
Numeraiの日本語版DOCS 新規参加者向けのTipsより
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/8G7WG28WE2.jpg)

ステーク&amp;ペイアウト
サブミットしたモデルに、NMRをステーキング（=預け入れ）できる
預け入れたNMRは、サブミットしたモデルのCorrとMMCの値に応じてペイアウトされ
る。
• payout =
stake̲value * payout̲factor * (corr * corr̲multiplier + mmc * mmc̲multipler)
現在選択できる、corr_multiplierとmmc_multiplier: Numerai Tournament Overviewより
• payout̲factorは、全体のstake量に応じて変動
Numerai Tournament Overviewより
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/W4JZLD82E3.jpg)

Corr
corr
• スピアマンの順位相関係数
• targetを上手く予想できると良い, 0.03程度出せると上位
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/KYE6W1K6EV.jpg)

mmc(Meta Model Contribution)
mmc(Meta Model Contribution)
• メタモデルへの貢献度
• 他の人と異なる独自のモデルを作れば高いMMCを得ることができる
• メタモデルへの貢献（MMC)について、MMC2 Announcement 、Numerai はいいぞ /
An encouragement of Numerai、機械学習による株価予測
Qiita などがとても詳しい
はじめようNumerai -
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/5GE5M4P5E4.jpg)

評価期間
４週間(20日間）のスコアの加重平均
でpayoutが決まる
毎週新しいsubmitをし、並行して
stakeできる
https://docs.numer.ai/tournament/learn より
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/V9729V6GJR.jpg)

2. 新データの概要
( Super Massive Data)


# Page. 18

![Page Image](https://bcdn.docswell.com/page/5DJY439G7M.jpg)

新データ (Super Massive Data)
Super Massive Data Release: Deep Dive
• リリース時のフォーラム
• eraは完全にweeklyになった
- era̲nとera̲{n+4}は重複なし
- era̲nからera̲{n+3}は重複あり
• era
- train: 0001~0574
- tournament̲data: 0575~0852
- live: X
- valid: 0857~0961
18


# Page. 19

![Page Image](https://bcdn.docswell.com/page/2V7NYVL8E8.jpg)

新データ (Super Massive Data)
• target21列
• 「target」と「target̲nomi̲20」は完全に同一で、予想すべき
target
• 20日間と60日間の10種類のtarget
• targetの分布
19


# Page. 20

![Page Image](https://bcdn.docswell.com/page/GYJ9P64X73.jpg)

私が使っている関数
APIでのデータダウンロード等
!pip install numerapi
napi = numerapi.NumerAPI(verbosity=&quot;info&quot;)
current_round = napi.get_current_round() # 現在のround
def get_massive_data(mode: str, round: int):
&quot;&quot;&quot;
mode: training, validation, tournament
round: ラウンド数
&quot;&quot;&quot;
parquet_path = Path(f&#039;{mode}_data_int8_{current_round}.parquet&#039;)
if not parquet_path.is_file():
napi.download_dataset(filename=f&quot;numerai_{mode}_data_int8.parquet&quot;,
dest_path=str(parquet_path),
round_num=round)
df = pd.read_parquet(f&#039;{mode}_data_int8_{current_round}.parquet&#039;)
return df
train = get_massive_data(&#039;training&#039;, current_round)
valid = get_massive_data(&#039;validation&#039;, current_round)
test = get_massive_data(&#039;tournament&#039;, current_round
napi.download_dataset(&#039;features.json&#039;, &#039;features.json&#039;)
import json
with open(&quot;features.json&quot;, &quot;r&quot;) as f:
feature_metadata = json.load(f)
)
20


# Page. 21

![Page Image](https://bcdn.docswell.com/page/5GJ8DZQ9JD.jpg)

APIでvalidの提出
!pip install numerapi
public_id = &#039;xxx&#039;
public_id, secret_keyは、Account&gt;SettingsのCreate API Keyから作成
secret_key = ‘xxx&#039;
model_id = ‘xxx&#039;
model_idは、https://numer.ai/models のModelsのMoreから取得、
napi.get_models() でも一覧を取得可能
# validの書き出し、必要なのはindexとprediction
valid_diagnostics_df = valid.index.to_frame().reset_index(drop=True)
valid_diagnostics_df[&quot;prediction&quot;] = valid_prediction
valid_diagnostics_df.to_csv(&#039;valid_diagnostics_df.csv&#039;, index=False)
napi.upload_diagnostics(&#039;valid_diagnostics_df.csv&#039;, model_id=model_id)
napi = numerapi.NumerAPI(public_id=public_id, secret_key=secret_key)
napi.upload_diagnostics(&#039;valid_diagnostics_df.csv&#039;, model_id=model_id)
提出すると右図のVALIDATION DIAGNOSTICSが、
https://numer.ai/tournament で閲覧可能となる
21


# Page. 22

![Page Image](https://bcdn.docswell.com/page/MLJLMDXMER.jpg)

APIでのサブミット
!pip install numerapi
public_id = &#039;xxx&#039;
public_id, secret_keyは、Account&gt;SettingsのCreate API Keyから作成
secret_key = ‘xxx&#039;
model_id = ‘xxx&#039;
model_idは、https://numer.ai/models のModelsのMoreから取得、
napi.get_models() でも一覧を取得可能
# testの書き出し
predictions_df = test.index.to_frame().reset_index(drop=True)
predictions_df[&quot;prediction&quot;] = predictions
predictions_df.to_csv(&quot;predictions.csv&quot;, index=False)
napi = numerapi.NumerAPI(public_id=public_id, secret_key=secret_key)
submit_file_path = &quot;predictions.csv&quot;
submission_id = napi.upload_predictions(submit_file_path, model_id=model_id, version=2)
新データはversion=2, 旧データはversion=1
22


# Page. 23

![Page Image](https://bcdn.docswell.com/page/547MYPL67W.jpg)

まずはサブミットしてみると、色々わかると思います
ベースライン
新データ:ベースライン
• 公式example
- Lightgbm
• [Numerai] NN baseline with new massive data | Kaggle
- KATSU1110さんがのベースライン
- Keras
23


# Page. 24

![Page Image](https://bcdn.docswell.com/page/ZP7R91KNE9.jpg)

3. どう取り組むか考える
1.validation
2.objective
3.Custom meticでvalidationのcorrを最大化
• LihgtGBM、XGBoost、Catboost
4.ターゲット、特徴


# Page. 25

![Page Image](https://bcdn.docswell.com/page/NPJXQYL87X.jpg)

validationをどのようにするか
与えられた、trainを学習データにして、validationデータをvalidationにするように思え
るが、このデータの区分は特殊でそれが正解とも限らない
• ただ、初手として取り組むには十分だし、これで十分に上位も狙えそう
validationデータは、testに期間が近いため、学習データに使えると精度が向上する可
能性は高い
trainとvalidationをconcatして、交差検証する方法が、kaggleなどのコンペに慣れてい
ると普通に思えるが、eraに重複があるので注意が必要
旧データではあるが、Numeraiのモデル紹介（旧Dataset）はとても参考になる
25


# Page. 26

![Page Image](https://bcdn.docswell.com/page/63JK93LLJD.jpg)

何をObjectiveに学習するか
LightGBMで使えるobjectiveの表現で 考える
• MSE(regression) 一般的
• multiclass(softmax) multiclassは多少重いが、5値分類と考えればかなりあり。
argmaxを取ると予測が5つの値になるので、加重平均をとる
• xentropy
targetを0~1にできる場合、xentropyはよく使われて精度も良い傾向にあ
る
• その他の可能性
- MAE、huber、fair 、Sorting and Ranking …
👉 今回のデータでは、上の太字の３つは精度がそんなに変わらない印象。Sorting nd R nkingはまだ試せていない
a
a
26


# Page. 27

![Page Image](https://bcdn.docswell.com/page/4LE3WG36E5.jpg)

何をmetricにするか（early stoppingの指標）
payout =
stake̲value * payout̲factor * (corr * corr̲multiplier + mmc * mmc̲multipler)
validationのcorrを最大化するようにearly stoppingするのが、取り組みやすそう
（mmc直ちに算出できないので、まずはcorrを最大化するのが良さそう）
次のページから、corrでearly stoppingするcustom metricsの使い方の説明
- LightGBM
- XGboost
- CatBoost
27


# Page. 28

![Page Image](https://bcdn.docswell.com/page/V8EDK14M7G.jpg)

custom metricsの使い方
Custom metrics（LightGBM）その１
def compute_corr_for_lgb(preds: np.ndarray, target: lgb.Dataset):
# validの全体のcorrを返すmetric
# https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.train.html#lightgbm.train
preds_rank = pd.Series(preds).rank(pct=True, method=&quot;first&quot;)
corr = np.corrcoef(preds_rank, target.get_label())[0, 1]
return &#039;corr&#039;, corr, True
eval_name, eval_result, is_higher_betterの順に返す
params = {&#039;objective&#039;: &#039;regression&#039;,
&#039;metric&#039;: &#039;None&#039;}
‘None’が必須, ないとobjectiveとmetricの両方でearly stoppingがかかる
参考：小ネタ：LightGBM の objective を metric から消し去る
d_train = lgb.Dataset(tr_x, tr_y)
d_valid = lgb.Dataset(va_x, va_y)
evals_result = {}
model = lgb.train(params,
d_train,
num_boost_round=10000,
valid_sets=d_valid,
[d_train, d_valid]にしても良いが、d_validで十分なことが多い。数を増
やすと重くなる
# 最大round数
trainとvalidの学習曲線を描きたい場合は、学習後に推論し直す方法も
# 検証データ
feval=compute_corr_for_lgb, # custom_metric
early_stopping_rounds=50,
verbose_eval=30, # 何roundおきに表示するか
fevalを複数にしたい場合は次のページが参考になる
)
・Python: LightGBM でカスタムメトリックを扱う
・小ネタ：LightGBM の objective を metric から消し去る
28


# Page. 29

![Page Image](https://bcdn.docswell.com/page/4V7PKQMQJ8.jpg)

学習後の推論とev ls_result
Custom metrics（LightGBM）その２
# 学習後の推論
for itr in range(num_iteration=model.best_iteration + early_stopping_rounds):
tr_preds = model.predict(tr_x, num_iteration=itr)
va_preds = model.predict(va_x, num_iteration=itr)
# ここでtr_preds, va_preds, targetで確認したい指標を計算して
# リストにappendしたりする
# valid_sets=[d_train, d_valid]にしておけば、trainとvalidのf_evalのitrとcorrの関係は確認可能
# リストにappendしたりする
plt.plot(evals_result[&#039;training&#039;][&#039;corr&#039;], label=&#039;train_corr&#039;)
plt.plot(evals_result[&#039;valid_0&#039;][&#039;corr&#039;], label=&#039;valid_corr&#039;)
plt.legend()
a
29


# Page. 30

![Page Image](https://bcdn.docswell.com/page/L2JVV59PJQ.jpg)

er 毎のcorrの平均でe rly stopping
Custom metrics（LightGBM）その３
ここまでのは、全体のcorrだったので、era毎のcorrの平均を計算するようにする
!pip install numpy-indexe
import numpy_indexed as npi
numpy_indexedというライブラリを使うと、簡単にかける
class MetricCorr:
def __init__(self, era_group: pd.Series):
self.group = npi.group_by(era_group.values)
def metric_corr_mean_lgb(self, preds: np.ndarray, data: lgb.Dataset): group毎に分割して、そのリストを返すメソッド
labels = self.group.split(data.get_label())
preds_rank = [pd.Series(p).rank(pct=True, method=&quot;first&quot;).values for p in self.group.split(preds)]
corr_mean = np.mean([np.corrcoef(preds, rank)[0, 1] for preds, rank in zip(preds_rank, labels)])
return &#039;corr_mean&#039;, corr_mean, True
d_train = lgb.Dataset(tr_x, tr_y)
d_valid = lgb.Dataset(va_x, va_y)
evals_result = {}
me_corr = MetricCorr(valid[&#039;era&#039;])
model = lgb.train(params,
d_train,
num_boost_round=10000,
valid_sets=d_valid,
出力の例
# 最大round数
# 検証データ
feval=me_corr.compute_corr_mean_lgb, # custom_metric
early_stopping_rounds=50,
verbose_eval=30 # 何roundおきに表示するか
d
a
a
)
30


# Page. 31

![Page Image](https://bcdn.docswell.com/page/Z5EGL6ZQJL.jpg)

Custom metrics（Xgboost）その１
Xgboostは、LightGBMに近い書き方
class MetricCorr:
def __init__(self, era_group: pd.Series):
self.group = npi.group_by(era_group.values)
def metric_corr_mean_xgb(self, preds: np.ndarray, data: xgb.DMatrix):
# https://xgboost.readthedocs.io/en/latest/tutorials/custom_metric_obj.html#customized-metric-function
labels = self.group.split(data.get_label())
preds_rank = [pd.Series(p).rank(pct=True, method=&quot;first&quot;).values for p in self.group.split(preds)]
corr_mean = np.mean([np.corrcoef(preds, rank)[0, 1] for preds, rank in zip(preds_rank, labels)])
return &#039;corr_mean&#039;, corr_mean
d_train = xgb.DMatrix(tr_x, tr_y)
d_valid = xgb.DMatrix(va_x, va_y)
watchlist = [(d_valid, &#039;valid&#039;)]
evals_result = {}
eval_name, eval_resultの順に返す
me_corr = MetricCorr(valid[&#039;era&#039;])
watchlist = [(d_valid, &#039;valid&#039;)]
model = xgb.train(params,
d_train,
num_boost_round=num_boost_round
evals=watchlist,
feval=me_corr.metric_corr_mean_for_xgb,
maximize=True, # fevalを最大化
最大化したいのか、最小化したいのか選択
early_stopping_rounds=early_stopping_rounds,
evals_result=evals_result,
verbose_eval=50
)
31


# Page. 32

![Page Image](https://bcdn.docswell.com/page/V4JQY4LW7P.jpg)

Custom metrics（Catboost）その１
Catboostは、LightGBM・XGboostとは違う書き方、CPUを使う場合
from catboost import CatBoost, Pool
class CorrMetricCatboost:
&quot;&quot;&quot;https://catboost.ai/en/docs/concepts/python-usages-examples#rmse1&quot;&quot;&quot;
def get_final_error(self, error, weight):
return error
def is_max_optimal(self):
最大化の場合はTrue
return True
def evaluate(self, approxes, target, weight):
assert len(approxes) == 1
assert len(target) == len(approxes[0])
approx = approxes[0]
output_weight = 1 # weight is not used
corr = np.corrcoef(approx, target)[0, 1]
return corr, output_weight
metric, weightの順に返す。get_ inal_errorでweightを使わないなら、weightは使用されない
train_pool = Pool(tr_x, tr_y)
valid_pool = Pool(va_x, va_y)
パラメータに、custom metricsを返すclassをセットする
params = {&#039;loss_function&#039;: &#039;RMSE&#039;,
&#039;iterations&#039;: 100,
&#039;eval_metric&#039;:CorrMetricCatboost(),
# &#039;task_type&#039;: &#039;GPU&#039;
CustomMetricsを使うとGPUを使えない
}
model = CatBoost(params)
https://github.com/catboost/catboost/issues/736
model.fit(train_pool,
eval_set=[valid_pool],
early_stopping_rounds=20,
verbose_eval=30)
f
32


# Page. 33

![Page Image](https://bcdn.docswell.com/page/DK74WQD1E1.jpg)

Custom metrics（Catboost）その2
GPUを使う場合、trainのみで学習した後に、後からvalidを計算する必要がある？
from catboost import CatBoost, Pool
train_pool = Pool(tr_x, tr_y)
params = {&#039;loss_function&#039;: &#039;RMSE&#039;,
&#039;iterations&#039;: num_iterations,
&#039;task_type&#039;: &#039;GPU&#039;}
model = CatBoost(params)
model.fit(train_pool)
metrics, eval_setを設定せずにまずは学習する
num_iterationsの値は重要
class MetricCorr:
def __init__(self, era_group: pd.Series):
self.group = npi.group_by(era_group.values)
def compute_corr_mean(self, preds, target):
# era毎のcorrの平均を返す
labels = self.group.split(target)
preds_rank = [pd.Series(p).rank(pct=True, method=&quot;first&quot;).values for p in self.group.split(preds)]
corr_list = [np.corrcoef(preds, rank)[0, 1] for preds, rank in zip(preds_rank, labels)]
return np.mean(corr_list)
mean_corrs = []
me_corr = MetricCorr(valid[&#039;era&#039;])
for valid_pred in model.staged_predict(valid_pool, ntree_end=num_iterations):
mean_corr = me_corr.compute_corr_mean(valid_pred, va_y])
mean_corrs.append(mean_corr)
model.staged_predictは、 itに比べてかなり
遅い。
f
33


# Page. 34

![Page Image](https://bcdn.docswell.com/page/PLJ1YPZ5EG.jpg)

target
まずはtargetのみで十分だが、他のtargetも使うとスコアが改善しそう
• 欠損のないtargetを使ってすぐにアンサンブルや
multi task学習はできる
• 329の欠損も除いてしまえばʼ̲20ʼのtargetは簡単に使える
• ʻ̲60ʼのtargetは欠損が多いので使うのに工夫が必要
34


# Page. 35

![Page Image](https://bcdn.docswell.com/page/8GJWG29W72.jpg)

特徴
一番工夫が必要そう
1050列もある。データが重たい。
次の記事が参考になりました
• 20 models ensemble diagnostics result
• Numeraiのtraining dataの周期構造について
• Numeraiのモデル紹介（旧Dataset）
35


