未経験から100日間でデータ分析コンペでメダル獲得したお話【前編|データ分析編】
はじめに
記事を書こうと思ったきっかけ
ご覧いただきありがとうございます!わとと申します。
私は8月末からデータサイエンティストへの転職を目指して勉強しており、その一環で日本最大級のデータサイエンスコンペ「SIGNATE」で開催された、SMBCグループ主催のコンペに参加しました。その結果として銅メダルを獲得することができました!
そこで今回は、SMBCのコンペに対して、具体的にどのように分析を進めたのか、どのような姿勢で取り組んだのかを前後編に分けてお届けします。前編はデータサイエンスに取り組んでいる人へ、後編はデータサイエンス以外でも何かに取り組んでいる人へ役立つのではないかと思っています。今回は前編です。何かひとつでも皆様の人生を変えるきっかけになればとても嬉しいです!よろしくお願いします!
読者ターゲットと求めている行動
データサイエンスの勉強に取り組んでいる方
→何か1つでも勉強になることを持ち帰ってください!
→アドバイス・質問も大歓迎です!データサイエンティストの方
→まだまだ未熟なため、アドバイスを大歓迎しております!
→将来はデータサイエンティスト転職を目指しているので、ご興味ありましたらご連絡ください!(X:@hgdn_biglove)上記含めて全ての方
→もしご興味あれば前編も読んでいただきたいですが、後編にてコンペに取り組んだ中で整理した自分の人生の価値観をお話する予定です。あなたの人生を変えるきっかけになれば嬉しいので、よかったら後編もご覧いただきたいです!
コンペ前のステータス
本当にざっくりというと、全くのデータサイエンス未経験から2ヶ月でビギナーコンペ2位を獲得した状態です。「そもそもどうしてデータサイエンス転職を目指したの?」「SMBCのコンペ以前はどんな勉強をしていたの?」が気になる方は、前回の記事でまとめています。是非ご覧ください!
また、後編でも深掘りしてお話する予定ですので、僕という人間に興味が湧いた方はぜひご覧ください。funnyかつinterestingな文章にするつもりです笑
コンペ概要と結果
概要
今回のコンペが何をするものなのかわからないと、読んでいてちっとも面白くないと思うので、まずは概要を説明します。詳細を知りたい方はコンペのHPをご覧ください。
タイトル
SMBC Group GREEN×DATA Challenge 2024
ーGHGの排出量の予測にチャレンジしよう!ー開催期間
2024年11月1日(金) 19:00〜2024年12月5日23:59.59タスクとデータ
目的変数:2014年の温室効果ガス(GHG)の排出量
学習用データ:2014年の排出量報告済み施設のデータ
検証用データ:報告未実施施設のデータの50%
評価用データ:報告未実施施設のデータの残り50%
各施設についてのデータは、緯度経度・州などの位置データ、産業分野などの業界データ、過去の排出量などの時系列データが与えられていました。評価指標
RMSLE
今回のGHGの値は10^4~10^5とオーダーが大きいため、誤差の大きさの影響度を含めた評価指標となっていた(予測と正解が1000ズレていた時に「100000を99000と予測してしまう」のと「2000を1000と予測してしまう」のでは後者の方がマズイから、そういう予測に対して罰点を与えるようなイメージ)
結果
LB上の暫定順位(スコア)
20位 / 864人 (RMSLE:0.7199364) → 銀メダル圏内(11~50位)最終順位(スコア)
57位 / 864人 (RMSLE:0.8192771) → 銅メダル獲得(51位~100位)
のように、メダルを獲得することができました!ウレピー!!
ただ、結果を確認した時の第一印象は「悔しい」でした。暫定から最終で大幅に精度と順位が悪くなってしまいました。精度は他の方も漏れなく改悪していたのですが、その幅が他の方より大きかったため、順位が下がって銀メダル圏外になってしまいました。モデルの汎化性能に拘れなかったからですね。反省です。
期待していたほどの結果には至らずとはいえ一定の成果が出たため、自分の分析過程でも何かの参考にはなるのかと思います。どのような思考過程でどのような分析を行ったのか、最終的な特徴量やモデルチューニング、アンサンブルについてお話しますので、是非ご覧ください。同じコンペに参加された方がいらっしゃれば、どのように分析を行ったのかを是非教えてください!
カラム名を見た際の仮説
カラムを見た際に、今回のデータは大きく3種類にカテゴライズされると考えました。以下はそのカテゴライズとそこで考えた仮説です。
位置データ
施設の緯度経度や住所、所属する州・市・郡といった、「その施設がどこにあるの?」を表すデータが与えられていました。 そこで自分の中で思いついた仮説は以下のようなものでした;
GHGの排出量は、天気とは違って単純な地形的な要因は関係ないはずなので、単純にインプットしても改善にはあまり影響しないはず
温室効果ガスは工業が発展している地域ほど排出量がはず
→日本と同様に都心ほど排出量が多い?
→田舎ほど工場が多く設置されて逆に排出量が多い?州レベルだと面積が広すぎて差がつかないし、市・郡レベルだとカテゴリが細かすぎるので、単純にエンコーディングしても改善には繋がらない気がする
業界データ
産業タイプやNAICSコード(業種を分類するための6桁のコード)といった、「その施設は何をするところなの?」を表すデータが与えられていました。そこで自分の中で思いついた仮説は以下のようなものでした;
GHGの排出量は、産業や業種に大きく影響するはずなので、改善に繋がる気がする
ただし、NAICSコードの6桁分類だとカテゴリが細かすぎる。コードの先頭2桁が「建設」「小売」「製造」…といった産業の大分類を、3桁目までがもう少し細かい分類を表しているので、先頭2桁or3桁をエンコーディングするくらいが良いのでは?
時系列データ
2010年〜2013年の有害物質排出量(TRI)やGHG排出量といった、「その施設は過去にどのくらい排出していたの?」を表すデータが与えられていました。そこで自分の中で思いついた仮説は以下のようなものでした;
GHGの排出量は、過去の排出量の延長線上にあるはずなので、元のカラムの中では最も改善に繋がるはず
特に、前年との変化を表す差分や比率、毎年の平均や標準偏差は大きく改善に繋がる気がする
有害物質排出量と温室効果ガス排出量に関係があるなら精度改善に繋がる?もしくは多重共線性が生じて改悪になる?
上記のような仮説を持ちつつも、基本に忠実にまずはベースラインを作成しました。
ベースライン作成時(11/1)
最低限のデータ確認
最低限のデータ確認として、データ量やデータ型、欠損値の数を確認しました。一般コンペはデータ数が多いものだと勝手に思い込んでいたので、4000件程度と知ったときはかなり驚きました。また、数的データはどれも欠損値が存在していたので、ベースライン作成時にどのカラムを投入するか一瞬悩みました。
ベースライン作成
結局、特徴量としては2010年〜2013年のTRI、GHG排出量を投入しました。(今考えるとGHGだけで入れた方が、TRIを入れた時との差分がわかってよかったなと感じました)モデルは王道のLightGBMです。
評価指標として、Light GBMにはRMSLEが標準搭載されていないため、その部分の実装には工夫が必要でした。ちなみにこの時点では誤ったコーディングを行なってしまっていましたため、後々修正します。
LBのスコアだけでなく、CVスコアも確認できるように、KFoldを用いました。ひとまず分割数は5にしました。
また、Light GBMをせっかく用いるので、特徴量のImportanceも確認できるように、各Foldごとに格納して合計を算出していました。やはりGHGの方がTRIよりImportanceは大きかったです。
このようにベースラインを作成して提出したスコアは0.870程度でした。この時点での上位が0.72台を叩き出していたので焦りつつも、ひとまずは特徴量エンジニアリングに進みます。
EDAと特徴量エンジニアリング(11/2~9)
ざっくりとしたEDAメモ
全てを書き下すとキリがないので、特徴量として使いうると考えたものだけ抜粋します。
緯度経度は欠損値あり。欠損しているレコードだけ抜き出したら以下のような特徴あり
詳細住所に緯度経度が書かれているデータがいくつかあった
→その値を用いて正確な緯度経度を補完することが可能市が"OFFSHORE"(本州外)になっている。しかし州は記載あり
→東京で言う小笠原諸島みたいな位置付けかと思い、州の平均緯度で補完するのは危険な気がした。欠損情報を残した方がフラグが残って良い気がした。
産業タイプは"x","x,y","x,y,others"のようにカンマわけでものすごいカテゴリー数になっていた
カンマでデータを区切って特徴量にしようかとも思ったが、それならNAICSコードの先頭2,3桁で良いと思い、特徴量には使わず
TRI、GHG排出量は左に偏った分布になっていた
LightGBMでは大小関係しか関係ないので当座スケール変換はしないが、集約統計量を取るときには必要だったりするのかな?程度の認識
※詳しい方は教えてください!
TRI、GHGの欠損値処理
欠損値を単純な中央値補完する、丸めたNAICSコードごとに中央値補完する、何もしない等の前処理の候補がいくつか思いつく
特徴量エンジニアリング
上記の仮説を検証するために、特徴量生成や欠損値補完などを行いましたが、自分の場合精度改善につながった施策は以下のみでした。
GHGの2010年から2013年の平均値と標準偏差
各年のTRIとGHGの比率
緯度経度を詳細住所から補完
これらをして精度改善するも、0.8xxから抜けられず、かなり苦しんでいました。データサイエンスにおいては、特徴量エンジニアリングが最も重要だと思っている中で上位の方に全然追いつけず、ぶっちゃけモチベダダ下がりでした。
そんな中でモチベーションを上げようと色々工夫したのですが、その話は後編の方に書こうと思います。だから読んでね??(圧)
ベースライン再作成・ハイパラ調整(11/15~11/20)
モチベも戻り、再度コンペに集中しました。まずはベースラインの修正をしました。というのも、CVスコアとLBスコアの桁が違っていたので、モデリング部分で何か変だな〜と思っていたからです。結論としては、y_trainにlog1p処置をして投下していたのにrmsleで評価してしまい、二重に対数処理をしていたせいでした。
無事にベースラインを修正できたものの特徴量エンジニアリングでは本当に改善されないので、思い切って少しだけハイパラを調整しました。いじったのはlearning_rate、n_estimators、num_leavesだけで、それによってスコアが0.737まで一気に改善しました。あまりにも初期のハイパラが悪すぎたんですね。次のコンペでも、最低限のハイパラ調整は初期のうちにやってみても良いのかなと思いました。
とにかく、これでようやくコンペに参加できた感が出てきて、メダル獲得を意識しはじめました。
Optuna+手動でのLightGBM調整(11/21~24)
その後もChatGPTと会話しながら特徴量エンジニアリングで色々と試しましたが、自分の場合は改善されませんでした。コンペも期間としては後半になってきたので、ハイパラ調整を再度行いました。今回はOptunaも使って調整したところ、0.733程度まで改善しましたが、best_paramsのnum_leavesやdepthの値はもっと工夫できると感じて手動で調整したら0.727までは改善しました。
他モデル作成・ハイパラ調整(11/25~30)
LightGBMは一旦触るのをストップして、他のGBDT系のモデルを作成しました。具体的にはCatBoostとXGBoostです。今回はカテゴリカルデータを投入していないので、あまりCatBoostは良くないと思っていたら予想通りあまり良いスコアはでませんでした。ただ、XGBoostはハイパラ調整前なのに0.7230(当時の銅メダルボーダー付近)のスコアが出たため、この後はXGBoostを育てることに注力しました。
XGBoostのハイパラ調整は、depthを手動で調整した際に自分の特徴量の場合は4のときがスコアが最もよかったので、depthを4に固定した上でOptunaで調整した結果、0.7222の銅メダル圏内に到達し、過学習を抑えるためにlearning_rateを半分にしつつn_estimatorを倍にしたところ、CV・LBともに改善して、0.7203939の銀メダル圏内に到達しました。
本当はアンサンブルで汎化性能を高めることを目的にdepthを3や5のXGBoostであったり他モデルも育成した方が良かったのですが、どうにもLB上のスコアが良くなかったので棄却してしまいました。単体スコアに捉われずに、汎化性能のために幅広いモデルを育成すればよかったなというのが、次回に向けた反省点です。
アンサンブル・スタッキングでの最終調整(12/1~5)
LBスコアが0.720~0.721のXGBoostを4本育てることに成功したので、コンペ最終盤はそれらを用いてアンサンブルすることにしました。4つのモデルを単純平均して0.7201263に、LBスコアが低いひとつを除外して単純平均したら0.7199364(LB暫定20位)になりました。
その後、今までのコンペで初めてスタッキングを試しました。3つのモデルでのスタッキングで特徴量を作成したのに加え、3モデルの単純平均も特徴量としましたが、暫定LB0.7215827とあまりよくありませんでした。が、コンペ終了後に蓋を開けてみると最終LB0.8165279(最終3位相当)だったため、ファイル選択しておけば金メダルだったのかと思うと悔しいです。最終日で慌てていて確認していなかったのですが、CVもかなりよかったので、冷静でいれば選択し得た分だけに余計に悔しいです。次回は提出ファイル選択も丁寧に行いたいです。
総評
今回のコンペに参加して振り返ったときに、良かった点は継続して出来るままでありたいですし、悪かった点は改善して出来るようになりたいので、整理しておきます。
良かった点
特徴量を投入するときに、考えなしに投入するのではなく仮説を持って投入するという、仮設思考が実践できたこと
特徴量エンジニアリングが最重要だとわかりつつも、変に固執することなくパラメータが的外れであると疑えたこと
submit数が限られているので、cv確認を重視してコード修正をしたこと
XGBoostのハイパラ調整(ビギナーコンペでも上手くできた)
スタッキングという手法を自分の中で新たに導入できたこと(今までできなかったことでも必要に応じて身に着ける)
悪かった点
データの可視化が十分にできた自信がないので、次回はEDAで今回試さなかった手法を試してみる
特徴量生成や欠損値補完がほぼ精度改善に寄与しなかったので、ChatGPTを活用しながらもっと他の選択肢を試せるようになる
(スコアがデータセット依存なのは承知した上で)LightGBM、CatBoostのハイパラ調整が上手くできた試しがないので、次回はこれらのモデルのハイパラをもっと理解して調整してみる
LBスコアに依存しすぎていたため、CVスコアを信じ、汎化性能を高めるための工夫をする
最後に
長文にも関わらず最後までご覧いただき本当にありがとうございました!気持ち的には悔しさや反省が色濃い振り返りになったものの、学習開始から100日以内で一般コンペにてメダル獲得できたことは我ながら上手くいったなと思います。本気で学習を始める前には想像もできませんでした。
こんな短期間でデータサイエンティストとしての能力が十分に備わったわけでは全く無いですが、日々の学習に対しては本当に強い願いを原動力に取り組んでいます。コンペ期間で学習に費やした時間は約130時間(平均3.5h/day)でした。平日7~20時くらいまで働いていた中で時間確保したのは今後の自信につながりました。
次回参加のコンペはまだ決まっていませんが、良かったところはそのままに、悪かったところを改善し、今回が運だけでなかったことを証明していきたいと思います!
「スキ」「記事の拡散」をしていただけると大変励みになります!コメントにて質問やアドバイスもお待ちしております!
是非これからも応援よろしくお願いいたします。後編の【マインドセット編】もお楽しみに!