機械学習の新人として、私はなんとか3位になりました。 そして、この記事では、参加の経験を共有しようとします。
私は実際にそれについて学んだMail.Ruからの他の選手権を含む、スポーツプログラミングのさまざまなコンテストに長い間参加しています。
機械学習に精通していたのは、実験室レベルだけでした。 kaggleのようなリソースについて聞いたことがありますが、以前にそのようなものに参加したことはありません。 したがって、大学で教えられたことを思い出し、この知識の一部を集めようとすることは、私にとって一種の挑戦になりました。
高い場所を望んでいませんでしたが、賞品は良いモチベーションを追加しました。
開始の少し前に、タスクはすでにわかっていました。 これは、バイナリ分類タスクです。 プログラミング言語の選択はそれほど大きくなく、PythonまたはRを使用するのが慣習であることがわかっていました。私は両方とも最低限のレベルで慣れていますが、Rを選択しました。 。 奇妙なことですが、GCカーブでは定期的に低下しますが、選択を後悔しませんでした。
挑戦する
過去2週間のオンラインゲームへのプレイヤーの参加に関するデータが、12個の数字の形であります。 プレーヤーが少なくとも1週間彼女を離れるか、または残っているかを判断する必要があります。 つまり、このイベントの確率を言うことです。
→問題の完全な状態へのリンク 。
一見したところ、タスクは絶対に古典的です。 このような、おそらく、kaggleの海では、準備ができたコードを使用して使用します。 トレーニングでも、同様のクレジットスコアリングタスクを提供します。 結局のところ、それほど単純ではありません。
私はそれが便利だと思いました
- 2台のコンピューターi5-3210M 2.5GHz×4、12GB RAMおよびi3-4170 3.7GHz×4、16GB RAM(8台ありましたが、さらに購入する必要がありました)
- それぞれにRStudioをインストールしました
- 少しの運
データの概要
ギャップのないトレーニングおよびテストサンプル。 それぞれ25,000のサイズ-そんなに。 これで、データ調査はほぼ終了します。 グラフやその他の視覚化はほとんど行いませんでした。
最初の試み
論理的分類アルゴリズム-決定木、決定フォレスト、およびランダムフォレスト、バギング、それらの上へのブースト-から始めることは既に事前に決定されています。
木とランダムフォレストを決定することは、自分でプログラムするのは難しくありません。 これは、ID3アルゴリズムを説明するVorontsovの講義に従って行われます。
自己記述アルゴリズムではこれまでのところうまくいかないことが明らかになりましたが、この手順はそれらを理解する上で大いに役立ちました。 既製のものを使用する必要があります。
Xgboost
Xgboostは、勾配ブースティングを実装するライブラリです。 多くのkaggleコンテストの受賞者が使用しているため、試してみる必要があります。
学習パラメーターの1つはツリーの数( nrounds )でしたが、どれだけ表示すべきかがすぐにはわかりません。 別の方法があります-サンプルを2つの部分に分割する-トレーニングとコントロール。 新しいツリーを追加するときに、コントロールのエラーが悪化し始めたら、学習を停止します。 Bootstrap集約技術を使用しました。
サンプルを200回ランダムにトレーニングとコントロールに分割し(私の実験によれば、比率0.95 / 0.05が最適であることが判明しました)、xgboostを実行します。 最終的な分類子は、200個すべての基本分類子の投票(平均)です。
これにより、自己記述のランダムフォレストまたはAdaBoostよりもはるかに良い結果が得られました。
機能エンジニアリング
次のステップは、新しい機能の生成でした。
考えられる最も簡単なことは、既存の機能の非線形の組み合わせを多数生成し、不要なものを削除して、最適なセットのみを残すことでした。
新しい符号は、それぞれのペアごとの乗算とペアごとの除算です。 ソースと合わせて、合計144個の属性が取得されました。
同じ講義で、Vorontsovは貪欲なAdd-Delアルゴリズムを使用して、新しい属性を1つずつ削除および追加することを提案しています。 しかし、モデルが不安定であるため(同じデータを持つ異なるランダムシードでは、品質評価は大きく異なります)、このアプローチでは結果が得られませんでした。
私は遺伝的アルゴリズムを使用しました。 最初の母集団-バイナリベクトルを生成します。これは、どちらの符号を使用するか、または使用しないかを意味します。 新しい個体は、以前の個体と交配して変異することにより現れます。 ここでは、さまざまな確率の選択、兆候の数に対するペナルティなどを計算する必要がありました。4〜6世代と12時間の作業では、通常すべてが局所的な最小値に収束しました。 ただし、このローカルミニマムはすでに適切な推定値を示しています。 Xgboostは、情報のない兆候にあまり敏感ではありません(後で説明するニューラルネットワークとは異なります)。2つの良い兆候セットを交差させることも良いセットを与える理由の1つです。
その結果、144個のサインのうち63個が私から選ばれました。
Lightgbm
その後、MicrosoftのLightGBMライブラリを使用するように切り替えました。 Xgboostとほぼ同じ結果が得られましたが、何倍も速く動作しました。 また、追加のトレーニングオプションもありました。 たとえば、ツリーの最大深さ( max_depth )だけでなく、葉の数( num_leaves )も制限すると便利であることがわかりました 。 私にとっては、 num_leaves = 9およびmax_depth = 4が最適であることがわかりました 。
ニューラルネットワーク
SVM、KNN、ランダムフォレストの使用に失敗した後、私はニューラルネットワークに決めました。 より具体的には、 nnetパッケージを使用して、1つの隠れ層を持つパーセプトロンで。
私が最初にしたことの1つは、次のようなものを実行することでした。
set.seed(2707) trControl = trainControl(method='cv', number=5, classProbs=T, summaryFunction=mnLogLoss) model = train(X, Y, method='nnet', metric='logLoss', maxit=1000, maximize=F, trControl=trControl)
これは実際にはマニュアルの例です。 さらに、LightGBMから受け取ったものと算術平均を取り、サーバーに送信しました。 1週間続いた最初の場所にどのように投げ込まれたかに非常に驚きました。
特殊なケースの取り扱い
トレーニングサンプルとテストサンプルの場合と同様に、同じベクトルが存在しましたが、答えは異なりました。 たとえば、1423、278、357、110回出会った人がいました。 おそらく、それらの確率を個別に計算することほど良い方法はありません。 15回以上会ったものだけを処理しました。
問題は、これらの繰り返しをトレーニングから除外するかどうかだけでした。 私は両方のオプションを試してみましたが、例外は少なくとも少しですが、さらに悪い結果をもたらすと結論付けました。
実際、今では停止することができました。 これにより、わずかなマージンで最終的な1位になります。 しかし、後知恵では、誰もが賢いです。
2つのモデルのアンサンブル
単に算術平均や幾何平均よりも成功する集計関数を考え出す価値がありました。 アイデアは次のとおりです。
- 古い選択に基づいて新しい選択を作成します。 違いは回答の列のみです。 回答列は、2つのモデルのどちらが正解と比較して最良の結果をもたらしたかに応じて、0または1です。
- このサンプルでロジスティック回帰、SVM、ブースティングなどを実行します。 結局のところ、SVMを使用する価値がありました。
- この集約モデルのこれらの結果に基づいて、2つのソース(ブースティングまたはニューラルネットワーク)のそれぞれを信頼する確率を取得します。 実際、線形モデルを使用すると、通常の平均ではなく最適な係数が取得されます。
ニューラルネットワーク+ブートストラップ
種の良い選択で起こったことを残すことは不可能でした。 幸運なことに、それは明らかな過剰適合のように思えました。 さらに、少なくとも結果に近づくためにすべての時間を費やしました。
だから、幸運なことに、種子の良い選択、すなわち ニューロンの重みが正常に選択されました。 その後、何度もトレーニングを開始し、最適なものを選択する必要がありました。 しかし、それがより良くなったかどうかを判断する方法は? そして、私は次のことを思いつきました:
- サンプルを0.9 / 0.1(トレーニング/コントロール)の比率で200回分割しました。
- パーティションごとに、トレーニングサブサンプルで20回トレーニングを開始します。 コントロールで最良の結果が得られたモデルを選択します。
- 最終モデルは200モデルの投票(平均)です(すべてが200×20ではないことが重要です)。
したがって、私はほとんど望みの結果に近づきました。 しかし、残念ながら、少しでも勝利には十分ではありませんでした。
未実現のアイデア
- グラフィックカードを使用して学習をスピードアップします。 LightGBMの公式バージョンはサポートしていませんが、フォークがあります。
- 2台のコンピューターのコンピューティングクラスターを使用します。 doParallelパッケージはこれをサポートしています。 以前は、RDPを2台目のコンピューターに切り替えて、手動で開始しました。
- 理論的には、いくつかの前提を費やして、異なる回答でベクトルを繰り返すためのより正確な確率を計算することができました(つまり、隠れたテストサブサンプルからさらにデータを抽出する)。
ご清聴ありがとうございました。
参照:
→ githubのコード