失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 基于K-Means聚类算法对NBA球员数据的聚类分析

基于K-Means聚类算法对NBA球员数据的聚类分析

时间:2021-11-15 12:18:53

相关推荐

基于K-Means聚类算法对NBA球员数据的聚类分析

聚类分析的研究成果主要集中在基于距离(或者称为基于相似度)的聚类方法,用距离来作为相似性度量的优点是十分直观,从我们对物体的识别角度来分析,同类的数据样本是相互靠近的,不同类样本应该相聚较远。K-Means聚类算法是划分聚类方法中最常用、最流行的经典算法,许多其他的算法都是K-Means聚类算法的变种。其主要思想是通过迭代过程将数据集划分为不同类别,使评价聚类性能的准则函数达到最优,使生成的每个聚类类内紧凑,类间独立。

本文介绍并实践了一种无监督的聚类算法——K-Means聚类,结合“簇内离差平方和拐点法”、“轮廓系数法”两种方法进行K值的选取。从虎扑上获取球员数据之后,使用K-Means算法对NBA球员数据集进行聚类,我们通过观察聚类的结果,把球员分成三种类别,可以对比球员的价值,在实际应用中可以作为参考,帮助球队进行人才的挑选。

1.数据获取

使用pandas中的read_html函数读取虎扑体育网页中的球员数据表,代码如下

import pandas as pdimport numpy as n# 读取网页中的数据表table = []for i in range(1,7):table.append(pd.read_html('/stats/players/pts/%d' %i)[0])# 所有数据纵向合并为数据框players = pd.concat(table)# 变量重命名columns=['排名','球员','球队','得分','命中-出手','命中率','命中-三分','三分命中率','命中-罚球','罚球命中率','场次','上场时间']players.columns=columnsplayers.drop(0,inplace=True)print(players)players.to_csv(r"C:\Users\Administrator\Desktop\小论文代码\players.csv",encoding='utf_8_sig')

将结果写入本地文件players.csv,如下图所示

原始数据中命中率的格式为x%,需要进行标准化处理转化为数值形式,小数点后保留3位小数。

2.模型构建

模型的构建主要包括两部分:

(1)根据所获数据集,对球员进行聚类分群;

(2)结合分类结果对球员状态进行分析,分析球员价值。

2.1球员聚类
最佳k值的确定

本文使用了两种常用的评估方法,用于确定最佳k值:“簇内离差平方和拐点法”、“轮廓系数法”。

①拐点法:在不同的k值下计算簇内的离差平方和,然后通过可视化的方法找到“拐点”所对应的k值。

通过离差平方和的折线图我们能发现k值最好取在3、4、5之间,但还是很难通过观察找到最佳的k值。于是我们采用第二种方法(轮廓系数法)来进行k值的确定。

②轮廓系数法:该方法综合考虑了簇的密集性与分散性两个信息,如果数据集被分割为理想的k个簇,那么对应的簇内样本会很密集,而簇间样本会很分散,轮廓系数的计算公式如下:

其中,a(i)体现了簇内的密集性,代表样本i与同簇内其他样本点距离的平均值;b(i)反映了簇间的分散性,其计算过程是:样本i与其他非同簇样本点距离的平均值,然后从平均值中挑选出最小值。

有关轮廓系数的计算,我们可以直接调用sklearn子模块metris中的函数silhouette_score。该函数接受的聚类簇数必须大于或等于2,下面基于该函数重新自定义一个函数,用于绘制不同k值下对应轮廓系数的折线图,具体代码如下所示:

观察不同k值轮廓系数折线图,我们能发现k=3时轮廓系数最大,总体随k值增大而递减,但是最大也只有0.36左右,并不能达到约等于1的理想值,所以我们综合轮廓系数法和拐点法,在之前的结论3、4、5中选出最合适的k值:3。

聚类分析

在上面的结论下,我们把该数据聚集为三类:

从最终的结论图中我们不难发现,第一类红色部分表示球员的得分相对较低且命中率也较低,我们可以总结为得分能力不强的球员,总样本中占136人。第二类蓝色正方形表示的球员得分高、命中率高,我们总结其为职业生涯巅峰球员,各个球队的得分机器,样本中有68人。第三类用紫色圆点表示的球员得分低但命中率很高,我们可以归类为上场及进攻次数较少的球员,占33人。

最后附上聚类分析的代码:

# 读取球员数据import pandas as pdimport matplotlib.pyplot as pltimport numpy as npplayers = pd.read_csv(r'players.csv',encoding='gbk')players.head()# 中文和负号的正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.rcParams['axes.unicode_minus'] = False#绘制得分与命中率的散点图import seaborn as snssns.lmplot(x = '得分',y = '命中率',data = players,fit_reg = False, scatter_kws = {'alpha':0.8,'color':'steelblue'})plt.show()# 构造自定义函数,用于绘制不同k值和对应总的簇内离差平方和的折线图def k_SSE(X, clusters):# 选择连续的K种不同的值K = range(1,clusters+1)# 构建空列表用于存储总的簇内离差平方和TSSE = []for k in K:# 用于存储各个簇内离差平方和SSE = []from sklearn.cluster import KMeanskmeans = KMeans(n_clusters=k)kmeans.fit(X)# 返回簇标签labels = kmeans.labels_# 返回簇中心centers = kmeans.cluster_centers_# 计算各簇样本的离差平方和,并保存到列表中for label in set(labels):SSE.append(np.sum((X.loc[labels == label,]-centers[label,:])**2))# 计算总的簇内离差平方和TSSE.append(np.sum(SSE))# 中文和负号的正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.rcParams['axes.unicode_minus'] = False# 设置绘图风格plt.style.use('ggplot')# 绘制K的个数与GSSE的关系plt.plot(K, TSSE, 'b*-')plt.xlabel('簇的个数')plt.ylabel('簇内离差平方和之和')# 显示图形plt.show()from sklearn import preprocessing# 数据标准化处理X = preprocessing.minmax_scale(players[['得分','罚球命中率','命中率','三分命中率']])# 将数组转换为数据框X = pd.DataFrame(X, columns=['得分','罚球命中率','命中率','三分命中率'])k_SSE(X, 15)# 构造自定义函数,用于绘制不同k值和对应轮廓系数的折线图def k_silhouette(X, clusters):K = range(2,clusters+1)# 构建空列表,用于存储个中簇数下的轮廓系数S = []for k in K:from sklearn.cluster import KMeanskmeans = KMeans(n_clusters=k)kmeans.fit(X)labels = kmeans.labels_# 调用字模块metrics中的silhouette_score函数,计算轮廓系数from sklearn.metrics import silhouette_scoreS.append(silhouette_score(X, labels, metric='euclidean'))# 中文和负号的正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.rcParams['axes.unicode_minus'] = False# 设置绘图风格plt.style.use('ggplot')# 绘制K的个数与轮廓系数的关系plt.plot(K, S, 'b*-')plt.xlabel('簇的个数')plt.ylabel('轮廓系数')# 显示图形plt.show()k_silhouette(X, 10)# 将球员数据集聚为3类from sklearn.cluster import KMeanskmeans = KMeans(n_clusters = 3)kmeans.fit(X)# 将聚类结果标签插入到数据集players中players['cluster'] = kmeans.labels_# 构建空列表,用于存储三个簇的簇中心centers = []for i in players.cluster.unique():centers.append(players.loc[players.cluster == i,['得分','罚球命中率','命中率','三分命中率']].mean())# 将列表转换为数组,便于后面的索引取数centers = np.array(centers)# 绘制散点图sns.lmplot(x = '得分', y = '命中率', hue = 'cluster', data = players, markers = ['^','s','o'],fit_reg = False, scatter_kws = {'alpha':0.8}, legend = False)# 添加簇中心plt.scatter(centers[:,0], centers[:,2], c='k', marker = '*', s = 180)plt.xlabel('得分')plt.ylabel('命中率')# 图形显示plt.show()res0Series = pd.Series(kmeans.labels_)res0 = res0Series[res0Series.values == 0]print(players.iloc[res0.index])res0Series = pd.Series(kmeans.labels_)res0 = res0Series[res0Series.values == 1]print(players.iloc[res0.index])res0Series = pd.Series(kmeans.labels_)res0 = res0Series[res0Series.values == 2]print(players.iloc[res0.index])

参考文献

/liuzuoping/article/details/103167684

/JAVA_wangyi/article/details/106032641

如果觉得《基于K-Means聚类算法对NBA球员数据的聚类分析》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。