Grouping Soccer Players with Similar Skillsets in FIFA 20 | Part 1: K-Means Clustering | by Jaemin Lee | Towards Data Science

Soccer (European football) has been one of my favorite sports ever since I was little. I used to bring a ball with me anywhere I went so that I could maximize my opportunity to play soccer.
I also like playing soccer games — FIFA. I thought it would be cool to analyze players in FIFA using machine learning.
In this tutorial, I am going to use the K-Means clustering algorithm to group soccer players in FIFA 20 with similar skillsets.
Clustering is one of the unsupervised learning techniques (PCA is another one).
We can cluster (or group) observations into the same subgroups so that observations within a subgroup are quite similar to each other and observations in different subgroups are quite different from each other.
The scatter plot above shows us that there are three distinct groups within the dataset.
K-Means clustering is one of the clustering algorithms.
The basic algorithm is this:
Specify K-clusters and initialize random centroids
Iterate until the cluster assignments stop changing. The method assigns each observation to exactly one of the K clusters
For each K cluster, calculate the cluster mean
Proceed through the list of observations and assign an observation to the cluster whose mean is nearest.
The goal is to form the clusters in a way that the observations within the same cluster are as similar as possible.
K-Means clustering calculates similarity using Squared Euclidean distance.
We are going to use Kaggle’s FIFA 20 dataset.
We are only going to selected numeric values and each player’s name.
df = df[['short_name','age', 'height_cm', 'weight_kg', 'overall', 'potential','value_eur', 'wage_eur', 'international_reputation', 'weak_foot','skill_moves', 'release_clause_eur', 'team_jersey_number','contract_valid_until', 'nation_jersey_number', 'pace', 'shooting','passing', 'dribbling', 'defending', 'physic', 'gk_diving','gk_handling', 'gk_kicking', 'gk_reflexes', 'gk_speed','gk_positioning', 'attacking_crossing', 'attacking_finishing','attacking_heading_accuracy', 'attacking_short_passing','attacking_volleys', 'skill_dribbling', 'skill_curve','skill_fk_accuracy', 'skill_long_passing', 'skill_ball_control','movement_acceleration', 'movement_sprint_speed', 'movement_agility','movement_reactions', 'movement_balance', 'power_shot_power','power_jumping', 'power_stamina', 'power_strength', 'power_long_shots','mentality_aggression', 'mentality_interceptions','mentality_positioning', 'mentality_vision', 'mentality_penalties','mentality_composure', 'defending_marking', 'defending_standing_tackle','defending_sliding_tackle', 'goalkeeping_diving','goalkeeping_handling', 'goalkeeping_kicking','goalkeeping_positioning', 'goalkeeping_reflexes']]
I am extract players whose overalls’ are above 86 as we don’t want to use 18000+ players to group.
df = df[df.overall > 86] # extracting players with overall above 86
Replace null values with the mean.
df = df.fillna(df.mean())
Normalize (standardize/rescale) the data.
We want to normalize the data as variables are measured on different scales.
from sklearn import preprocessingx = df.values # numpy arrayscaler = preprocessing.MinMaxScaler()x_scaled = scaler.fit_transform(x)X_norm = pd.DataFrame(x_scaled)
Use PCA to reduce 60 dimensions into 2 for the plot.
from sklearn.decomposition import PCApca = PCA(n_components = 2) # 2D PCA for the plotreduced = pd.DataFrame(pca.fit_transform(X_norm))
We are going to specify that there are 5 clusters.
from sklearn.cluster import KMeans# specify the number of clusterskmeans = KMeans(n_clusters=5)# fit the input datakmeans = kmeans.fit(reduced)# get the cluster labelslabels = kmeans.predict(reduced)# centroid valuescentroid = kmeans.cluster_centers_# cluster valuesclusters = kmeans.labels_.tolist()
Make a new data frame by adding players’ names and their clusters.
reduced['cluster'] = clustersreduced['name'] = namesreduced.columns = ['x', 'y', 'cluster', 'name']reduced.head()
import matplotlib.pyplot as pltimport seaborn as sns%matplotlib inlinesns.set(style="white")ax = sns.lmplot(x="x", y="y", hue='cluster', data = reduced, legend=False,fit_reg=False, size = 15, scatter_kws={"s": 250})texts = []for x, y, s in zip(reduced.x, reduced.y, reduced.name):texts.append(plt.text(x, y, s))ax.set(ylim=(-2, 2))plt.tick_params(labelsize=15)plt.xlabel("PC 1", fontsize = 20)plt.ylabel("PC 2", fontsize = 20)plt.show()
It’s cool to see how clusters are formed based on players’ positions!
I hope you find this tutorial useful and stay tuned for the next ones!