Kmeans聚类分析
该算法可以将数据划分为指定的k个簇,并且簇的中心点由各簇样本均值计算所得
该聚类算法的思路非常通俗易懂,就是不断地计算各样本点与簇中心之间的距离,直到收敛为止,其具体的步骤如下:
(1)从数据中随机挑选k个样本点作为原始的簇中心。
(2)计算剩余样本与簇中心的距离,并把各样本标记为离k个簇中心最近的类别。
(3)重新计算各簇中样本点的均值,并以均值作为新的k个簇中心。
(4)不断重复(2)和(3),直到簇中心的变化趋于稳定,形成最终的k个簇。
KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')n_clusters:用于指定聚类的簇数。init:用于指定初始的簇中心设置方法,如果为'k-means++',则表示设置的初始簇中心之间相距较远;如果为'random',则表示从数据集中随机挑选k个样本作为初始簇中心;如果为数组,则表示用户指定具体的簇中心。n_init:用于指定Kmeans算法运行的次数,每次运行时都会选择不同的初始簇中心,目的是防止算法收敛于局部最优,默认为10。max_iter:用于指定单次运行的迭代次数,默认为300。tol:用于指定算法收敛的阈值,默认为0.0001。precompute_distances:bool类型的参数,是否在算法运行之前计算样本之间的距离,默认为'auto',表示当样本量与变量个数的乘积大于1200万时不计算样本间距离。verbose:通过该参数设置算法返回日志信息的频度,默认为0,表示不输出日志信息;如果为1,就表示每隔一段时间返回一次日志信息。random_state:用于指定随机数生成器的种子。copy_x:bool类型参数,当参数precompute_distances为True时有效,如果该参数为True,就表示提前计算距离时不改变原始数据,否则会修改原始数据。n_jobs:用于指定算法运算时使用的CPU数量,默认为1,如果为-1,就表示使用所有可用的CPU。algorithm:用于指定Kmeans的实现算法,可以选择'auto' 'full'和'elkan',默认为'auto',表示自动根据数据特征选择运算的算法。
最佳k值的确定
拐点法
就是在不同的k值下计算簇内离差平方和,然后通过可视化的方法找到“拐点”所对应的k值。正如前文所介绍的Kmeans聚类算法的目标函数J,随着簇数量的增加,簇中的样本量会越来越少,进而导致目标函数J的值也会越来越小。通过可视化方法,重点关注的是斜率的变化,当斜率由大突然变小时,并且之后的斜率变化缓慢,则认为突然变化的点就是寻找的目标点,因为继续随着簇数k的增加,聚类效果不再有大的变化。
为了验证这个方法的直观性,这里随机生成三组二元正态分布数据,首先基于该数据绘制散点图
# 导入第三方包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics# 随机生成三组二元正态分布随机数
np.random.seed(1234)
mean1 = [0.5, 0.5]
cov1 = [[0.3, 0], [0, 0.3]]
x1, y1 = np.random.multivariate_normal(mean1, cov1, 1000).Tmean2 = [0, 8]
cov2 = [[1.5, 0], [0, 1]]
x2, y2 = np.random.multivariate_normal(mean2, cov2, 1000).Tmean3 = [8, 4]
cov3 = [[1.5, 0], [0, 1]]
x3, y3 = np.random.multivariate_normal(mean3, cov3, 1000).T# 绘制三组数据的散点图
plt.scatter(x1,y1)
plt.scatter(x2,y2)
plt.scatter(x3,y3)
# 显示图形
plt.show()
# 构造自定义函数,用于绘制不同k值和对应总的簇内离差平方和的折线图
def k_SSE(X, clusters):# 选择连续的K种不同的值K = range(1,clusters+1)# 构建空列表用于存储总的簇内离差平方和TSSE = []for k in K:# 用于存储各个簇内离差平方和SSE = []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()# 将三组数据集汇总到数据框中
X = pd.DataFrame(np.concatenate([np.array([x1,y1]),np.array([x2,y2]),np.array([x3,y3])], axis = 1).T)
# 自定义函数的调用
k_SSE(X, 15)
轮廓系数法
。有关轮廓系数的计算,可以直接调用sklearn子模块metrics中的函数,即
silhouette_score。需要注意的是,该函数接受的聚类簇数必须大于等于2。下面基于该函数重新自定义一个函数,用于绘制不同k值下对应轮廓系数的折线图
# 构造自定义函数,用于绘制不同k值和对应轮廓系数的折线图
def k_silhouette(X, clusters):K = range(2,clusters+1)# 构建空列表,用于存储个中簇数下的轮廓系数S = []for k in K: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'] = ['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, 15)
当k等于3时,轮廓系数最大,且比较接近于1,说明应该把虚拟数据聚为3类比较合理
间隔统计量法
# 自定义函数,计算簇内任意两样本之间的欧氏距离
def short_pair_wise_D(each_cluster):mu = each_cluster.mean(axis = 0)Dk = sum(sum((each_cluster - mu)**2)) * 2.0 * each_cluster.shape[0]return Dk# 计算簇内的Wk值
def compute_Wk(data, classfication_result):Wk = 0label_set = set(classfication_result)for label in label_set:each_cluster = data[classfication_result == label, :]Wk = Wk + short_pair_wise_D(each_cluster)/(2.0*each_cluster.shape[0])return Wk# 计算GAP统计量
def gap_statistic(X, B=10, K=range(1,11), N_init = 10):# 将输入数据集转换为数组X = np.array(X)# 生成B组参照数据shape = X.shapetops = X.max(axis=0)bots = X.min(axis=0)dists = np.matrix(np.diag(tops-bots))rands = np.random.random_sample(size=(B,shape[0],shape[1]))for i in range(B):rands[i,:,:] = rands[i,:,:]*dists+bots# 自定义0元素的数组,用于存储gaps、Wks和Wkbsgaps = np.zeros(len(K))Wks = np.zeros(len(K))Wkbs = np.zeros((len(K),B))# 循环不同的k值,for idxk, k in enumerate(K):k_means = KMeans(n_clusters=k)k_means.fit(X)classfication_result = k_means.labels_# 将所有簇内的Wk存储起来Wks[idxk] = compute_Wk(X,classfication_result)# 通过循环,计算每一个参照数据集下的各簇Wk值for i in range(B):Xb = rands[i,:,:]k_means.fit(Xb)classfication_result_b = k_means.labels_Wkbs[idxk,i] = compute_Wk(Xb,classfication_result_b)# 计算gaps、sd_ks、sk和gapDiffgaps = (np.log(Wkbs)).mean(axis = 1) - np.log(Wks) sd_ks = np.std(np.log(Wkbs), axis=1)sk = sd_ks*np.sqrt(1+1.0/B)# 用于判别最佳k的标准,当gapDiff首次为正时,对应的k即为目标值gapDiff = gaps[:-1] - gaps[1:] + sk[1:]# 中文和负号的正常显示plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.rcParams['axes.unicode_minus'] = False# 设置绘图风格plt.style.use('ggplot')# 绘制gapDiff的条形图plt.bar(np.arange(len(gapDiff))+1, gapDiff, color = 'steelblue')plt.xlabel('簇的个数')plt.ylabel('k的选择标准')plt.show()# 自定义函数的调用
gap_statistic(X)
x轴代表了不同的簇数k,y轴代表k值选择的判断指标gapDiff,gapDiff首次
出现正值时对应的k为3。所以,对于虚拟的数据集来说,将其划分为3个簇是比较合理的,同样与预设的簇数一致。代码中自定义了3个函数,分别用于计算公式中的Dk、Wk和Gapk,虽然计算逻辑比较简单,但是涉及的循环比较多,所以对大数据集而言,其k值的确定会比较慢。
Kmeans聚类的应用
在做Kmeans聚类时需要注意两点,一个是聚类前必须指定具体的簇数k值,如果k值是已知的,可以直接调用cluster子模块中的Kmeans类,对数据集进行分割;如果k值是未知的,可以根据行业经验或前面介绍的三种方法确定合理的k值;另一个是对原始数据集做必要的标准化处理,由于Kmeans的思想是基于点之间的距离实现“物以聚类”的,所以,如果原始数据集存在
量纲上的差异,就必须对其进行标准化的预处理,否则可以不用标准化。数据集的标准化处理可以借助于sklearn子模块preprocessing中的scale函数或minmax_scale实现
iris数据集的聚类
iris数据集经常被用于数据挖掘的项目案例中,它反映了3种鸢尾花在花萼长度、宽度和花瓣长度、宽度之间的差异,一共包含150个观测,且每个花种含有50个样本。下面将利用数据集中的四个数值型变量,对该数据集进行聚类,且假设已知需要聚为3类的情况下
# 读取iris数据集
iris = pd.read_csv(r'iris.csv')
# 查看数据集的前几行
iris.head()Sepal_Length Sepal_Width Petal_Length Petal_Width Species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
# 提取出用于建模的数据集X
X = iris.drop(labels = 'Species', axis = 1)
# 构建Kmeans模型
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
# 聚类结果标签
X['cluster'] = kmeans.labels_
# 各类频数统计
X.cluster.value_counts()0 62
1 50
2 38
Name: cluster, dtype: int64
如上结果所示,通过设定参数n_clusters为3就可以非常方便地得到三个簇,并且各簇样本量分别为62、50和38。为了直观验证聚类效果,不妨绘制花瓣长度与宽度的散点图,对比原始数据的三类和建模后的三类差异
# 导入第三方模块
import seaborn as sns# 三个簇的簇中心
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('花瓣长度')
plt.ylabel('花瓣宽度')
# 图形显示
plt.show()
# 增加一个辅助列,将不同的花种映射到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('花瓣长度')
plt.ylabel('花瓣宽度')
# 图形显示
plt.show()
,左图为聚类效果的散点图,其中五角星为每个簇的簇中心;右图为原始分
类的散点图。从图中可知,聚类算法将标记为1的所有花种聚为一簇,与原始数据吻合;对于标记为0和2的花种,聚类算法存在一些错误分割,但绝大多数样本的聚类效果还是与原始数据比较一致的。为了直观对比三个簇内样本之间的差异,使用雷达图对四个维度的信息进行展现,绘图所使用的数据为簇中心。雷达图的绘制需要导入pygal模块,需要读者提前在Python中安装该模型,绘图代码如下
# 导入第三方模块
import pygal
# 调用Radar这个类,并设置雷达图的填充,及数据范围
radar_chart = pygal.Radar(fill = True)
# 添加雷达图各顶点的名称
radar_chart.x_labels = ['花萼长度','花萼宽度','花瓣长度','花瓣宽度']# 绘制三个雷达图区域,代表三个簇中心的指标值
radar_chart.add('C1', centers[0])
radar_chart.add('C2', centers[1])
radar_chart.add('C3', centers[2])
# 保存图像
radar_chart.render_to_file('radar_chart.svg')
NBA球员数据集的聚类
NBA球员数据集却是未知分类个数的,对于这样的数据集就需要通过探索方法获知理想的簇数k值,然后进行聚类操作。该数据集来自于虎扑体育网,一共包含286名球员的历史投篮记录,这些记录包括球员姓名、所属球队、得分、各命中率等信息
# 读取球员数据
players = pd.read_csv(r'players.csv')
players.head()排名 球员 球队 得分 命中-出手 命中率 命中-三分 三分命中率 命中-罚球 罚球命中率 场次 上场时间
0 1 詹姆斯-哈登 火箭 31.9 9.60-21.10 0.454 4.20-10.70 0.397 8.50-9.90 0.861 30 36.1
1 2 扬尼斯-阿德托昆博 雄鹿 29.7 10.90-19.90 0.545 0.50-1.70 0.271 7.50-9.80 0.773 28 38.0
2 3 勒布朗-詹姆斯 骑士 28.2 10.80-18.80 0.572 2.10-5.10 0.411 4.50-5.80 0.775 32 37.3
3 4 斯蒂芬-库里 勇士 26.3 8.30-17.60 0.473 3.60-9.50 0.381 6.00-6.50 0.933 23 32.6
4 4 凯文-杜兰特 勇士 26.3 9.70-19.00 0.510 2.50-6.30 0.396 4.50-5.10 0.879 26 34.8
从数据集来看,得分、命中率、三分命中率、罚球命中率、场次和上场时间都为数值型变量,并且量纲也不一致,故需要对数据集做标准化处理。这里不妨挑选得分、命中率、三分命中率和罚球命中率4个维度用于球员聚类的依据。首先绘制球员得分与命中率之间的散点图,便于后文比对聚类后的效果
# 绘制得分与命中率的散点图
sns.lmplot(x = '得分', y = '命中率', data = players, fit_reg = False, scatter_kws = {'alpha':0.8, 'color': 'steelblue'})
plt.show()
通过肉眼,似乎无法直接对这286名球员进行分割。如果需要将这些球员
聚类的话,该划为几类比较合适呢?下面将利用前文介绍的三种选择k值的方法,对该数据集进行测试,代码如下:
from sklearn import preprocessing
# 数据标准化处理
X = preprocessing.minmax_scale(players[['得分','罚球命中率','命中率','三分命中率']])
# 将数组转换为数据框
X = pd.DataFrame(X, columns=['得分','罚球命中率','命中率','三分命中率'])
# 使用拐点法选择最佳的K值
k_SSE(X, 15)
随着簇数k的增加,簇内离差平方和的总和在不断减小,当k在4附近时,折线斜率的变动就不是很大了,故可选的k值可以是3、4或5。为了进一步确定合理的k值,再参考轮廓系数和间隙统计量的结果
# 使用轮廓系数选择最佳的K值
k_silhouette(X, 15)
# 使用间隙统计量选择最佳的K值
gap_statistic(X, B = 20, K=range(1, 16))
左图为轮廓系数图,右图为Gap Statistic图。对于左图而言,当k值为2时对
应的轮廓系数最大;在右图中,纵坐标首次为正时所对应的k值为3。故综合考虑上面的三种探索方法,将最佳的聚类个数k确定为3。接下来基于这个k值,对NBA球员数据集进行聚类,然后基于分组好的数据,重新绘制球员得分与命中率之间的散点图
# 将球员数据集聚为3类
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()
三类散点图看上去很有规律,其中五角星代表各个簇的中心点。对比正
方形和圆形的点,它们之间的差异主要体现在命中率上,正方形所代表的球员属于低得分低命中率型,命中率普遍在50%以下;圆形所代表的球员属于低得分高命中率型。再对比正方形和三角形的点,它们的差异体现在得分上,三角形所代表的球员属于高得分低命中率型,当然,从图中也能发现几个强悍的球员,即高得分高命中率(如图5-12中圈出的三个点)。需要注意的是,由于对原始数据做了标准化处理,因此图中的簇中心不能够直接使用
cluster_centers_方法获得,因为它返回的是原始数据标准化后的中心。故在代码中通过for循环重新找出了原始数据下的簇中心,并将其以五角星的标记添加到散点图中。最后看看三类球员的雷达图,比对四个指标上的差异。由于四个维度间存在量纲上的不一致,故需要使用标准化后的中心点绘制雷达图
# 雷达图
# 调用模型计算出来的簇中心
centers_std = kmeans.cluster_centers_
# 设置填充型雷达图
radar_chart = pygal.Radar(fill = True)
# 添加雷达图各顶点的名称
radar_chart.x_labels = ['得分','罚球命中率','命中率','三分命中率']# 绘制雷达图代表三个簇中心的指标值
radar_chart.add('C1', centers_std[0])
radar_chart.add('C2', centers_std[1])
radar_chart.add('C3', centers_std[2])
# 保存图像
radar_chart.render_to_file('radar_chart.svg')
Kmeans聚类分析相关推荐
- R语言KMeans聚类分析确定最优聚类簇数实战:间隙统计Gap Statistic(确定最优聚类簇数)
R语言KMeans聚类分析确定最优聚类簇数实战:间隙统计Gap Statistic(确定最优聚类簇数) 目录
- R语言KMeans聚类分析确定最优聚类簇数实战:NbClust包(确定最优聚类簇数)
R语言KMeans聚类分析确定最优聚类簇数实战:NbClust包(确定最优聚类簇数) 目录
- R语言KMeans聚类分析确定最优聚类簇数实战:期望最大化expectation-maximization准则(确定最优聚类簇数)
R语言KMeans聚类分析确定最优聚类簇数实战:期望最大化expectation-maximization准则(确定最优聚类簇数) 目录
- R语言KMeans聚类分析确定最优聚类簇数实战:Calinski-Harabasz准则(确定最优聚类簇数)
R语言KMeans聚类分析确定最优聚类簇数实战:Calinski-Harabasz准则(确定最优聚类簇数) 目录
- kmeans聚类分析结果怎么看_聚类分析终稿1(SPSSAU)
一.前言 在项目8中,我们学习了利用联合分析法萃取客户喜爱值,本次项目我们将学习利用SPSS实现聚类分析. 二.方法 1.聚类分析的描述 按照个体(记录)的特征将它们分类,使同一类别内的个体具有尽可能 ...
- 使用Kmeans聚类分析对复杂的数据进行分类
代码解释 使用简单的Kmeans方法对特征数与样本数较多的电离层雷达回波数据进行分类,并计算分类精度,检验效果. 其中,通过PCA方法对数据降维实现可视化. 本文代码通过MATLAB2020a编写. ...
- K-means聚类分析
k-means聚类分析 什么是聚类分析 k-means聚类分析(k-means clustering)源于信号处理中的一种向量量化方法,现在则更多地作为一种聚类分析方法流行于数据挖掘领域.来自维基百科 ...
- Iris鸢尾花数据集可视化、线性回归、决策树分析、KMeans聚类分析
在进行可视化及聚类分析前,我们需要为IDLE安装sklearn库,scikit-learn是Python的一个开源机器学习模块,它建立在NumPy,SciPy和matplotlib模块之上能够为用户提 ...
- Python使用K-means聚类分析
Python使用K-means聚类分析 文章目录 Python使用K-means聚类分析 介绍 1.集群标签作为特征 一.k-均值聚类 二.示例 - 加州住房 2.KMeans 总结 介绍 提示:这里 ...
- 机器学习之K-means聚类分析NBA球员案例
机器学习之K-means聚类分析NBA球员案例 本次案例利用k-means算法分析NBA球员球队实力,具体采用2种方式实现案例,一种为自己实现,一种为调用sklearn库,数据来源nba_2013.c ...
最新文章
- 学python爬虫需要什么基础-Python爬虫需要学习那些东西?
- oracle授权、表备份、用户管理
- MFC的框架程序分析3
- pyqt5生成py的文件为什么是c 语言,如何使用PyQt5在python中创建文件对话框
- 李航老师亲自推荐的《统计学习方法》课件下载
- pip install安装php,Python下的常用下载安装工具pip的安装方法
- 吴恩达深度学习CNN作业:Convolutional Neural Networks: Step by Step
- 统计图源代码_openlayers4 入门开发系列结合 echarts4 实现统计图(附源码下载)
- 浙江省智慧城市建设改变百姓生活
- nlu 意图识别_在NLU中,您无视危险的意图
- 在win10 python3用pyhive连接hive
- 将yolov4的权重文件转换为wts文件
- 安装AAE v11.x Control Room简易教程
- 【转载】如何学习统计学,或我的学习之路——初学者写给初学者
- 最新无限制188旅游系统V7.0升级补丁 全社通V2.0补丁 Tourex 5.0源码下载
- iOS中 Realm的学习与使用 韩俊强的博客
- 微信电脑版收到的表格文件保存到桌面打开后不显示内容
- 基于Java对Flash网站的抓取
- 萌新浅谈DHCP以及ospf
- 2019高考江苏卷语文作文
热门文章
- lstm需要优化的参数_通过Keras 构建基于 LSTM 模型的故事生成器
- 不懂就要问!流量卡拒收对个人会有影响吗?
- 【Python学习记录】Numpy广播机制(broadcast)
- 假如给我三天光明阅读心得收获
- matlab三相触发电路图,三相过零触发电路图
- 介绍一款非常好用的截图软件-《Snipaste》
- 小标题 html,论文的小标题格式
- 模型量化从1bit到8bit,二值到三值
- oracle中alter index,oracle alter index rebuild online和alter index rebuild的區別
- 伸展树 自底向上 自顶向下