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


前言

 聚类分析的研究成果主要集中在基于距离(或者称为基于相似度)的聚类方法,用距离来作为相似性度量的优点是十分直观,从我们对物体的识别角度来分析,同类的数据样本是相互靠近的,不同类样本应该相聚较远。K-Means聚类算法是划分聚类方法中最常用、最流行的经典算法,许多其他的算法都是K-Means聚类算法的变种。其主要思想是通过迭代过程将数据集划分为不同类别,使评价聚类性能的准则函数达到最优,使生成的每个聚类类内紧凑,类间独立。
  本文介绍并实践了一种无监督的聚类算法——K-Means聚类,结合“簇内离差平方和拐点法”、“轮廓系数法”两种方法进行K值的选取。从虎扑上获取球员数据之后,使用K-Means算法对NBA球员数据集进行聚类,我们通过观察聚类的结果,把球员分成三种类别,可以对比球员的价值,在实际应用中可以作为参考,帮助球队进行人才的挑选。


1.数据获取

使用pandas中的read_html函数读取虎扑体育网页中的球员数据表
在这里插入图片描述
代码如下

import pandas as pd
# 读取网页中的数据表
table = []
for i in range(1,7):
    table.append(pd.read_html('https://nba.hupu.com/stats/players/pts/%d' %i)[0])

# 所有数据纵向合并为数据框
players = pd.concat(table)
# 变量重命名
columns=['排名','球员','球队','得分','命中-出手','命中率','命中-三分','三分命中率','命中-罚球','罚球命中率','场次','上场时间']
players.columns=columns
players.drop(0,inplace=True)
print(players)
players.to_csv(r"C:\Users\Administrator\Desktop\players.csv",encoding='utf_8_sig')

将结果写入本地文件players.csv,如下图所示
在这里插入图片描述
**原始数据中命中率的格式为x%

二、使用步骤

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 pd
import matplotlib.pyplot as plt
import numpy as np
players = 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 sns
sns.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 KMeans
        kmeans = 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 KMeans
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        labels = kmeans.labels_
        # 调用字模块metrics中的silhouette_score函数,计算轮廓系数
        from sklearn.metrics import silhouette_score
        S.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 KMeans
kmeans = 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])

总结

源码和数据下载地址:https://download.csdn.net/download/qq_44421796/18811876

  • 2
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我要变胖哇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值