这一节将使用k-平均聚类方法根据篮球运动员的行为数据对运动员进行聚类,这样的聚类结果在与球队有关的各项工作中都具有参考价值。例如,可根据聚类结果判断球员风格,从而更好地进行上场球员的调配;引进新球员时可根据聚类结果挑选更适合球队的球员,弥补球队短板,避免球员同质化;球员还可参考聚类结果进行有针对性的训练等。本案例所用数据是2013-2014赛季NBA控球后卫的赛场行为数据,并已经过适当地处理(去除噪声和无效数据),数据可从教材资源平台下载。
首先导入需要使用的Python库。其中pandas提供了高效易用的数据分析工具,numpy是适用于科学计算的库,两者经常配合使用。matplotlib是Python中常用的绘图系统,用来做数据可视化非常方便。
In[1]:import pandas as pd
In[2]:import matplotlib.pyplot as plt
In[3]:import numpy as np
读入所需的数据,显示数据的前5行,可以看到数据包含33个数据项,其中包括球员姓名、在球队中所打的位置、年龄、赛季等。具体地,pos代表球员在球场上所打的位置,g代表本赛季参赛场数,pts代表总得分,ast代表助攻次数,tov代表失误次数,ppg=pts/g代表平均得分(Points Per Game),atr=ast/tov表示助攻失误比(Assist Turnover Ratio)。为了简单起见,在此案例中只使用其中的数据项ppg和atr进行聚类,感兴趣的同学可以探索使用更多的数据项进行分析。
In[4]:nba=pd.read_csv('nba_2013.csv')
In[5]:nba.head()
Out[5]:
player pos age ...season_end ppg atr
0 D.J.Augustin PG 26 ...2013 13.098592 2.504000
1 Leandro Barbosa PG 31 ...2013 7.500000 1.684211
2 Jose Barea PG 29 ...2013 8.354430 2.424000
3 Jerryd Bayless PG 25 ...2013 9.250000 2.365854
4 Steve Blake PG 33 ...2013 6.872727 3.009804
[5 rows x 33 columns]
使用matplotlib可以画出相应数据的散点图(图5-5)。
图5-5
第一步,设置聚类的个数为5,并且随机选取5个点作为初始种子,初始的种子在图中用红色标出(图5-6)。
In[6]:cluster_num=5
In[7]:random_initial=np.random.choice(nba.index,size=clus
ter_num)
In[8]:centroids=nba.loc[random_initial]
图5-6
第二步,将每个元素分配给距离其最近的中心,生成5个簇。
第三步,重新计算每个簇的中心。因为这两个步骤是需要反复迭代的,为了代码的易用性,下面先以函数的形式定义好这两个步骤要实现的功能,然后在迭代过程中就可以通过反复调用这些函数来完成相应的工作了。
首先定义一个函数,以字典的形式存储中心,字典键值是每个簇的名称,字典的值是对应中心的坐标。
In[10]:def centroids_to_dict(centroids):
dictionary={}
counter=0
for index,row in centroids.iterrows():
coordinates=[row['ppg'],row['atr']
dictionary[counter]=coordinates
counter+=1
return dictionary
再定义用来计算点到中心欧式距离的函数。这里导入了用于数学计算的math库。
In[11]:import math
In[12]:def calculate_distance(centroid,player_value):
root_distance=0
for x in range(0,len(centroid)):
difference=centroid[x]-player_value[x]
squared_difference=difference**2
root_distance+=squared_difference
euclid_distance=math.sqrt(root_distance)
return euclid_distance
定义函数用来计算每个点到中心的距离,并把它分配到距离最近的中心所在的那个簇。
In[13]:def assign_to_cluster(row):
player=[row['ppg'],row['atr']]
lowest_dist=-1
clus_id=-1
for clu_id,centroid in centroids_dict.items():
distance=calculate_distance(centroid,player)
if lowest_dist==-1:
lowest_dist=distance
clus_id=clu_id
elif distance0:
centroids_dict=centroids_dict_new
nba['cluster']=nba.apply(assign_to_cluster,axis=1)
centroids_dict_new=recalculate_centroids(nba)
centr_change=centroids_change(centroids_dict,
centroids_dict_new)
In[27]:visualize_clusters(nba,cluster_num)
图5-7
上述过程完整地实现了k-平均聚类的算法。前面已经提到过这种聚类方法的结果与初始中心的选取有关,只进行一次这样的聚类,聚类结果会有一定的偏差。Python的sklearn库针对简单的k-平均聚类做了优化。例如,通过多次选取初始中心,参考多次聚类的结果输出最终的聚类结果,从而改善聚类效果。通过调用sklearn库来实现k-平均聚类只需要设置聚类的个数,数行代码就可以完成聚类工作。代码和相应的输出结果如图5-8所示。
In[1]:from sklearn.cluster import KMeans
In[2]:import pandas as pd
In[3]:import matplotlib.pyplot as plt
In[4]:def visualize_clusters(df,cluster_num):
colors=['b','g','r','c','m','y','k']
for i in range(cluster_num):
clustered_df=df[df['cluster']==i]
plt.scatter(clustered_df['ppg'],clustered_df
['atr'],c=colors[i])
plt.xlabel('Points Per Game',fontsize=12)
plt.ylabel('Assist Turnover Ratio',fontsize=12)
plt.show()
In[5]:cluster_num=5
In[6]:nba=pd.read_csv('nba_2013.csv')
In[7]:kmeans=KMeans(n_clusters=cluster_num)
In[8]:kmeans.fit(nba[['ppg','atr']])
Out[8]:
KMeans(algorithm='auto',copy_x=True,init='k-means++',max_iter
=300,n_clusters=5,n_init=10,n_jobs=1,precompute_distances='aut
o',random_state=None,tol=0.0001,verbose=0)
In[9]:nba['cluster']=kmeans.labels_
In[10]:visualize_clusters(nba,cluster_num)
图5-8