さて、本日は機械学習のクラスタリングという手法を使ってFIFA 20 のプレイヤーをグルーピングしてみようと思います。
FIFA20 とは
『FIFA 20』は、EAスポーツが開発し、エレクトロニック・アーツより2019年9月27日に世界同時発売されたサッカーゲーム。(出典:Wikipedia)
使用するデータデータ
Kaggle の「FIFA 20 complete player dataset」にある「players_20.csv」を使用します。
Kaggle とは
Kaggleは企業や研究者がデータを投稿し、世界中の統計家やデータ分析家がその最適モデルを競い合う、予測モデリング及び分析手法関連プラットフォーム及びその運営会社である。 (出典:Wikipedia)
クラスタリングとは
(統計学)データ解析手法の1つ。「クラスタ解析」、「クラスター分析」とも。機械学習やデータマイニング、パターン認識、イメージ解析やバイオインフォマティックスなど多くの分野で用いられる(データ・クラスタリングを参照)。クラスタリングではデータの集合を部分集合(クラスタ)に切り分けて、それぞれの部分集合に含まれるデータが(理想的には)ある共通の特徴を持つようにする。この特徴は多くの場合、類似性や、ある定められた距離尺度に基づく近さで示される。(出典:Wikipedia)
使用するクラスタリング手法
k-meansクラスタリングを使用します。
関連エントリー
機械学習関連のエントリーです。興味のある方はぜひ読んでみてください。
環境
Windows10 64bit
Python3.8.5
手順
- データ分析
- クラスタリング
- 可視化
1.データ分析
データ読込
プレイヤーのデータを読み込みます。
import pandas as pd data = pd.read_csv(r"players_20.csv") data.head()
なんと104カラムもありますね。
データ探索
カラムの型や基本統計量などを確認します。
data.shape data.info() data.describe()
カラム選定
クラスタリングを行うにあたって必要なカラムを選択します。また、フィールドプレイヤーとゴールキーパーによって使用するカラムを分けます。
################################################ # フィールドプレイヤーの分析に必要なカラムをセット # ################################################ data_field_players = data[data.player_positions != "GK"] field_players_features = ['short_name','overall','potential', 'skill_moves', 'pace','shooting','passing','dribbling','defending','physic'] # 名前ありデータフレーム data_field_players = data_field_players[field_players_features] # 名前なしデータフレーム data_field_players_drop = data_field_players.drop(columns = ['short_name']) ################################################ # ゴールキーパーの分析に必要なカラムをセット # ################################################ data_goal_keepers = data[data.player_positions == "GK"] goal_keepers_features = ['short_name','overall','potential', 'skill_moves', 'gk_diving','gk_handling','gk_kicking','gk_reflexes','gk_speed','gk_positioning'] # 名前ありデータフレーム data_goal_keepers = data_goal_keepers[goal_keepers_features] # 名前なしデータフレーム data_goal_keepers_drop = data_goal_keepers.drop(columns = ['short_name'])
2.クラスタリング
まずはスケーリングをします。
スケーリング(フィールドプレイヤー)
# スケーリング(フィールドプレイヤー) from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaler.fit(data_field_players_drop) data_field_players_drop_scaled = scaler.transform(data_field_players_drop) field_players_df = pd.DataFrame(data_field_players_drop_scaled) field_players_features.remove('short_name') field_players_df.columns = field_players_features field_players_df
スケーリング(ゴールキーパー)
# スケーリング(ゴールキーパー) from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() scaler.fit(data_goal_keepers_drop) data_goal_keepers_drop_scaled = scaler.transform(data_goal_keepers_drop) goal_keepers_df = pd.DataFrame(data_goal_keepers_drop_scaled) goal_keepers_features.remove('short_name') goal_keepers_df.columns = field_players_features goal_keepers_df
エルボー法(フィールドプレイヤー)
エルボー法で最適なクラスター数を検討します。
import matplotlib.pyplot as plt distortions = [] for i in range(1,11): km = KMeans(n_clusters=i, init='k-means++', n_init=10, max_iter=16242, random_state=0) km.fit(field_players_df) distortions.append(km.inertia_) plt.plot(range(1,11),distortions,marker='o') plt.xlabel('Number of clusters') plt.ylabel('SSE') plt.show()
「クラスター数3が最適なクラスター数」と判断します。
エルボー法(ゴールキーパー)
import matplotlib.pyplot as plt distortions = [] for i in range(1,11): km = KMeans(n_clusters=i, init='k-means++', n_init=10, max_iter=2036, random_state=0) km.fit(data_goal_keepers_drop) distortions.append(km.inertia_) plt.plot(range(1,11),distortions,marker='o') plt.xlabel('Number of clusters') plt.ylabel('Distortion') plt.show()
こちらも「クラスター数3が最適なクラスター数」と判断します。
さて、いよいよクラスタリングですね。
クラスタリング(フィールドプレイヤー)
from sklearn.cluster import KMeans kmeans = KMeans(n_clusters = 3) kmeans.fit(field_players_df) result = kmeans.predict(field_players_df) # 名前ありデータフレームにクラスタリングの結果を格納 data_field_players['cluster_id'] = result # 名前なし、かつ、スケーリング済みのデータフレームにクラスタリングの結果を格納 field_players_df['cluster_id'] = result field_players_df.head()
クラスタリング(ゴールキーパー)
from sklearn.cluster import KMeans kmeans = KMeans(n_clusters = 3) kmeans.fit(goal_keepers_df) result = kmeans.predict(goal_keepers_df) # 名前ありデータフレームにクラスタリングの結果を格納 data_goal_keepers['cluster_id'] = result # 名前なし、かつ、スケーリング済みのデータフレームにクラスタリングの結果を格納 goal_keepers_df['cluster_id'] = result goal_keepers_df.head()
3.可視化
クラスタリングの結果を可視化します。
フィールドプレイヤー
# 可視化 import matplotlib.pyplot as plt clusterinfo = pd.DataFrame() for i in range(3): clusterinfo['cluster' + str(i)] = field_players_df[field_players_df['cluster_id'] == i].mean() clusterinfo = clusterinfo.drop('cluster_id') my_plot = clusterinfo.T.plot(kind='bar', stacked=True, title="Mean Value of 3 Clusters") my_plot.set_xticklabels(my_plot.xaxis.get_majorticklabels(), rotation=0) plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=18)
結果が出ました。以下のような傾向があることがわかります。
- cluster = 0 のプレイヤー:全体的に能力が高い。スタープレイヤーと考えられる。
- cluster = 1 のプレイヤー:スピードとドリブル能力が高い。ウイングのようなタイプと考えられる。
- cluster = 2 のプレイヤー:フィジカルとディフェンス能力が高い。ディフェンダーと考えられる。
それぞれのクラスターに属する選手です。cluster = 0 はメッシやロナウドなどが所属しており、スタープレイヤーのグループという推測はあってそうですね。
ゴールキーパー
# 可視化 import matplotlib.pyplot as plt clusterinfo = pd.DataFrame() for i in range(3): clusterinfo['cluster' + str(i)] = goal_keepers_df[goal_keepers_df['cluster_id'] == i].mean() clusterinfo = clusterinfo.drop('cluster_id') my_plot = clusterinfo.T.plot(kind='bar', stacked=True, title="Mean Value of 3 Clusters") my_plot.set_xticklabels(my_plot.xaxis.get_majorticklabels(), rotation=0) plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=18)
結果が出ました。以下のような傾向があることがわかります。
- cluster = 0 のプレイヤー:全体的に能力が低い。若手やレベルの低いリーグのキーパーと考えられる。
- cluster = 1 のプレイヤー:全体的に能力が中くらい。中堅レベルのキーパーと考えられる。
- cluster = 2 のプレイヤー:全体的に能力が高い。スタープレイヤーと考えられる。
それぞれのクラスターに属する選手です。知っている選手がいないのですが、能力を見る限り推測は正しそうな気がします。
さいごに
いかがでしたでしょうか?クラスタリングを使用するとデータセットの中から類似データごとにグループ分けをしてくれます。とても便利ですね。大量のデータの中から何かしらの法則を見つける方法はクラスタリング以外にもありますので、今後はそういったものも紹介していこうと思います。本日は以上です。