イナズマの日記

こんにちは。

SIGNATE Student Cup 2021参加記 (public 9th, private 7th)

こんにちは,SIGNATE Student Cup 2021に参加しました. 機械学習コンペはリアルタイムで参加したのは2回目なのですが,7位になれたのでSolutionや感想その他などをここに残そうと思います. ソースコードこちら

どんなコンペ?

この画像(SIGNATEより引用)の通り,いくつかの特徴から音楽のジャンルを推定します. いわゆるテーブルデータを扱うコンペでした. f:id:inazuma110:20210510160624p:plain

Solution

Feature Engineering

各音楽ごとの欠損値の数,tempoのmax-min,以外は特徴量は追加していません. あとは標準化,欠損値の-1埋め,RegionのOne hot化,特徴量の重み付けです. 特徴量の重み付けはフォーラム通りにやったのですが,Feature Engineeringにおいてはこれが一番効きました.

Prediction

まず,上述の通りの前処理をした説明変数をkNNで予測し,これで自己訓練をしました. 具体的には,予測結果のうちpredict_probaの最大値が0.7以上のもの(これは結果的にはすべて1になりました)を疑似ラベルとしてトレーニングデータに追加して,半教師あり学習をしました. これもスコアを上げるのにかなり貢献してくれました.

Ensemble

上述の自己訓練を,kNN,SVC,Random Forest, XGBoostで行い,それらをアンサンブル学習したものを最終提出としました. kNN, SVCのCVが0.7以上だったことに対して,Random ForestとXGBoostがCVが0.6程度だったのですが,CVとLBが大きく乖離していたので過学習を恐れてアンサンブルしました. しかし,結果的にはSVC単体がCV, Public LB, Private LBすべて最も高いスコアとなりました.(これを最終提出にできていれば2位相当のスコアでした…)

期間中の流れ

ここからはより具体的に,コンペ中の流れや考えなどを時系列に沿って書きます.

チーム作成

正直,それほど良い結果を残せるとは思っていなかったのでチームメイトはプログラミングや機械学習の経験すら問わずにサークルのDiscordで募りました. f:id:inazuma110:20210510161759p:plain 仮に経験が無くとも,サークル活動で教えつつのんびり進められれば良いなと思っていました.

しかし,実際には緊急事態宣言の発令に伴い,サークルの対面活動が禁止され,コミュニケーションを取れた回数が減ってしまいました. 結果,後輩たちの面倒をほとんど見ることができず,自分で勝手にどんどん進んでしまったことは反省です.

Baseline

テーブルデータではXGBoostやLightGBMが強いということを知っていたので,まずはXGBoostで学習したものをベースラインとして提出しました. そのままでは扱えない特徴量は,それぞれいい感じに変換しましたが,元のデータままだと思ってください. f:id:inazuma110:20210510162548p:plain 思っていたよりスコアが高く,ブロンズが見えたため結構嬉しかったです.

フォーラムのタイトルにkNNとあったので,それも試したり, ScikitLearnのチートシートを見てRandom Forestなども試していました.

探索的データ解析

探索的データ解析(EDA)をしました. pandas-profilingを用いると良いということだったのでそれを用いました. tempo_maxとtempo_minという特徴量があったのですが,これらの相関係数が非常に高い(それはそう)ことに気付いたのでこれらの平均を取ることにして,特徴量を1つ減らしました. また,不均衡データであることもわかりました. これについては後述します.

その他は特にわかることはありませんでした. というのも,pandas-profilingの使い方を解説しているサイトは山ほどあっても,そこからどういうことに着目すれば良いかを書いているサイトはほとんど見つけられなかったからです. なにかいいサイトがあれば教えてください!

網羅的特徴量の探索

特徴量を四則演算したものや,カテゴリーごとに統計を取った特徴量(Aggregation)したものがよく使われるとわかったので,featuretoolsというライブラリを用いて特徴量の網羅的探索をした後にXGBoostにかけてみました. feature importanceの上位50%だけ追加,のような工夫をするも結果的にはCVが下がってしまったので,なにも採用することなく終わりました.

特徴量の重み付け

この辺りでフォーラムを眺め始めます. フォーラムは長いコードが書き連ねられていてなんとなく避けていたのですが,Baseline以上のスコアが全く達成できなかったので読んで見ることにしました. このフォーラムに結構とんでもないことが書いてあって,要約するとRegionがかなり重要と書いてあります.RegionはXGBのFeature importanceは小さい値だったのでかなり驚きつつ,フォーラムを参考にregionのOnehot化や特徴量への重み付けをしてkNNを提出しました. 結果的にスコアはかなり上がったものの,ブロンズのボーダーも上がっていてブロンズ入りは果たせませんでした.

しかし,ここでチームメイトが特徴量の重みやハイパーパラメータを探索してブロンズ入りを果たしてくれました!! f:id:inazuma110:20210510171926p:plain この辺りでSVCもkNNと同等以上の精度が出ることに気付きました.

不均衡データに対する対処

EDAの際にも書きましたが,本コンペのデータはいわゆる不均衡データです. ジャンルごとにデータ数の偏りがかなりあるので,どうにかしないといけないと思ってUnder SamplingやOver Smaplingなるものを試しました. これらは,データを切り捨てたり水増ししたりして,データの偏りを無くすのですが,両手法ともデメリットがあります.

バギングなどもしつつ両手法を試したのですがうまく行かず,不均衡データの対処は一回Pendingとしました. 結局最後まで対処はできなかったのですが,今回のデータでは有効な対処が発見されなかったのか,良好な成績を残すことができました.

疑似ラベル

もう1個のフォーラムで疑似ラベルなるものを利用していたので実際に使ってみました. フォーラムが長くてあんまり真面目にコードまでは読めなかったのですが,とりあえずkNNのpredict_proba(予測の際の確信度みたいなイメージ)を用いて疑似ラベルを振ってみました. 本当はSVCも試したかったのですが,どうもSVCのpredict_probaは訳ありみたいだったので今回は見送りました. f:id:inazuma110:20210510173019p:plain 結果,LBは上がったのですが,CVがLBを大幅に上回ったのでとても不安でした. 一応,チームメイトやフォーラムでも同様のことをしてCVが壊れるという報告があったので目をつぶることにしました.

突然のゴールド入り

ハイパーパラメータ探索をOptunaで行っていたのですが,最適化する関数の戻り値をCVにしたら突然スコアが0.2ほど上がりました. OptunaのGitHubのexampleでCVした値を返していたのでこういう変更をしたのですが,ここまで変わるとは思いませんでした. ありがとうOptuna. f:id:inazuma110:20210510175420p:plain

ensemble

とは言え,CVとLBの乖離は解消していなかったので過学習がとても怖かったです. 過学習気味のモデルをアンサンブルすると良い感じになると聞いたので,kNN,SVC,Random Forest,XGBoostをアンサンブルしたモデルを最終提出としました. 実はそれぞれをRandom Seed Averageしたモデルをアンサンブルしたものが締切4分前に学習が終わったのでそれも提出したのですが,しないものの方がLBが0.01程度高かったので最終提出にはしませんでしたし,実際最終評価のスコアも高かったです. f:id:inazuma110:20210510175859p:plain

感想

最初の目標よりはるかに高い順位でとても嬉しかったです. とは言え,機械学習コンペは(少なくとも僕から見ると)良くも悪くも運ゲーに感じてしまいました. どのアルゴリズムが適切か,どんな特徴量を増やす・減らすと良いのか,スタッキング,バギング,アンサンブルをどのくらいやるべきか,その際の重みや特徴量の重みはどんな値が適切かなどは何回も試して特定していくしかないように感じました. もちろん機械学習アルゴリズムへの理解やドメイン知識があればある程度わかることなのかもしれませんが,それでも試行回数を稼いでいろいろ試さなきゃいけない部分はなくならないと思います. これらの試行がうまくハマれば高いスコアが出てくれるので,僕のような初学者でもワンチャン賞金の夢を見ることができるのはとても良いと思いましたし,実際とても楽しかったです. (例えばAtCoderなどの短期間のアルゴリズムコンテストでは今の僕では絶対に上位に行くことはできないため)

チームメイトの皆さんもありがとうございました!楽しかったです!! チームでコンペに出た経験はICPCくらいしかないため,貴重な経験にもなりました.

大学院で履修した講義 感想

こんにちは.大学院で履修した講義の感想を書きます.

inazuma110.hatenablog.com

の続きみたいなものです. ちなみに,学部生でも先生に許可を取れば聴講できると思うので,興味あるやつあったら行ってみてください.

クオーターくらいを目安に追記していく予定です.

ウェブサイエンス

グラフ理論(ネットワーク分析),主成分解析などをします.この辺の話に興味ある人が受ければいいと思います.

敵対探索アルゴリズム

ゲーム理論における探索アルゴリズムの講義です. トピック的には面白いのですが,講義の進め方が好きではありません.

まず,学生は次週の内容をWebや書籍などで調べて,5分程度のスライドにまとめます. 講義の半分くらいは各学生がスライドを発表する時間です. 残った時間で先生がアルゴリズムの説明などを行います.

学生の発表自体は全く問題ないのですが,毎回やるとなると学生側の準備も大変だし,そもそも1学生が調べられることなどたかが知れてます. しかも,先生の講義の内容に発展的な内容はほとんどありません.つまり,学生は自分であらかじめ調べたこととほとんど同じことを繰り返し聞きます. 学生の発表時間を減らして,より発展的な講義をしてほしかったです.

機械学習

機械学習アルゴリズムについて学びます. あんまり記憶にないのですが,解析学統計学エアプすぎて途中でついていけなくなってしまいました.

データサイエンス特論

上記の「機械学習」が基礎研究っぽいことに対し,こちらは応用的な内容についても扱います. 課題があまりにも多いのでしんどかったです.

数値解析

Pythonを用いて,多項式近似などをします. 面白かったです,がなぜか記憶にほとんど残ってないです(は?)

最適化概論

サステイナブル工学専攻の講義です.最適化について学びます. 最適化は最近のトレンドだと思っていて,AIとかやりたい人は履修し得だと思います. 自分は最適化の基本的な話も全く知らなかったのですが,用語などから入ってくれてわかりやすかったです. 主に単体法,最急降下法ニュートン法の話が多いです. 組み合わせ最適化については全く扱わないので注意です.

グラフにおけるカーディナリティ

cardinality は「濃度」みたいな意味だけど,size だと思って良さそう.

  • 集合では元の数
  • グラフでは頂点の数
  • ハイパーグラフでも頂点の数
  • ハイパーエッジでは,接続している頂点の数(だから普通のエッジのカーディナリティは2だね 自己辺のカーディナリティは1)

Julia のメリットとデメリット

Julia を書いているとどういうメリットがあるかを聞かれることが多いので,Python を始めとする他言語と比較した時のメリットやデメリットを書きます.しかし,「for文が速い」みたいな月並みなことや「1/2 を 2\1 と記述できる」などのような役立った試しがないようなことは書きません. 当方 Julia,Python ともにエアプなので,こういう構文・機能を使えば便利だよ.みたいなものがあったら教えてくださると幸いです.

メリットとデメリット共に発見次第追記していく予定です.

メリット

Dot 構文

f.(x)みたいなやつです.x が配列などの時に x の各要素に関数 f を適用します. Python では map 関数を用いることにより同様のことをできますが,f の引数が複数あったりすると面倒です. 例えば,

def f(x, y):
    return x + y

を用いて,配列 (リスト) L の要素すべてを 10 増やしたいとします.

map(lambda i : f(i, 10), L)

Python だとこのようになりますが,Julia だと

f(x, y) = x+y
f.(i, 10)

と簡潔になります.

このDot構文は演算子にも適用できて,要素同士の演算が 「.==」 や 「.+」などでスッとできます.

引数の値を後ろの引数で使える

Python では

def f(x, y=x+10):

のような関数は宣言できませんが,Juliaでは

function f(x, y=x+10)

のような宣言ができます. 割と便利です.

パッケージ管理ツールで悩まない

Python はpipenv や poetryなどたくさんのツールがありますが,Julia は言語がデフォルトで持っているので選択の余地がありません,多分.

デメリット

for文でエラーが生まれやすい

for i in l
end

でfor文が書けますが,lがInt型でも動いてしまいます. 例えばPythonだとlがIntだとエラーが出てくれます.

日本語の情報が少ない

頑張って英語を読みましょう.そして我々が日本語で情報発信をやっていきましょう. もしかしたら英語の情報も Python などと比べると少ないかもです.

引数の名前を指定した呼び出しが不便

Pythonでは任意の引数を名前を指定して呼び出せます.

f(x=10, y=10)

Julia ではこれはできなくて,名前を付けて呼び出すには

function f(x; y)

のようにあらかじめ宣言しておかなければしなければなりません.このように宣言すると,セミコロンの後の引数のみ名前を付けて呼び出せます. しかしこの宣言だと,今度は必ず引数の名前を指定しなくてはならないので不便です.

precompile をする必要がある

例えばJupyterでカーネルのリスタートするたびに,各ライブラリの precompile が走り,待つ必要があります. precompile のおかげで高速になるため仕方ないですが,速度が要求されない小規模なシミュレーションなどをする際は別言語を使ったほうが良いかもです. 結構待つものの,噂によると Julia 0.6 で大幅に高速化されるらしいです.

プログラムの強制終了に時間がかかる場合がある

自分の環境のせいかもしれませんが,Jupyter の Interrupt the kernel をクリックしてもすぐにプログラムが止まらない場合があります. 連打すると止まる場合がありますが,勝手にカーネルがリスタートしていたりします.

module の import が遅いがち

Julia でモジュールを利用するときは

using package_name

と書くのですが,precompile が無くてもなんか遅いです.なんででしょう.

出力が遅い

例えば

x = 1
for i in 1:N
  x += i
  println(x)
end

などと書くと,for文が終わってから出力されたりします.なんででしょう.

「クラスタリング」のニュアンスの違い

今まで「クラスタリング」と聞くと,「データをいくつかの集合 (クラスタ) に分割すること」をイメージしていました. 実際,scikit-learn の spectral_clustering や Louvain 法などはこのような操作をしているし,私の研究でもこのような操作をするアルゴリズムを考えています.

しかし,

KDD 2020 | Minimizing Localized Ratio Cut Objectives in Hypergraphs

KDD 2020 | Parameterized Correlation Clustering in Hypergraphs and Bipartite Graphs

の論文ではクラスタリングのニュアンスが違っています. これらの論文では「あるデータ集合にとって適切な要素の発見」というようなニュアンスで使われています. 「ユーザーの聞いた音楽集合が与えられたときに,最も適切な新しい音楽をサジェストする」ようなことに応用したい場合は,このニュアンスのクラスタリングアルゴリズムを用いる方が適切だと思います.

この2つのクラスタリングにおいて,前者のニュアンスでは「Modularity」,後者のニュアンスでは「Conductance」を用いてクラスタリングの適切さが測られていることが多いです.

…ニュアンスの違いを適切に言語化できていない気がしますが,このような違いがあることを頭の片隅に置いておくと論文を読んだときに変な混乱を防げる気がします.

ところで,「Clustering」と類似した言葉に「Community Detection」や「Cutting」や「Partitioning」などがありますので,これらの単語がそれぞれ適切に意味付けられればいいなと思ってます. (僕がエアプなだけで実際にはそれぞれ違う意味付けがされているのかも)

Affinity Matrixとは?使い方は? 調べてみた!

Affnity Matrixとは,データ間の類似度を表す行列です. Spectral Clusteringなどでは隣接行列がそのまま使われます.

いかがでしたか? この記事が良いと思った方はチャンネル登録,グッドボタンおねがいします!!

僕が一人暮らしをしようと思った理由

自分でも自分の考えをまとめておきたかったので,書きます. 一人暮らしを考えている方の助けになれば幸いですが,個人的な考え方がかなり強く出てしまうと思います.

1. 大学が遠いから

大学が遠いと大学に行く気が大きく失せます. 僕の場合通学に往復3-4時間はかかります.これを毎日のように行うのは馬鹿です.

2. 友達と自由に遊ぶ空間ができるから

みんなでお酒を飲みながらボードゲームなどやりたくないですか?僕はやりたいです. ところで1Kか1Rなのでそんなに人間が部屋に入るかはわかりません.

2. 今より正しくお金の価値を知りたいから

実家暮らしをしている限り正しいお金の価値を知ることはできないと思っています. 生きていくために必要な多くの費用を家族に支払ってもらう,または共同で支払うからです. お金の価値を正しく知らないと,「お金を稼ぎたい」という自分の中の欲求を正しく自覚しにくいです. この欲求を正しく知らないと,自分にとって最善のお金の稼ぎ方(自分にとって,十分幸せに生活するにはどれくらいお金が必要なのかなど)がわかりません. 今回は親からいくらか仕送りをしてもらうので,完全に正しい価値を知ることはできないでしょうが,それでも今よりは正しく認知できるでしょう.

3. 一人で生きていく力を身に着けたいから

僕はクズなのでおそらく結婚はできません. 祖父母や父母は十中八九僕より早く死ぬでしょう. いずれ一人で生きていく必要が出てきます. 父母が生きているうちに大きな失敗をしておいたほうが無難でしょう.

まとめ

やっぱり言語化すると考えがまとまっていいですね.

想定質問

  • 今の時勢に毎日のように大学まで行く必要はなくないですか?
    • 僕は作業場所は家でないところが良いので,どこかしら作業場所は欲しいです. 一人暮らしするより安価で大学より環境の良い作業場所があるなら教えてほしいです.
  • 結婚できるよう努力はしないのですか?
    • その努力のほうが一人暮らしより難易度が高いように思えます.