Numerai で初めて報酬圏内に入ったので機械学習処理を簡単にまとめる

データサイエンティストが集まってモデルを作って市場予想をしヘッジファンドを動かす取り組みのNumerai

データサイエンティストとしては、そのNumerai上で毎週行われているコンペに参加し一定の条件をクリアすると報酬がもらえる。

何回か挑戦していたが、条件であるLogless 0.7 以下と提出データのオリジナリティが達成できていなかった。Logless 0.7 以下はそこまで難しく無いが、オリジナリティが達成しにくい。単純に一回予測しただけだと、他の人が同じ手順でやっているためオリジナリティは無くなってしまう。

前回の田中TOMの放送でLightGBMを触ったので、XGBoostと合わせてスタッキングで挑戦してみることに。

今回のデータ処理概要

概要は次の通り。

実行環境

  • Julia: 0.6.2
  • 使ったJuliaライブラリ
    • FileIO: 提出ファイル出力用
    • CSV: CSVデータの読み込み、以前はDataFrameがメソッドを用意してくれていたが、こちらでCSV.readするように推奨している。
    • XGBoost: XGBoost バージョンは更新されていないが最近masterブランチが0.6系に対応してくれた
    • DataFrames: DataFrameを扱えるように
    • MultivariateStats: 主成分分析用
    • LightGBM: LightGBM コアライブラリは別途用意する必要があるし、まだjuliaの公式パッケージになっておらずgithubから持ってくる必要がある
    • LossFunctions: 損失関数を確認するため
    • CSVFiles: 提出ファイルの出力用

無事にLogless 0.7以下とオリジナリティも承認されて、報酬圏内に入ることができた。

Juliaで並列計算を試す

引き続き Numerai をランダムフォレストで解いてみる。

のスライドによると、 DecisionTree は並列計算対応してくれているらしいので、実験してみた。

using DataFrames
using DecisionTree
using ScikitLearn
using LossFunctions
train = readtable("./numerai_training_data.csv")
test = readtable("./numerai_tournament_data.csv")
yTrain_array = Array(train[:, :target] * 1.0)
xTrain_array = Array(train[:, 4:53])
@time model = build_forest(yTrain_array, xTrain_array, 2, 30, 4, 0.7, 50)
pred_test = apply_forest(model, Array(test[:,4:53]))
labelsInfoTest = DataFrame()
labelsInfoTest[:id] = test[:id]
labelsInfoTest[:probability] = pred_test
writetable("numerai_answer3.csv", labelsInfoTest, separator=',', header=true)

@time を付けることでそのコードでの処理時間やメモリ使用量が分かるっぽい。

実行結果

> julia numerai.jl 
657.770862 seconds

> julia -p 3 numerai.jl 
282.813077 seconds

確かに、かなり時間が節約できている。

今後はJupyter である程度変数とかを絞ったら、コードにして並列計算したほうが良さそう。

肝心のNumeraiの結果は一度、Loglossが 0.70 台まで下がったが、Originarity チェックで弾かれた。なんでだろう。

他の結果は 0.75 以上の結果になってしまった。

損失関数の計算で分かってきたけど、1か0 の結果に対して、全ての予測が 0.5 だと、Logloss は 0.75 になる。

つまり0.75を下回らないと、予測の精度は全てを 0.5 で答えた結果よりも悪いことになる。

ここに一つのハードルがありそうだ。データはマスキングされているけど、元々はグラフデータとかの内容だろうし、普通に株取引とかで機械学習でやろうとしても、なかなか結果が出せないのと同じで、取引データから利益を出せるようになるには、もっとデータサイエンスを学ばないといけないな。

Julia で Numerai にチャレンジ

Numerai というデータサイエンスが競い合って、効率の良いファウンドを運営しようという試み。

ビットコインで雇われた匿名の7,500人が「頭脳」となるヘッジファンド「Numerai」|WIRED.jp

良いデータを登録できると、報酬ももらえるので頑張って Julia で挑戦してみる。

using DataFrames
using DecisionTree
using ScikitLearn

train = readtable("./numerai_training_data.csv")
test = readtable("./numerai_tournament_data.csv")

yTrain_array = Array(train[:, :target] * 1.0)
xTrain_array = Array(train[:,4:53])

model = RandomForestRegressor()
ScikitLearn.fit!(model, xTrain_array, yTrain_array)

predTest = ScikitLearn.predict(model, Array(test[:,4:53]))

labelsInfoTest = DataFrame()
labelsInfoTest[:id] = test[:id]
labelsInfoTest[:probability] = predTest

writetable("numerai_predict.csv", labelsInfoTest, separator=',', header=true)

とりあえず、simpleなランダムフォレストを作って登録もできた。Loglossは0.76522ぐらいだった。