🎅
[Numerai Tips] Numeraiの現状使用されていないTargetの基礎的な解析
サマリー
- Numeraiのtargetは現状nomi_20が使われているが、その他の変数を使うとCorrやTCが改善する可能性がある。
- 20 daysの変数は相関が高く、スピアマン相関係数値が0.70〜0.80を超えているものが多いので、これら変数を使うと特にCorrが改善するかも?(以下がSharpe ratioが高かったです)
- target_arthur_20
- target_william_20
- target_jerome_20
はじめに
Numeraiにおいて現状スコアリングに使われているターゲットは普段1つだけですが、他のターゲットにも予測に重要な情報が眠っている可能性があります。以下の記事においてはNumeraiのCEOが「jerome_60はblendingによく効くターゲット」と言っています(!!)
本記事では、スコアリングに使用しているターゲットとスコアリングに使用していないターゲットとの相関を解析してみました。
ソースコード
Kaggle notebook 上にもソースコードをおいています。
import os
import pandas as pd
import scipy.stats as st
import matplotlib.pylab as plt
from numerapi import NumerAPI
from collections import defaultdict
from contextlib import redirect_stderr
from tqdm import tqdm_notebook as tqdm
napi = NumerAPI()
with redirect_stderr(open(os.devnull, 'w')):
napi.download_dataset("v3/numerai_training_data_int8.parquet", "numerai_training_data.parquet")
napi.download_dataset("v3/numerai_validation_data_int8.parquet", "numerai_validation_data.parquet")
napi.download_dataset("v3/numerai_live_data_int8.parquet", "numerai_live_data.parquet")
napi.download_dataset("v3/numerai_datasets.zip", "numerai_datasets.zip")
df_train = pd.read_parquet("numerai_training_data.parquet")
df_valid = pd.read_parquet("numerai_validation_data.parquet")
df_train_targets = df_train.loc[:, df_train.columns.str.startswith('target')]
df_valid_targets = df_valid.loc[:, df_valid.columns.str.startswith('target')]
df_train_targets["era"] = df_train["era"]
df_valid_targets["era"] = df_valid["era"]
era_set_train = sorted(set(df_train["era"]))
era_set_valid = sorted(set(df_valid["era"]))
dd_train = defaultdict(lambda: defaultdict(int))
for era in tqdm(era_set_train):
df_train_targets_era = df_train_targets.query("era == @era").drop("era", axis=1)
for col in df_train_targets_era.columns:
if col == "target":
continue
# 60 days はNaNの値があるため、ignore(omit)しています。
dd_train[era][col] = st.spearmanr(df_train_targets_era["target"], df_train_targets_era[col], nan_policy="omit")[0]
dd_valid = defaultdict(lambda: defaultdict(int))
for era in tqdm(era_set_valid):
df_valid_targets_era = df_valid_targets.query("era == @era").drop("era", axis=1)
for col in df_valid_targets_era.columns:
if col == "target":
continue
# 60 days はNaNの値があるため、ignore(omit)しています。
dd_valid[era][col] = st.spearmanr(df_valid_targets_era["target"], df_valid_targets_era[col], nan_policy="omit")[0]
df_spearmanr_train = pd.DataFrame(dd_train)
df_spearmanr_valid = pd.DataFrame(dd_valid)
df_spearmanr_train_mean_std = df_spearmanr_train.drop("target_nomi_20").T.agg(["mean", "std"]).T
df_spearmanr_valid_mean_std = df_spearmanr_valid.drop("target_nomi_20").T.agg(["mean", "std"]).T
df_spearmanr_train_mean_std["sharpe_ratio"] = df_spearmanr_train_mean_std["mean"] / df_spearmanr_train_mean_std["std"]
df_spearmanr_valid_mean_std["sharpe_ratio"] = df_spearmanr_valid_mean_std["mean"] / df_spearmanr_valid_mean_std["std"]
display(df_spearmanr_train_mean_std.sort_values("sharpe_ratio", ascending=False))
display(df_spearmanr_valid_mean_std.sort_values("sharpe_ratio", ascending=False))
df_spearmanr_train.loc[df_spearmanr_train.index.str.endswith("_20"), :].T.drop("target_nomi_20", axis=1).plot()
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=12)
plt.title("data: train, target: 20 days")
plt.xlabel("Era")
plt.ylabel("Spearman's Rho")
plt.show()
df_spearmanr_train.loc[df_spearmanr_train.index.str.endswith("_60"), :].T.plot()
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=12)
plt.title("data: train, target: 60 days")
plt.xlabel("Era")
plt.ylabel("Spearman's Rho")
plt.show()
df_spearmanr_valid.loc[df_spearmanr_valid.index.str.endswith("_20"), :].T.drop("target_nomi_20", axis=1).plot()
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=12)
plt.title("data: valid, target: 20 days")
plt.xlabel("Era")
plt.ylabel("Spearman's Rho")
plt.show()
df_spearmanr_valid.loc[df_spearmanr_valid.index.str.endswith("_60"), :].T.plot()
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=12)
plt.title("data: valid, target: 60 days")
plt.xlabel("Era")
plt.ylabel("Spearman's Rho")
plt.show()
結果
trainの相関係数とそのsharpe ratio
validの相関係数とそのsharpe ratio
相関係数の変遷
所感
- 結果だけ見ると 60 days はあまりBlendingする気にならない...笑
- TC狙いならこっちでも良さそうですね。
- パッとできそうなのは20 daysの相関が高い変数をBlendingすること?Corrの改善には効きそうですよね。以下がSharpe ratioが高そうです
- target_arthur_20
- target_william_20
- target_jerome_20
Discussion