こんにちは。
父ラボ運営者のMAMEです。
プログラミング能力0から、機械学習、AI、データサイエンスをPythonで学び始めて3ヶ月。
いよいよ、データ分析スキルをどこまで高めることが出来たか確認する最終課題に取り組んでいます。

テーマは自由なので何に取り組むべきか悩むこと数時間。やはり興味のあることにしたいということで、ここ数年改めて見始めている全米プロバスケットボールリーグ(NBA)のデータ分析に取り組むことにしました。折しも日本人初のドラフト1巡目指名で話題の八村塁(はちむらるい)選手で日本のバスケット熱も盛り上がっています。下の写真もかっこいいですよね〜!

八村塁選手の画像日本代表での八村塁選手(出展:wikipedia)

データ分析の目的とパラメータの検討

またデータ分析するにあたって、まずは目的を明らかにしたいと思います。
そこは、八村選手のような新人バスケットボールプレイヤーがどのようにしたらNBAで成功できるか?を明らかにして提言することにしようと考えました。

  • 成功の定義=優勝回数や人気など色々とあるのでしょうが、簡単に数値化できそうなサラリー(給料)の高さで定義します。
  • 分析パラメータ=バスケットの成績、所属チーム、ポジション、SNSでの人気度など

こういった分析を行うためのデータを準備する必要があります。
kaggleでは様々なプロジェクトが行われており、それに伴うデータセットも存在しています。
NBAに関するデータも次のようなものがあります。

https://www.kaggle.com/drgilermo/nba-players-stats
https://www.kaggle.com/data/52669
https://www.kaggle.com/justinas/nba-players-data

Kaggleでアカウントを作成すればこれらのデータセットを使って分析することが可能となります。
アカウント作成し、データをダウンロードしてみました。

まずはデータを見てみましょう

NBAのデータセット

Kaggleからダウンロードしたデータをまず確認してみました。
多くの種類のデータがありますが、今回必要なデータは「バスケットの成績、所属チーム、ポジション、SNSでの人気度など」が入ったデータ、もしくはそれぞれのデータが入っているデータを結合したデータです。できればひとまとめになっていると楽です。。。)

これらをざっと確認したのち今回は、https://www.kaggle.com/noahgift/social-power-nbaより入手したnba_2017_players_with_salary_wiki_twitter.csvを分析データとして用いることにしました。

まずは諸々必要そうなライブラリと、データを読み込み、データを訓練データとテストデータにわけてみます。訓練データ70%、テストデータ30%です。

次にtrain_df, test_dfの全ての特徴量について、infoメソッドを利用して欠損値の有無を確認します。
欠損データがあれば補完しておきます。結果が長いので省略。

どの特徴量がサラリー(SALARY_MILLIONS)に影響を与えるかを調査

まず所属チームごとのサラリー平均に差があるかを調査します。データが全チーム、全選手というわけではないので偏りが出そうですが、所属するチームによってサラリーが良い、悪いというのは出てきうることなのかなと。

結果としては次のようにチームにより差はありそうです。
CLE(クリーブランドキャバリアーズ)、GS(ゴールデンステートウォーリアーズ)の2チームはこのデータの当時東西のトップチームでしたので、そこに所属している選手のサラリーがよかったということでしょうか。
4位のWSH(ワシントンウィザーズ)はなんと八村選手が所属するチーム。八村選手なかなかよいのでは?

次のポジションごとにサラリーの差があるかを見てみましょう。
バスケットボールにはセンター(C)、パワーフォワード(PF)、スモールフォワード(SF)、シューティングガード(SG)、ポイントガード(PG)といったポジションがあります。この辺詳しく知りたい方は「スラムダンク」をご覧ください。

データは十分ではないかもしれないが、ポジションによる差もありそうですね。
ちなみに八村選手はパワーフォワード(PF)、スモールフォワード(SF)あたりのポジションで出場していることが多そうです。
スモールフォワード(SF)おすすめです。

続いて年齢について。何歳くらいにピークがあるといいのでしょうかね?

25才くらいでピークがあるようです。意外と若いですね。

これまでのようにひとつひとつ見ていってもよいのですが、ヒートマップ(関連図)を作成し、どのパラメータが関連性があるかを見る方法もあるということを教わりました。

結果下図のように、年齢、得点に関するパラメータ、出場時間、出場ゲームでの勝率、ページビュー(Wikipediaの)がサラリーに影響しそうです。


そこで、年齢、出場ゲームでの勝率とサラリーの関係を調査してみます。

こちらを見ると、年齢は25-30前半までがサラリーが高く、各年代では出場ゲームの勝率の高さもサラリーに影響していそうです。


次は、1試合当たりの出場時間、PIE(Player Impact Estimate)とサラリーの関係を調査してみます。

1試合当たりの出場時間の長さによりサラリーが高い選手が出現しています。いい選手ほど長い時間出場するということでしょうが、長い時間出場できる選手になるというのも重要なファクターになりそうです。


次は、得点、ターンノーバー数(ボールを失った回数)とサラリーの影響を調査します。

得点が高いほどサラリーの高い選手が現れる傾向あります。これは直感的に理解しやすいですね。
一方、ターンノーバー数(ボールを失った回数)の高さもある程度そう感が見られそうです。これは直感的に逆なイメージですが、おそらく多くボールを持つエース級の選手ほどターンノーバー数が高くなるためサラリーの高さと関連しているのかもしれません。


最後にWikipediaのページビュー数とサラリーの影響を調査します。

こちらも相関はみられそうです。人気選手ほど高いサラリーということかもしれません。目立つのが吉。

データ確認後にデータの前処理を行う

データセットよりプレーヤー名、通し番号等不要なデータを削除します。

以下で行う分析は回帰分析なので、 データ内に文字列があると分析できません。
そのため文字データを数値データに変換します

(参考サイト:pandasでカテゴリ変数をダミー変数に変換(get_dummies)

すると下のように各ポジションに当てはまる選手のところに1が入力され、当てはまらない箇所には0が入力されます。

続いて同様にチーム名の文字列データを数値データに変換します。
こちらも上と同様に.getdummiesを使用して変換したかったのですが、データ数が少なく訓練データとテストデータで出現するチーム数が異なってしまい、変換できませんでした
そこで下のように手動で各チームに数字を設定し、変換しました。
(参考:【Pythonステップアップ!】高階関数mapの便利な使い方
(参考:pandasで欠損値NaNを除外(削除)・置換(穴埋め)・抽出

*この記述がブサイクだったので、最終的にはプログラムのはじめに下記のように記述することとしました。すっきり!!

前処理の最後に訓練データとテストデータを完成させます。
これで一旦準備完成です。いや〜ここまで長かった。

いよいよデータ分析を行います


データ分析は、Pythonの機械学習ライブラリ「scikit-learn(サイキットラーン)」を用いて行いました。scikit-learnについては下記サイトをご参考ください。
これを使うことで、私のような素人もほぼ一瞬で「機械学習やってます」と言うことができます。
機械学習やってます。えっへん。

機械学習のライブラリ!scikit-learnとは【初心者向け】
scikit-learn(sklearn)の使い方

データ分析は「回帰」で行うか?「分類」で行うか?

データ分析も大きく分けると「回帰」と「分類」に分かれるかと思います
乱暴に説明すると「回帰」は連続した数値を予測するもの、「分類」は非連続的な状態を予測するものかと。今回は連続した数値であるサラリー(給料)を予測するものですので、回帰分析を行いました

線形重回帰分析

まずは回帰分析で最もシンプルと言える線形重回帰分析を行います。

誰でも出来る!!scikit-learn(sklearn)で重回帰分析しちゃう
Pythonで基礎から機械学習 「重回帰分析」
Scikit-learn で線形回帰

結果もあわせて記しています。決定係数が訓練データで0.76ですが、テストデータでは0.25程度とひどいもんでした。
各パラメータの係数はMPG、MPなどの出場時間に関するもの、eFG%、FG%、FGなど得点に関するもので高い値が出てきており、それっぽいです。

ラッソ回帰・リッジ回帰

より高い精度で予測できるモデルを探すために、他の回帰分析を試行します。
ここではラッソ回帰、リッジ回帰を試みました。
パラメータ調整は行っていませんが、結果は下程度。もう一息かな。

【機械学習】ラッソ回帰・リッジ回帰について メモ
ラッソ(Lasso)回帰とリッジ(Ridge)回帰をscikit-learnで使ってみる

ランダムフォレスト(回帰)

私の引き出しも残るは一つとなりましたが、ランダムフォレスト回帰分析です。
ランダムフォレストにも分類(RandomForestClassifier)と、回帰(RandomForestRegressor)がありますが、今回は後者です。
この結果、今回の中では最も高い、訓練データで決定係数0.93、テストデータで決定係数0.62が出ました。

なお、ランダムフォレストでは「.feature_importances_」で各変数の重要度を調べることができます。これで調べた結果も下に示していますが、AGE(年齢)、FGA(シュート試投数)、POINTS(得点)、TWITTER_FAVORITE_COUNT(Twitterお気に入り数)、PIE(Player Impact Estimate)などが上位5要素となりました。

TWITTER_FAVORITE_COUNTなどが上位にきているのが面白いですよね。これからすると、シュートをたくさん打ち、得点を重ね、SNSで活躍できるいい年齢の選手が高額なサラリーを獲得できるということです。わかったかな八村選手

(参考サイト)
機械学習手法「ランダムフォレスト」で回帰分析にチャレンジ
Pythonでデータ分析:ランダムフォレスト
“PIE” ってなに?

ランダムフォレスト(回帰)について学習曲線を検討する

ここまでで、RandomForestRegressorが良さそうなのがわかりましたが、訓練データの精度に比べ、テストデータの精度が低い課題が残っています。
こちらに関しては原因を調査してみましょう。

(こちらのサイトを参考にしました)
AI(機械学習)のモデル精度向上に効く!学習曲線と検証曲線を入門

こちらの図のように、訓練データは精度良くフィッティングしていますが、テストデータについてはいまいちのようです。
参考サイトによると、この状態は過学習=「バリアンスが高い(ハイバリアンス)」のようです
これを解消するには、特徴量を減らして過剰なフィッティングを抑えるなどが効果的とのことです。
まだまだ改善可能そうですね。

パラメータサーチでモデルを最適化

テストデータの精度向上のため、RandomForestRegressorのパラメータサーチを試みました。
なお、ネット情報によるとRandomForestRegressorは初期状態でもまずまずの精度を持っているようです。
パラメータサーチのために用いたのはGridSearchCVです。
結果テストデータの精度は0.64程度となり、0.01程度の改善がみられました。

XGBoostで最後に分析

xgboostでの分析にもチャレンジしました。
パラメータサーチが十分でないかもしれませんが、結果はRandomForestRegressorと同程度でした。

(参考サイト)
xgboost: テーブルデータに有効な機械学習モデル
XGBoostのハイパーパラメータをチューニングする

最後に

八村選手へ。とにかく貪欲に得点を取りに行って下さい。SNSも更新してください。
そうしたら間違いなく高級取りや!

↓↓微力ながら八村選手の給料に貢献。↓↓
https://www.instagram.com/rui_8mura/
https://twitter.com/rui_8mura?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor

以上で3ヶ月で学習したデータ分析の成果報告を終了します。
いざ書いてみると大したことはしていないように感じますが、3ヶ月前の全くのプログラミング経験ゼロの自分からみたらすごいことしているように見えるでしょうね。

これもAIDEMYの講師の皆様のご指導の賜物です。
どんな質問にも丁寧に対応頂きありがとうございました。