找回密码
 会员注册
查看: 25|回复: 0

Python大数据分析——Kmeans聚类分析

[复制链接]

5

主题

0

回帖

16

积分

新手上路

积分
16
发表于 2024-9-7 11:10:30 | 显示全部楼层 |阅读模式
Python大数据分析——Kmeans聚类分析介绍步骤数学分析目标函数K值选择拐点法轮廓系数法函数示例已知k值的情况——iris聚类未知k值的情况——NBA球员分类介绍对于有监督的数据挖掘算法而言,数据集中需要包含标签变量(即因变量y的值)。但在有些场景下,并没有给定的y值,对于这类数据的建模,一般称为无监督的数据挖掘算法,最为典型的当属聚类算法。Kmeans聚类算法利用距离远近的思想将目标数据聚为指定的k个簇,进而使样本呈现簇内差异小,簇间差异大的特征。步骤从数据中随机挑选k个样本点作为原始的簇中心计算剩余样本与簇中心的距离,并把各样本标记为离k个簇中心最近的类别重新计算各簇中样本点的均值,并以均值作为新的k个簇中心不断重复第二步和第三步,直到簇中心的变化趋于稳定,形成最终的k个簇数学分析目标函数在Kmeans聚类模型中,对于指定的k个簇,只有簇内样本越相似,聚类效果才越好。基于这个思想,可以理解为簇内样本的离差平方和之和达到最小即可。进而可以行生出Kmeans聚类的目标函数:其中,cj表示第j个簇的簇中心,xi属于第j个簇的样本i,nj表示第j个簇的样本总量。对于该目标函数而言,cj是未知的参数,要想求得目标函数的最小值,得先知道参数cj的值。我们对目标函数求偏导:令其导数为0:K值选择拐点法簇内离差平方和拐点法的思想很简单,就是在不同的k值下计算簇内离差平方和,然后通过可视化的方法找到“拐点”所对应的k值。当折线图中的斜率由大突然变小时,并且之后的斜率变化缓慢,则认为突然变化的点就是寻找的目标点,因为继续随着簇数k的增加,聚类效果不再有大的变化。也就是在变换最大的处,就是我们要找的类别数,也就是K值:自定义函数:defk_SSE(X,clusters): #选择连续的K种不同的值 K=range(1,clusters+1) #构建空列表用于存储总的簇内离差平方和 TSSE=[] forkinK: #用于存储各个簇内离差平方和 SSE=[] kmeans=KMeans(n_clusters=k) kmeans.fit(X) #返回簇标签 labels=kmeans.labels_ #返回簇中心 centers=kmeans.cluster_centers_ #计算各簇样本的离差平方和,并保存到列表中 forlabelinset(labels): SSE.append(np.sum((X.loc[labels==label,]-centers[label,:])**2)) #计算总的簇内离差平方和 TSSE.append(np.sum(SSE))12345678910111213141516171819轮廓系数法该方法综合考虑了簇的密集性与分散性两个信息,如果数据集被分割为理想的k个簇,那么对应的簇内样本会很密集,而族间样本会很分散。轮廓系数的计算公式可以表示为:其中,a(i)体现了簇内的密集性,代表样本i与同簇内其他样本点距离的平均值;b(i)反映了簇间的分敬性,它的计算过程是,样本i与其他非同簇样本点距离的平均值,然后从平均值中挑选出最小值。当S(i)接近于-1时,说明样本i分配的不合理,需要将其分配到其他簇中;当S(i)近似为0时,说明样本落在了模糊地带,即簇的边界处;当S(i)近似为1时,说明样本i的分配是合理的。所以我们希望的是ai,也就是类内越小越好;bi,也就是类间,越大越好。假设数据集被拆分为4个簇,样本i对应的a(i)值就是所有C1中其他样本点与样本i的距离平均值;样本i对应的b(i)值分两步计算,首先计算该点分别到C2、C3和C4中样本点的平均距离,然后将三个平均值中的最小值作为b(i)的度量。#构造自定义函数defk_silhouette(X,clusters): K=range(2,clusters+1) #构建空列表,用于存储不同簇数下的轮廓系数 S=[] forkinK: kmeans=KMeans(n_clusters=k) kmeans.fit(X) labels=kmeans.labels_ #调用子模块metrics中的silhouette_score函数,计算轮廓系数 S.append(metrics.silhouette_score(X,labels,metric='euclidean'))1234567891011当这个值最大,接近于1的时候,就是我们选择的K的值:函数KMeans(n_clusters=8,init=‘k-means++’,n_init=10,max_iter=300,tol=0.0001)n_clusters:用于指定聚类的簇数init:用于指定初始的簇中心设置方法,如果为’k-means++‘,则表示设置的初始簇中心之间相距较远;如果为’random’,则表示从数据集中随机挑选k个样本作为初始簇中心;如果为数组,则表示用户指定具体的簇中心n_init:用于指定Kmeans算法运行的次数,每次运行时都会选择不同的初始簇中心,目的是防止算法收敛于局部最优,默认为10max_iter:用于指定单次运行的迭代次数,默认为300tol:用于指定算法收敛的阈值,默认为0.0001示例已知k值的情况——iris聚类首先我们通过已知k值的情况下,通过有y标签的,画出的图像;对比我们聚类得到的图像,验证我们的方法是否良好。导入包读取数据集#导入第三方包importpandasaspdimportmatplotlib.pyplotaspltfromsklearn.clusterimportKMeans#读取iris数据集iris=pd.read_csv(r'D:\pythonProject\data\iris.csv')#查看数据集的前几行iris.head()123456789输出:构建Kmeans模型,对其标签结果进行分析#提取出用于建模的数据集XX=iris.drop(labels='Species',axis=1)#构建Kmeans模型kmeans=KMeans(n_clusters=3)kmeans.fit(X)#聚类结果标签X['cluster']=kmeans.labels_#各类频数统计X.cluster.value_counts()123456789输出:首先来看我们Kmeans模型,聚类得到的分布#导入第三方模块importseabornassns#三个簇的簇中心centers=kmeans.cluster_centers_#绘制聚类效果的散点图sns.lmplot(x='Petal_Length',y='Petal_Width',hue='cluster',markers=['^','s','o'],data=X,fit_reg=False,scatter_kws={'alpha':0.8},legend_out=False)plt.scatter(centers[:,2],centers[:,3],marker='*',color='black',s=130)plt.xlabel('Petal_Length')plt.ylabel('Petal_Width')#图形显示plt.show()12345678910111213再来看我们原始分布是什么样子#增加一个辅助列,将不同的花种映射到0,1,2三种值,目的方便后面图形的对比iris['Species_map']=iris.Species.map({'virginica':0,'setosa':1,'versicolor':2})#绘制原始数据三个类别的散点图sns.lmplot(x='Petal_Length',y='Petal_Width',hue='Species_map',data=iris,markers=['^','s','o'],fit_reg=False,scatter_kws={'alpha':0.8},legend_out=False)plt.xlabel('Petal_Length_old')plt.ylabel('Petal_Width_old')#图形显示plt.show()123456789我们通过对比发现基本上是差不多的,这说明我们的Kmeans模型十分有效,一般情况下我们是不知道K值的,也没用y标签,下面我们讲正常情况下的聚类例子。未知k值的情况——NBA球员分类导入功能包,读取数据#导入第三方包importpandasaspdimportnumpyasnpimportseabornassnsimportmatplotlib.pyplotaspltfromsklearn.clusterimportKMeansfromsklearnimportmetrics#轮廓系数包#读取球员数据players=pd.read_csv(r'D:\pythonProject\data\players.csv')players.head()1234567891011查看数据分布#绘制得分与命中率的散点图sns.lmplot(x='得分',y='命中率',data=players,fit_reg=False,scatter_kws={'alpha':0.8,'color':'steelblue'})plt.rcParams['font.family']=['SimHei']#matplotlib显示中文字plt.show()12345构造拐点法函数#构造自定义函数,用于绘制不同k值和对应总的簇内离差平方和的折线图defk_SSE(X,clusters):#选择连续的K种不同的值K=range(1,clusters+1)#构建空列表用于存储总的簇内离差平方和TSSE=[]forkinK:#用于存储各个簇内离差平方和SSE=[]kmeans=KMeans(n_clusters=k)kmeans.fit(X)#返回簇标签labels=kmeans.labels_#返回簇中心centers=kmeans.cluster_centers_#计算各簇样本的离差平方和,并保存到列表中forlabelinset(labels):SSE.append(np.sum((X.loc[labels==label,]-centers[label,:])**2))#计算总的簇内离差平方和TSSE.append(np.sum(SSE))#中文和负号的正常显示plt.rcParams['font.sans-serif']=['MicrosoftYaHei']plt.rcParams['axes.unicode_minus']=False#设置绘图风格plt.style.use('ggplot')#绘制K的个数与GSSE的关系plt.plot(K,TSSE,'b*-')plt.xlabel('簇的个数')plt.ylabel('簇内离差平方和之和')#显示图形plt.show()1234567891011121314151617181920212223242526272829303132构造轮廓系数法#构造自定义函数,用于绘制不同k值和对应轮廓系数的折线图defk_silhouette(X,clusters):K=range(2,clusters+1)#构建空列表,用于存储个中簇数下的轮廓系数S=[]forkinK:kmeans=KMeans(n_clusters=k)kmeans.fit(X)labels=kmeans.labels_#调用字模块metrics中的silhouette_score函数,计算轮廓系数S.append(metrics.silhouette_score(X,labels,metric='euclidean'))#中文和负号的正常显示plt.rcParams['font.sans-serif']=['MicrosoftYaHei']plt.rcParams['axes.unicode_minus']=False#设置绘图风格plt.style.use('ggplot')#绘制K的个数与轮廓系数的关系plt.plot(K,S,'b*-')plt.xlabel('簇的个数')plt.ylabel('轮廓系数')#显示图形plt.show()1234567891011121314151617181920212223对数据进行标准化处理,然后寻找K值对数据进行标准化后,首先来看拐点法:fromsklearnimportpreprocessing#数据标准化处理X=preprocessing.minmax_scale(players[['得分','罚球命中率','命中率','三分命中率']])#将数组转换为数据框X=pd.DataFrame(X,columns=['得分','罚球命中率','命中率','三分命中率'])#使用拐点法选择最佳的K值k_SSE(X,15)1234567我们发现3之后变换就没那么大了,那么3可能就是我们要选的值。我们再看轮廓系数法:#使用轮廓系数选择最佳的K值k_silhouette(X,10)12但因为其数值特别小,我们人为是不可靠的,一般只有轮廓系数比较接近于1时,才是比较靠谱的通过得到的K值进行聚类分析#将球员数据集聚为3类kmeans=KMeans(n_clusters=3)kmeans.fit(X)#将聚类结果标签插入到数据集players中players['cluster']=kmeans.labels_#构建空列表,用于存储三个簇的簇中心centers=[]foriinplayers.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()123456789101112131415161718192021注意:在Pandas的早期版本中,ix是一个方便的索引器,允许用户通过标签和整数位置来索引DataFrame的行和列。然而,随着Pandas版本的更新,为了简化API和提高代码的可读性,ix索引器在Pandas0.20.0版本中被弃用,并在后续版本中完全移除。因此,如果你尝试在较新版本的Pandas中使用ix,你将会遇到一个AttributeError。所以我们要改为.loc或者.iloc
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 22:08 , Processed in 0.436387 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表