2022/3/24 10:27:05 阅读:1121 发布者:chichi77
一文搞定
聚类分析
1.0 什么是聚类分析?
聚类分析(Clustering),就是将数据所对应的研究对象进行分类的统计方法。
它是将若干个个体集合,按照某种标准分成若干个簇,并且希望簇内的样本尽可能地相似,而簇和簇之间要尽可能地不相似。
其作为一种对特征进行定量无监督学习分类的方法,当不知道数据中每个样本的真实类别时,但又想将数据分开时,可以考虑使用聚类算法。
1.1 常用的聚类算法有哪些呢?
一般来说,聚类算法可以分为:传统聚类算法和深度聚类算法。
传统聚类算法主要是根据原特征+基于划分/密度/层次等方法。
常用的传统聚类算法包括:
① K-means聚类(K-均值 聚类);
② K-medians聚类 (K-中位数 聚类);
③ 系统聚类(层次聚类);
④ 谱聚类;
⑤ 模糊聚类;
⑥ 密度聚类;
深度聚类方法则主要是根据表征学习后的特征+传统聚类算法。
1.2 K-means聚类
概述:
一种快速聚类方法,把样本空间中n个点划分到K个簇,需要的计算量较少,较容易理解。
思想:
假设数据有p个变量参与聚类,并且要聚类K个簇。则在p维空间中,
1)首先选取K个不同样本作为聚类种子,然后根据每个样本到达K个点的距离远近,将所有样本分为K个簇。
2)在每一簇中,重新计算出簇的中心(即每个特征的均值)作为新种子,再把样本分为K类。
3)如此下去,直到种子位置不再发生改变位置。
其目标函数为:
样本与其归属的簇类中心的距离为最小
选择距离度量:
两点之间距离的度量函数很多,常见的有欧几里得距离、曼哈顿距离。
① 欧几里得距离:图中红色
② 曼哈顿距离:图中蓝色
又称为:城市街区距离
核心:(肘方法确定最佳K值)
在K-means聚类中,如何寻找合适的K值对聚类结果很重要。常用方法为:
观察K个簇内的组内平方和与组间平方和的变化情况来确定合适的聚类数目K。
因此:
常需要绘制类内部的同质性或类间的差异性随K值变化的曲线(形状类似人的手肘),来确定出最佳的K值,而该K值点恰好处在手肘曲线的肘部点,因此这种确定最佳K值的办法称为肘方法。
衍生:变种算法
① 二分K-means 聚类
② K-medians (中值)聚类
③ K-medoids (中心点)聚类
这些方法在初始K个平均值的选择,相异度的计算和聚类平均值的策略上有所不同。
缺陷:
① 初始化中心点随机化
Kmeans是采用随机初始化中心点,而不同初始化的中心点对于算法结果的影响比较大。
所以,针对这点更新出了Kmeans++算法:
其初始化的思路是:各个簇类中心应该互相离得越远越好。基于各点到已有中心点的距离分量,依次随机选取到k个元素作为中心点。离已确定的簇中心点的距离越远,越有可能(可能性正比与距离的平方)被选择作为另一个簇的中心点。
② 欧式距离下数据具有一样的的先验概率并呈现球形分布
基于欧式距离的 Kmeans 假设了了各个数据簇的数据具有一样的的先验概率并呈现球形分布,但这种分布在实际生活中并不常见。面对非凸的数据分布形状时我们可以引入核函数来优化,这时算法又称为核 Kmeans 算法,是核聚类方法的一种。
核聚类方法的主要思想是:通过一个非线性映射,将输入空间中的数据点映射到高位的特征空间中,并在新的特征空间中进行聚类。非线性映射增加了数据点线性可分的概率,从而在经典的聚类算法失效的情况下,通过引入核函数可以达到更为准确的聚类结果。
③ Kmeans要求特征为数值型变量
kmeans是面向数值型的特征,对于类别特征需要进行onehot或其他编码方法。
此外还有 K-Modes 、K-Prototypes 算法可以用于混合类型数据的聚类,对于数值特征簇类中心我们取的是各特征均值,而类别型特征中心取得是众数,计算距离采用海明距离,一致为0否则为1。
④ Kmeans要使用特征缩放确保同一量级
聚类是基于特征间距离计算,计算距离时,需要关注到特征量纲差异问题,量纲越大意味这个特征权重越大。
假设各样本有年龄、工资两个特征变量,如计算欧氏距离的时候,(年龄1-年龄2)² 的值要远小于(工资1-工资2)² ,这意味着在不使用特征缩放的情况下,距离会被工资变量(大的数值)主导。
因此,我们需要使用特征缩放来将全部的数值统一到一个量级上来解决此问题。通常的解决方法可以对数据进行“标准化”或“归一化”,对所有数值特征统一到标准的范围如0~1。
所谓标准化,即:Z-score Normalization;
所谓归一化,即:Max-Min Normalization;
⑤ Kmeans结果依赖特征选择
这是所有聚类算法的同一缺陷。聚类,本质上只是根据样本特征间的距离(样本分布)确定所属的簇类。而不同特征的情况,就会明显影响聚类的结果。
对于无监督聚类的特征选择:
一方面可以结合业务含义,选择贴近业务场景的特征。
另一方面,可以结合缺失率、相似度、PCA等常用的特征选择(降维)方法可以去除噪音、减少计算量以及避免维度爆炸。再者,如果任务有标签信息,结合特征对标签的特征重要性也是种方法(如xgboost的特征重要性,特征的IV值。)
最后,也可以通过神经网络的特征表示(也就深度聚类的思想。后面在做专题介绍),如可以使用word2vec,将高维的词向量空间以低维的分布式向量表示。
1.3 系统聚类(层次聚类)
系统聚类,又称层次聚类,英文为:Hierarchical cluster。
概述:
一种常见聚类方法,在不同层级上对样本进行聚类,逐步形成树状的结构。
思想:
根据层次分解是自底向上(合并)还是自顶向下(分裂)可将其分为两种模式。
① 凝聚:采用自底向上的策略,即开始令每一个对象形成自己的簇,然后根据指定的距离度量方式,首先找到两个最接近的簇,开始合并并且迭代会把簇合并成越来越大的簇(每次合并最相似的两个簇),直到所有对象都在一个簇中,或者满足某个终止条件。
② 分裂:采用自顶向下的策略,即开始所有的对象都是一个簇,然后将簇划分为多个较小的簇(在每次划分时,将一个簇划分为差异最大的两个簇),并且迭代划分为更小的簇,直到最底层的簇都足够凝聚或仅包含一个对象,或者簇内对象彼此足够相似。
1.4 谱聚类
概述:
从图论中演化而来,由于优秀性能被广泛应用于聚类。
思想:
第一步为构图:将采样点数据构造成一张网图;
第二步为切图:按照一定的切边准则,将第一步的构图切分成不同子图。子图即为对应的聚类结果。
优点:
谱聚类是对图进行切割,因此不存在K-均值聚类中将离散小簇聚合到一起的情况。
1.5 模糊聚类
概述:
类比于K-均值聚类,但并非是非此即彼的硬划分方法。
思想:
计算每个样本属于各个类别的隶属度。
常用:
模糊C均值聚类(FCM)
1.6 密度聚类
概述:
基于密度的聚类,常假设聚类结果可以根据样本分布的稠密程度来确定,主要目标是寻找被低密度区域(噪声)分离的高密度区域。
优势:
基于距离的聚类结果常为球状簇,而基于密度的聚类结果可以是任意形状的,对带有噪声数据的处理比较好。
典型:DBSCAN
DBSCAN(Density-Based Spatial Clustering of Application with Noise)是一种典型的基于密度的聚类算法。
1)一般假定可以通过样本分布的紧密程度来决定。同一类别的样本,它们之间是紧密相连的。即,在该类别任意样本周围不远处一定还有同类别的样本存在。
2)通过将紧密相连的样本划为一类,就得到了一个聚类类别。
3)将所有各组紧密相连的样本划为各个不同的类别,这就得到了最终的所有聚类类别结果。
4)那些没有划分为某一簇的数据点,则可看作是噪声数据。
1.7 高斯混合模型聚类
概述:
K-means模型的一个优化模型,是一种生成式的模型。
思想:
试图找到多维高斯模型概率分布的混合表示,从而拟合出任意形状的数据分布。
1.8 亲和力传播聚类
思想:
将全部数据点作为潜在的聚类中心,然后数据点两两间连线构成一个网络(或称为:相似度矩阵),再通过网络中各条边的信息传递,找到每个样本的聚类中心。
1.9 BIRCH聚类
概述:
BIRCH,即利用层次方法的平衡迭代规约和聚类,是一种利用树结构来帮助快速聚类的算法,比较适合较大数据集的聚类。
优势:
可以识别出数据集中数据分布的不均衡性,将分布在稠密区域中的点聚类和分布在稀疏区域中的点视作异常点移除。
2.0 聚类分析的Python实现
下面将介绍多种聚类算法在同一数据集上的Python实现。
# 导入需要的包
# !pip install pyclustering
# !pip install pyod
## 导入会使用到的相关库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
from sklearn.manifold import TSNE
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_wine
from sklearn.cluster import *
from sklearn.metrics.cluster import v_measure_score
from sklearn.metrics import *
from sklearn.mixture import GaussianMixture,BayesianGaussianMixture
from sklearn.neighbors import LocalOutlierFactor
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.svm import OneClassSVM
from pyclustering.cluster.kmedians import kmedians
from pyclustering.cluster.fcm import fcm
from pyclustering.cluster import cluster_visualizer
from scipy.cluster import hierarchy
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout
import pyod.models as pym
from pyod.models.cof import COF
from pyod.models.pca import PCA
from pyod.models.sod import SOD
from pyod.models.iforest import IForest
from pyod.models.xgbod import XGBOD
数据集:酒数据集,使用t-SNE降维到3维,方便聚类可视化展示。
## 对酒数据的TSNE降维后的结果进行聚类分析
## 对酒的特征数据进行标准化
wine_x,wine_y = load_wine(return_X_y=True)
wine_x = StandardScaler().fit_transform(wine_x)
print("每类样本数量:",np.unique(wine_y,return_counts = True))
wine_x
## TSNE进行数据的降维,降维到3维空间中
tsne = TSNE(n_components = 3,perplexity =25,
early_exaggeration =3,random_state=123)
## 获取降维后的数据
tsne_wine_x = tsne.fit_transform(wine_x)
print(tsne_wine_x.shape)
tsne_wine_x
注意:
聚类算法,只用到特征X。因此一般的输入都是arrary格式,并非dataframe格式。
可以使用:
x=df[['','']].values
来获得输入变量x。
2.1 K均值聚类和K中值聚类
2.1.1 K均值聚类
采用KMeans函数实现K均值聚类。
① 使用肘方法寻找合适的聚类数目K;
## 使用肘方法搜索合适的聚类数目
kmax = 10
K = np.arange(1,kmax)
iner = [] ## 类内误差平方和
for ii in K:
kmean = KMeans(n_clusters=ii,random_state=1)
kmean.fit(tsne_wine_x)
## 计算类内误差平方和
iner.append(kmean.inertia_)
## 可视化类内误差平方和的变化情况
plt.figure(figsize=(10,6))
plt.plot(K,iner,"r-o")
plt.xlabel("聚类数目")
plt.ylabel("类内误差平方和")
plt.title("K-means聚类")
## 在图中添加一个箭头
plt.annotate("转折点", xy=(3,iner[2]),xytext=(4,iner[2] + 2000),
arrowprops=dict(facecolor='blue', shrink=0.1))
plt.grid()
plt.show()
图 肘方法寻找合适的聚类数目K
结果解读:当簇的数量为3后,类内误差平方和变化非常平缓,说明K=3是较为理想的取值。
② V测度衡量分类效果;
由于该数据集知道每个样本的类别标签,可以使用V测度的取纸大小来分析聚类的效果。
该得分是聚类同质性和完整性的调和平均数。越接近于1说明聚类效果越好。
## 将数据聚类为3类并可视化相关结果
## 使用KMeans将数据聚类为3类
kmean = KMeans(n_clusters=3,random_state=1)
k_pre = kmean.fit_predict(tsne_wine_x)
print("每簇包含的样本数量:",np.unique(k_pre,return_counts = True))
print("每个簇的聚类中心为:\n",kmean.cluster_centers_)
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,k_pre))
## 该得分是聚类同质性和完整性的调和平均数,越接近于1,说明聚类的效果越好,
# 同质性(Homogeneity): 每个聚类(簇)里面只包含单个类的样本。
# 完备性(completeness): 一个给定类的所有样本都被分到了同一个聚类(簇)中。
结果解读:
每个簇分别包含55、56、57个样本;
聚类的V测度为0.7728;
接下来进行二维绘图展示:
x=tsne_wine_x
kmean = KMeans(n_clusters=3,random_state=1)
y=kmean.fit_predict(x)
# Kmeans绘图
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.figure(figsize=(10,10))
plt.scatter(x[:,0],x[:,1],c=y,s=20)
plt.title('三分类')
plt.show()
2.1.2 K-中值聚类
使用pyclustering库中的kmedians()函数实现K-中值聚类。
① 使用3个样本作为初始化聚类中心;
## 使用Kmedians将数据聚类为3类
initial_centers = tsne_wine_x[[1,51,100],:]
② 开始聚类;
np.random.seed(10)
kmed = kmedians(data=tsne_wine_x,initial_medians = initial_centers)
kmed.process() # 算法训练数据
kmed_pre = kmed.get_clusters() # 聚类结果
kmed_center = np.array(kmed.get_medians())
## 将聚类结果处理为类别标签
kmed_pre_label = np.arange(len(tsne_wine_x))
for ii,li in enumerate(kmed_pre):
kmed_pre_label[li] = ii
print("每簇包含的样本数量:",np.unique(kmed_pre_label,return_counts = True))
print("每个簇的聚类中心为:\n",kmed_center)
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,kmed_pre_label))
## 该得分是聚类同质性和完整性的调和平均数,越接近于1,说明聚类的效果越好
结果解读:
每个簇分别包含65, 62, 51个样本;
聚类的V测度为0.8609;
2.1.3 三维空间可视化展示聚类效果
## 在3D空间中可视化聚类后的数据空间分布
colors = ["red","blue","green"]
shapes = ["o","s","*"]
fig = plt.figure(figsize=(15,6))
## 将坐标系设置为3D,K均值聚类结果
ax1 = fig.add_subplot(121, projection="3d")
for ii,y in enumerate(k_pre):
ax1.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
## 可视化聚类中心
for ii in range(len(np.unique(k_pre))):
x = kmean.cluster_centers_[ii,0]
y = kmean.cluster_centers_[ii,1]
z = kmean.cluster_centers_[ii,2]
ax1.scatter(x,y,z,c = "gray",marker="o",s=150,edgecolor='k')
ax1.text(x,y,z,"簇"+str(ii+1))
ax1.set_xlabel("特征1",rotation=20)
ax1.set_ylabel("特征2",rotation=-20)
ax1.set_zlabel("特征3",rotation=90)
ax1.azim = 225
ax1.set_title("K-means聚为3簇")
## K中位数聚类结果
ax2 = fig.add_subplot(122, projection="3d")
for ii,y in enumerate(kmed_pre_label):
ax2.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
for ii in range(len(np.unique(kmed_pre_label))):
x = kmed_center[ii,0]
y = kmed_center[ii,1]
z = kmed_center[ii,2]
ax2.scatter(x,y,z,c = "gray",marker="o",s=150,edgecolor='k')
ax2.text(x,y,z,"簇"+str(ii+1))
ax2.set_xlabel("特征1",rotation=20)
ax2.set_ylabel("特征2",rotation=-20)
ax2.set_zlabel("特征3",rotation=90)
ax2.azim = 225
ax2.set_title("K-medians聚为3簇")
plt.tight_layout()
plt.show()
2.1.4 轮廓系数判别聚类效果
当每个类别属性已知时,可以使用V测度值来评价模型好坏。
该得分是聚类同质性和完整性的调和平均数,越接近于1,说明聚类的效果越好。
而当每个类别属性不全知道时,可以使用轮廓系数来评价模型好坏。
常用函数如下:
① 计算整个数据集的轮廓得分:
sklearn.metrics模块下的silhouette_score()函数
② 计算每个样本的轮廓得分:
sklearn.metrics模块下的silhouette_samples()函数
③ 可视化轮廓图:
1)K-均值聚类的轮廓得分:
## 使用轮廓系数评价聚类效果的好坏
## 计算整体的平均轮廓系数,K均值
sil_score = silhouette_score(tsne_wine_x,k_pre)
## 计算每个样本的silhouette值,K均值
sil_samp_val = silhouette_samples(tsne_wine_x,k_pre)
## 可视化聚类分析轮廓图,K均值
plt.figure(figsize=(10,6))
y_lower = 10
n_clu = len(np.unique(k_pre))
for ii in np.arange(n_clu): ## 聚类为了3类
## 将第ii类样本的silhouette值放在一块排序
iiclu_sil_samp_sort = np.sort(sil_samp_val[k_pre == ii])
## 计算第ii类的数量
iisize = len(iiclu_sil_samp_sort)
y_upper = y_lower + iisize
## 设置ii类图像的颜色
color = plt.cm.Spectral(ii / n_clu)
plt.fill_betweenx(np.arange(y_lower,y_upper),0,iiclu_sil_samp_sort,
facecolor = color,alpha = 0.7)
# 簇对应的y轴中间添加标签
plt.text(-0.08,y_lower + 0.5*iisize,"簇"+str(ii+1))
## 更新 y_lower
y_lower = y_upper + 5
## 添加平均轮廓系数得分直线
plt.axvline(x=sil_score,color="red",label = "mean:"+str(np.round(sil_score,3)))
plt.xlim([-0.1,1])
plt.yticks([])
plt.legend(loc = 1)
plt.xlabel("轮廓系数得分")
plt.ylabel("聚类标签")
plt.title("K-means聚类轮廓图")
plt.show()
2)K-中值聚类的轮廓得分:
## 使用轮廓系数评价聚类效果的好坏
## 计算整体的平均轮廓系数,K中位数
sil_score = silhouette_score(tsne_wine_x,kmed_pre_label)
## 计算每个样本的silhouette值,K中位数
sil_samp_val = silhouette_samples(tsne_wine_x,kmed_pre_label)
## 可视化聚类分析轮廓图,K中位数
plt.figure(figsize=(10,6))
y_lower = 10
n_clu = len(np.unique(kmed_pre_label))
for ii in np.arange(n_clu): ## 聚类为了3类
## 将第ii类样本的silhouette值放在一块排序
iiclu_sil_samp_sort = np.sort(sil_samp_val[kmed_pre_label == ii])
## 计算第ii类的数量
iisize = len(iiclu_sil_samp_sort)
y_upper = y_lower + iisize
## 设置ii类图像的颜色
color = plt.cm.Spectral(ii / n_clu)
plt.fill_betweenx(np.arange(y_lower,y_upper),0,iiclu_sil_samp_sort,
facecolor = color,alpha = 0.7)
# 簇对应的y轴中间添加标签
plt.text(-0.08,y_lower + 0.5*iisize,"簇"+str(ii+1))
## 更新 y_lower
y_lower = y_upper + 5
## 添加平均轮廓系数得分直线
plt.axvline(x=sil_score,color="red",label = "mean:"+str(np.round(sil_score,3)))
plt.xlim([-0.1,1])
plt.yticks([])
plt.legend(loc = 1)
plt.xlabel("轮廓系数得分")
plt.ylabel("聚类标签")
plt.title("K-medians聚类轮廓图")
plt.show()
结果解读:在簇2中有一部分样本的轮廓值<0,说明有些不属于该簇的样本被归到了这个簇。
2.2 层次聚类
2.2.1 常用函数:
① 计算层次聚类:
scipy.cluster模块下的hierarchy
② 计算聚类结果:
hierachy.linkage()函数
参数设置:
metric="euclidean" 欧几里得距离
method="ward" 类间方差度量
③ 可视化聚类树:
hierachy.dendrogram()函数
## 层次聚类
## 对数据进行系统聚类并绘制树
Z = hierarchy.linkage(tsne_wine_x, method="ward", metric="euclidean")
fig = plt.figure(figsize=(12,6))
Irisdn = hierarchy.dendrogram(Z,truncate_mode = "lastp")
plt.axhline(y = 40,color="k",linestyle="solid",label="three class")
plt.axhline(y = 80,color="g",linestyle="dashdot",label="two class")
plt.title("层次聚类树")
plt.xlabel("Sample number")
plt.ylabel("距离")
plt.legend(loc = 1)
plt.show()
图 层次聚类树
结果解读:
使用不同阈值可以获得不同聚类结果:分成3类使用黑色实线;分成2类:使用绿色虚线
2.2.2 V测度值计算
计算不同数量簇下的V测度值
函数:hierarchy.fcluster()获得类别标签
## 计算系统聚类后每个簇的信息
## 最多聚类为两类
hie2 = hierarchy.fcluster(Z,t = 2, criterion="maxclust")
print("聚为2个簇,每簇包含的样本数量:\n",np.unique(hie2,return_counts = True))
print("聚为2个簇,聚类效果V测度: %.4f"%v_measure_score(wine_y,hie2))
## 最多聚类为三类
hie3 = hierarchy.fcluster(Z,t = 3, criterion="maxclust")
print("聚为3个簇,每簇包含的样本数量:\n",np.unique(hie3,return_counts = True))
print("聚为3个簇,聚类效果V测度: %.4f"%v_measure_score(wine_y,hie3))
2.2.3 三维可视化层次聚类效果
## 将聚类为两类和3类的结果在空间中可视化出来
colors = ["red","blue","green"]
shapes = ["o","s","*"]
fig = plt.figure(figsize=(15,6))
## 将坐标系设置为3D,层次聚类结果
ax1 = fig.add_subplot(121, projection="3d")
for ii,y in enumerate(hie2-1):
ax1.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
ax1.set_xlabel("特征1",rotation=20)
ax1.set_ylabel("特征2",rotation=-20)
ax1.set_zlabel("特征3",rotation=90)
ax1.azim = 225
ax1.set_title("层次聚类为2簇")
ax2 = fig.add_subplot(122, projection="3d")
for ii,y in enumerate(hie3-1):
ax2.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
ax2.set_xlabel("特征1",rotation=20)
ax2.set_ylabel("特征2",rotation=-20)
ax2.set_zlabel("特征3",rotation=90)
ax2.azim = 225
ax2.set_title("层次聚类为3簇")
plt.tight_layout()
plt.show()
图 层次化聚类结果
2.3 谱聚类与模糊聚类
2.3.1 谱聚类
谱聚类是从图论中演化出来的算法,后来在聚类中得到了广泛的应用。
其主要思想是把所有的数据看做空间中的点,这些点之间可以用边连接起来。距离较远的两个点之间的边权重值较低,而距离较近的两个点之间的边权重值较高,通过对所有数据点组成的图进行切图,让切图后不同的子图间边权重和尽可能的低,而子图内的边权重和尽可能的高,从而达到聚类的目的。
1)建图聚类:
谱聚类的第一步是建图,建图的方法有很多:
① K-邻近算法相似矩阵建图:
## 使用K近邻算法相似矩阵的建立方式
speclu_nei = SpectralClustering(n_clusters=3, # 投影到子空间的维度
affinity="nearest_neighbors", # 相似矩阵的建立方式
n_neighbors = 5, # 相似矩阵的建立时使用的近邻数
random_state = 123)
speclu_nei.fit(tsne_wine_x)
## 计算聚类的效果
nei_pre = speclu_nei.labels_
print("聚为3个簇,每簇包含的样本数量:\n",np.unique(nei_pre,return_counts = True))
print("聚为3个簇,聚类效果V测度: %.4f"%v_measure_score(wine_y,nei_pre))
②使用rbf算法相似矩阵的建图:
## 使用rbf算法相似矩阵的建立方式
speclu_rbf = SpectralClustering(n_clusters=3, # 投影到子空间的维度
affinity="rbf", # 相似矩阵的建立方式
gamma = 0.005, # 相似矩阵的建立时使用的参数
random_state = 123)
speclu_rbf.fit(tsne_wine_x)
## 计算聚类的效果
rbf_pre = speclu_rbf.labels_
print("聚为3个簇,每簇包含的样本数量:\n",np.unique(rbf_pre,return_counts = True))
print("聚为3个簇,聚类效果V测度: %.4f"%v_measure_score(wine_y,rbf_pre))
结果解读:
相对来说,K-邻近算法相似矩阵获得的V测度较低。
2)可视化相似矩阵:
## 可视化中不同的聚类结果构建的相似矩阵
plt.figure(figsize=(14,6))
plt.subplot(1,2,1)
sns.heatmap(speclu_nei.affinity_matrix_.toarray(),cmap="YlGnBu")
plt.title("K近邻算法构建的相似矩阵")
plt.subplot(1,2,2)
sns.heatmap(speclu_rbf.affinity_matrix_,cmap="YlGnBu")
plt.title("RBF构建的相似矩阵")
plt.tight_layout()
plt.show()
结果解读:
可以看到,K-邻近算法构建的相似矩阵更加稀疏,其用于谱聚类有更少的边可以切。
3)可视化构建图:
使用NetworkX库可视化构件图
这里需要安装pygraphviz包来完成可视化操作
pygraphviz包的安装方法采用whl文件安装
可以在git-hub中下载对应的whl文件
网址如下:
https://github.com/CristiFati/Prebuilt-Binaries/tree/master/PyGraphviz/v1.6
## 在二维空间中可视化两种不同的算法构建的节点网络
colors = ["red","blue","green"]
shapes = ["o","s","*"]
nei_mat = speclu_nei.affinity_matrix_.toarray()
rbf_mat = speclu_rbf.affinity_matrix_
## 可视化网络图
plt.figure(figsize=(14,6))
## 使用K近邻算法获得的网路图
plt.subplot(1,2,1)
G1 = nx.Graph(nei_mat) ## 生成无项图
pos1=graphviz_layout(G1,prog="fdp")
for ii in range(3): # 为每种类型的点设置颜色和形状
nodelist = np.arange(len(wine_y))[wine_y == ii]
nx.draw_networkx_nodes(G1,pos1,nodelist = nodelist,alpha=0.8,
node_size=50,node_color = colors[ii],
node_shape=shapes[ii])
nx.draw_networkx_edges(G1,pos1,width=1,edge_color= "k")
plt.title("K近邻算法构建网络")
## 使用RBF算法获得的网路图
plt.subplot(1,2,2)
G2 = nx.Graph(rbf_mat) ## 生成无项图
pos2=graphviz_layout(G2,prog="fdp")
for ii in range(3): # 为每种类型的点设置颜色和形状
nodelist = np.arange(len(wine_y))[wine_y == ii]
nx.draw_networkx_nodes(G2,pos2,nodelist = nodelist,alpha=0.8,
node_size=50,node_color = colors[ii],
node_shape=shapes[ii])
nx.draw_networkx_edges(G2,pos2,width=1,alpha = 0.1,edge_color= "gray")
plt.title("RBF算法构建网络")
plt.tight_layout()
plt.show()
结果解读:
可以看到,在二维空间中K-邻近算法构建的图使用了较少的边,而基于RBF算法构建的图使用了更多的边。
2.3.2 模糊聚类
模糊聚类最常用的算法是:模糊C均值聚类。该算法可以通过pyclustering库中的fcm()函数完成。
下面,对降维后的酒数据进行模糊聚类,并输出聚类结果。
## 模糊聚类
initial_centers = tsne_wine_x[[1,51,100],:]
fcmcluster = fcm(data = tsne_wine_x,initial_centers=initial_centers)
fcmcluster.process() # 算法训练数据
fcmcluster_pre = fcmcluster.get_clusters() # 聚类结果
## 将聚类结果处理为类别标签
fcmcluster_label = np.arange(len(tsne_wine_x))
for ii,li in enumerate(fcmcluster_pre):
fcmcluster_label[li] = ii
## 获取每个样本预测的隶属度
membership = fcmcluster.get_membership()
membership = np.array(membership)
print("每簇包含的样本数量:",np.unique(fcmcluster_label,return_counts = True))
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,fcmcluster_label))
print("前几个样本属于每个类的隶属度:\n",np.round(membership[0:4,:],4))
结果解读:
输出结果可以发现,获取的每个样本的隶属度membership是一个概率值,在每行的输出中所对应的列值越大,说明属于对应簇的可能性越大。
通过计算获得的类别标签得到的V测度为0.7728。
为了更好理解模糊聚类对应的隶属度,在下面使用堆积条形图,可视化每个样本的隶属度取值情况。
## 使用堆积直方图可视化每个样本的隶属度
plt.figure(figsize=(14,6))
x = np.arange(membership.shape[0])
plt.bar(x, membership[:,0], color="red", edgecolor='red', width=1,
label = "class 1",alpha = 0.5)
plt.bar(x, membership[:,1],bottom = membership[:,0], color="blue",
edgecolor='blue', width=1,label = "class 2",alpha = 0.5)
plt.bar(x, membership[:,2], bottom = membership[:,0] + membership[:,1],
color="green", edgecolor='green', width=1,label = "class 3",alpha = 0.5)
plt.xlim([-0.5,len(x)])
plt.title("每个样本的隶属度取值")
plt.legend()
plt.show()
结果解读:
每个样本的隶属度之和为1;并且前面的样本属于第二个簇的可能性更大;中间的样本属于第一个簇的可能性更大,但有几个样本属于另外两个簇的可能性也很大;最后一些样本属于第三个簇的可能性很大。
2.4 密度聚类(DBSCAN)
采用“双月数据集”来展示密度聚类的算法特点。
下面进行可视化“双月数据集”
## 密度聚类,使用双月数据集进行演示
moons = pd.read_csv(r"C:\Users\Peter Chen\Desktop\11-21\moonsdatas.csv")
print(moons.head())
## 可视化数据的分布情况
index0 = np.where(moons.Y == 0)[0]
index1 = np.where(moons.Y == 1)[0]
plt.figure(figsize=(10,6))
plt.plot(moons.X1[index0],moons.X2[index0],"ro")
plt.plot(moons.X1[index1],moons.X2[index1],"bs")
plt.grid()
plt.title("数据分布情况")
plt.show()
结果解读:
所谓双月数据集,是指数据集包含:两个特征、2个分类。且每类数据的分布像个月牙,所以称之为双月数据。
密度聚类,可以使用sklearn库中的DBSCAN()建立聚类模型。其中,更改参数eps,min_samples可以获得不同的聚类效果。
下面演示,使用4组不同的参数,来获得4种不同的聚类效果,并且将聚类结果进行可视化。
## 对数据进行密度聚类,并可视化出聚类后的结果
epsdata = [0.2,0.2,0.13,1] ## 定义不同的eps参数的取值
min_sample = [5,10,5,10] ## 定义不同的min_samples参数的取值
plt.figure(figsize=(14,10))
for ii,eps in enumerate(epsdata):
db = DBSCAN(eps=eps,min_samples = min_sample[ii])
db.fit(moons[["X1","X2"]].values)
## 获取聚类后的类别标签
db_pre_lab = db.labels_
print("参数eps取值为:",eps,"参数min_samples取值为:",min_sample[ii])
print("每簇包含的样本数量:",np.unique(db_pre_lab,return_counts = True))
print("聚类效果V测度: %.4f"%v_measure_score(moons["Y"],db_pre_lab))
print("============================")
## 可视化出聚类后的结果
plt.subplot(2,2,ii+1)
sns.scatterplot(x=moons["X1"], y=moons["X2"],
style = db_pre_lab,s = 100)
plt.legend(loc = 1)
plt.grid()
plt.title("密度聚类:eps="+str(eps)+",min_samples="+str(min_sample[ii]))
plt.tight_layout()
plt.show()
结果解读:
可以看到,当参数eps=0.2,min_samples=5时,获得的聚类效果最好,可以将数据切分为两个簇,每个簇各有100个样本,聚类效果V测度为1。
而当参数eps=0.2,min_samples=10时,获得的聚类结果种两个簇分别有99个和100个样本,其中还有一个样本被认为是噪音。
剩余的两组参数获得的聚类效果较差,一个将数据聚为4簇,一个将数据聚为1簇。
接下来,可以比对下密度聚类和K-均值聚类的差异。
## 将密度聚类和Kmeans聚类的结果进行对比
## 密度聚类
db = DBSCAN(eps=0.2,min_samples = 5)
db.fit(moons[["X1","X2"]].values)
db_pre_lab = db.labels_
## k均值聚类
km = KMeans(n_clusters=2,random_state=1)
k_pre = km.fit_predict(moons[["X1","X2"]].values)
## 可视化两种算法的聚类效果
plt.figure(figsize=(14,6))
plt.subplot(1,2,1)
sns.scatterplot(x=moons["X1"], y=moons["X2"],
style = db_pre_lab,s = 100)
plt.legend(loc = 1)
plt.grid()
plt.title("密度聚类")
plt.subplot(1,2,2)
sns.scatterplot(x=moons["X1"], y=moons["X2"],
style = k_pre,s = 100)
plt.legend(loc = 1)
plt.grid()
plt.title("Kmeans聚类")
plt.tight_layout()
plt.show()
结果解读:
可以发现,针对非球型分布的数据,使用密度聚类能过获得比K-均值聚类更符合期望的聚类效果。
2.5 高斯混合模型聚类
在sklearn种,提供了两种基于高斯混合模型得聚类算法。
分别可以使用:
① GaussianMixture();
② BayesianGaussianMixture();
获得聚类结果。
## 使用高斯混合模型对酒数据进聚类分析
gmm = GaussianMixture(n_components=3,covariance_type = "full",
random_state = 1)
gmm.fit(tsne_wine_x)
## 获取对数据的聚类标签
gmm_pre = gmm.predict(tsne_wine_x)
print("高斯混合模型,每簇包含的样本数量:",np.unique(gmm_pre,return_counts = True))
print("每个簇的聚类中心为:\n",gmm.means_)
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,gmm_pre))
## 使用变分贝叶斯高斯混合模型对酒数据进聚类分析
bgmm = BayesianGaussianMixture(n_components=3,covariance_type = "full",
random_state = 1)
bgmm.fit(tsne_wine_x)
## 获取对数据的聚类标签
bgmm_pre = bgmm.predict(tsne_wine_x)
print("变分贝叶斯高斯混合模型,每簇包含的样本数量:",np.unique(bgmm_pre,return_counts = True))
print("每个簇的聚类中心为:\n",bgmm.means_)
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,bgmm_pre))
结果解读:
可以看到,使用GaussianMixture()获得的聚类效果V测度为0.7728,比使用BayesianGaussianMixture()效果要好很多。
接下来,使用3D散点图,来进行可视化对比:
## 可视化算法聚类结果
colors = ["red","blue","green"]
shapes = ["o","s","*"]
fig = plt.figure(figsize=(14,6))
## 将坐标系设置为3D,高斯混合模型聚类结果
ax1 = fig.add_subplot(121, projection="3d")
for ii,y in enumerate(gmm_pre):
ax1.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
## 可视化聚类中心
for ii in range(len(np.unique(gmm_pre))):
x = gmm.means_[ii,0]
y = gmm.means_[ii,1]
z = gmm.means_[ii,2]
ax1.scatter(x,y,z,c = "gray",marker="o",s=150,edgecolor='k')
# ax1.text(x,y,z,"簇"+str(ii+1))
ax1.set_xlabel("特征1",rotation=20)
ax1.set_ylabel("特征2",rotation=-20)
ax1.set_zlabel("特征3",rotation=90)
ax1.azim = 225
ax1.set_title("高斯混合模型聚为3簇")
## 变分贝叶斯高斯混合模型聚类结果
ax2 = fig.add_subplot(122, projection="3d")
for ii,y in enumerate(bgmm_pre):
ax2.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
## 可视化聚类中心
for ii in range(len(np.unique(bgmm_pre))):
x = bgmm.means_[ii,0]
y = bgmm.means_[ii,1]
z = bgmm.means_[ii,2]
ax2.scatter(x,y,z,c = "gray",marker="o",s=150,edgecolor='k')
# ax2.text(x,y,z,"簇"+str(ii+1))
ax2.set_xlabel("特征1",rotation=20)
ax2.set_ylabel("特征2",rotation=-20)
ax2.set_zlabel("特征3",rotation=90)
ax2.azim = 225
ax2.set_title("变分贝叶斯高斯混合模型聚为3簇")
plt.tight_layout()
plt.show()
2.6 亲和力传播聚类
在sklearn库中,可以使用AffinityPropagation()函数来完成。
参数damping设置算法的阻尼因子;
参数preference设置使用的示例样本数量;
接下来,使用相同的damping和不同的preference参数,来构建亲和力传播聚类:
## 对酒数据进行亲和力传播聚类
# preference = -200时
af1 = AffinityPropagation(damping = 0.6, ## 阻尼因子
preference = -200, ## 使用的示例样本数量
)
af1.fit(tsne_wine_x)
## 输出聚类分析的结果
af1.labels_
print("亲和力传播聚类1:\n每簇包含的样本数量:",np.unique(af1.labels_,return_counts = True))
print("每个簇的聚类中心为:\n",af1.cluster_centers_)
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,af1.labels_))
# preference = -300时
af2 = AffinityPropagation(damping = 0.6, ## 阻尼因子
preference = -300, ## 使用的示例样本数量
)
af2.fit(tsne_wine_x)
## 输出聚类分析的结果
af2.labels_
print("亲和力传播聚类2:\n每簇包含的样本数量:",np.unique(af2.labels_,return_counts = True))
print("每个簇的聚类中心为:\n",af2.cluster_centers_)
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,af2.labels_))
结果解读:
第一个亲和力传播模型将数据聚类为5个簇,每个簇各有20、45、27、37、49个样本;
第二个亲和力传播模型将数据聚类为3个簇,每个簇各有66、56、56个样本;
且第二个亲和力传播模型的V测度更高。
接下来,利用簇中心和对应样本连线的方法进行聚类的三维展示:
# 导入pandas包
import pandas as pd
# read_excel() 导入.xlsx文件
df =pd.read_excel(r"C:\Users\Peter Chen\Desktop\pandas示例数据.xlsx")# 指定文件路径
# 由于电脑文件中路径默认使用\,因此需要在引号前加转义符r,否则需要把所有的\改为/。
结果解读:
亲和力传播模型的聚类结果是,在同簇之间更加聚集,不同簇之间更加远离。
2.7 BIRCH聚类
BIRCH聚类的全称是利用层次方法的平衡迭代规约和聚类(Balanced Iterative Reducing and Clustering Using Hierarchies)。
其可以通过sklearn库中的Birch()函数来完成。
为了获得更好的聚类效果,可以先将数据聚类为不同数目的簇,再计算不同聚类模型的V测度值,通过得分高低来确定合适的聚类数目。
## 计算聚为不同簇的V测度大小
vm = []
n_cluster = 10
for cluster in range(1,n_cluster):
birch = Birch(threshold = 0.5, ## 合并样本的半径阈值
branching_factor = 20, ## 每个节点中CF子集群的最大数量
n_clusters=cluster)
birch.fit(tsne_wine_x) # 拟合模型
vm.append(v_measure_score(wine_y,birch.labels_))
## 可视化V测度的变化情况
plt.figure(figsize=(10,6))
plt.plot(range(1,n_cluster),vm,"r-o")
plt.xlabel("聚类数目")
plt.ylabel("V测度")
plt.title("BIRCH聚类")
## 在图中添加一个箭头
plt.annotate("V测度最高", xy=(3,vm[2]),xytext=(4,0.5),
arrowprops=dict(facecolor='blue', shrink=0.1))
plt.grid()
plt.show()
结果解读:
可以看到,将数据聚类为3个簇时的V测度得分最高。
接下来,将使用网格搜索针对Birch()聚类中的threshold和branching_factor参数,寻找聚类效果较好的参数组合,并且针对每组参数组合下的V测度值,进行3D曲面图可视化:
## 使用参数网格搜索的方法寻找最合适的threshold 和 ranching_factor参数
thre = [0.1,0.2,0.3,0.4,0.5, 0.75, 1,1.5,2,3,5]
ranch = np.arange(5,50,5)
threx, ranchy = np.meshgrid(thre,ranch)
vm = np.ones_like(threx)
## 计算不同参数组合下的V测度
for i,t in enumerate(thre):
for j,r in enumerate(ranch):
birch = Birch(threshold = t,branching_factor = r,
n_clusters=3)
birch.fit(tsne_wine_x) # 拟合模型
vm[j,i] = (v_measure_score(wine_y,birch.labels_))
## 使用3D曲面图可视化交叉验证的平均均方根误差
## 数据准备
x, y = np.meshgrid(range(len(thre)),range(len(ranch)))
## 可视化
fig = plt.figure(figsize=(10,6))
ax1 = fig.add_subplot(111, projection="3d")
surf = ax1.plot_surface(x,y,vm,cmap=plt.cm.coolwarm,
linewidth=0.1)
plt.xticks(range(len(thre)),thre,rotation=45)
plt.yticks(range(len(ranch)),ranch,rotation=125)
ax1.set_xlabel("threshold",labelpad=25)
ax1.set_ylabel("ranching_factor",labelpad=15)
ax1.set_zlabel("V测度",rotation = 90,labelpad=10)
plt.title("BIRCH参数搜索")
plt.tight_layout()
plt.show()
结果解读:
可以发现,当threshold=2时,聚类效果较好。
接下来,进行threshold=2时的聚类效果散点图展示:
## 使用合适的参数聚类为3类
birch = Birch(threshold = 2, ## 合并样本的半径阈值
branching_factor = 20, ## 每个节点中CF子集群的最大数量
n_clusters=3)
birch.fit(tsne_wine_x) # 拟合模型
print("BIRCH聚类,每簇包含的样本数量:",np.unique(birch.labels_,return_counts = True))
print("聚类效果V测度: %.4f"%v_measure_score(wine_y,birch.labels_))
## 在3维空间中可视化聚类的效果
colors = ["red","blue","green"]
shapes = ["o","s","*"]
birch_pre = birch.labels_
fig = plt.figure(figsize=(10,6))
## 将坐标系设置为3D,Birch模型聚类结果
ax1 = fig.add_subplot(111, projection="3d")
for ii,y in enumerate(birch_pre):
ax1.scatter(tsne_wine_x[ii,0],tsne_wine_x[ii,1],tsne_wine_x[ii,2],
s = 40,c = colors[y],marker = shapes[y],alpha = 0.5)
ax1.set_xlabel("特征1",rotation=20)
ax1.set_ylabel("特征2",rotation=-20)
ax1.set_zlabel("特征3",rotation=90)
ax1.azim = 225
ax1.set_title("BIRCH模型聚为3簇")
plt.tight_layout()
plt.show()
结果解读:
BRICH聚类可视化,可以看到,每个簇包含65、62、51个样本,并且V测度为0.8347。
3.1 Kmeans实战挑战-超市用户细分
实例:根据顾客ID、性别、年龄、平均收入、消费等级,实现对超市目标用户的群体细分。
① 导入库:
# 数据处理
import numpy as np
import pandas as pd
# KMeans聚类
from sklearn.cluster import KMeans
# 绘图库
import matplotlib.pyplot as plt
import seaborn as sns
import plotly as py
import plotly.express as px
import plotly.graph_objects as go
py.offline.init_notebook_mode(connected = True)
② 数据初步分析(EDA):
# 导入数据
df=pd.read_csv(r"C:\Users\Peter Chen\Desktop\11-21\Mall_Customers.csv")
df.head()
# 数据形状
df.shape
# 200行,5列的数据
# 缺失值情况
df.isnull().sum()
# 全部字段都是完整的,没有缺失值
# 数据类型
df.dtypes
# 除了性别Gender是字符串,其他都是int64的数值型
# 描述统计信息
# 个数、中值、方差、最值、四分位数等
df.describe()
③ 可视化层面的EDA:
3-1 数值型变量的分布直方图:
cols提取了三个数值型变量名:['Age', 'Annual Income (k$)', 'Spending Score (1-100)']
下面,查看'Age'、 'Annual Income (k$)'、 'Spending Score (1-100)'的直方图,观察整体的分布情况:
# 数值型变量的分布直方图
# cols提取了三个数值型变量名:['Age', 'Annual Income (k$)', 'Spending Score (1-100)']
# 查看'Age'、 'Annual Income (k$)'、 'Spending Score (1-100)'的直方图,观察整体的分布情况:
# 绘图
plt.figure(1,figsize=(15,6)) # 画布大小
n = 0
for col in cols:
n += 1 # 子图位置
plt.subplot(1,3,n) # 子图
plt.subplots_adjust(hspace=0.5,wspace=0.5) # 调整宽高
sns.distplot(df[col],bins=20) # 绘制直方图
plt.title(f'Distplot of {col}') # 标题
plt.show() # 显示图形
3-2 分类变量性别对数据的影响:
3-2-1 性别人数统计:
# 3-2 分类变量性别对数据的影响
# 3-2-1 性别人数统计
plt.figure(1,figsize=(12,5))
sns.countplot(y="Gender",data=df)
plt.show()
3-2-2 不同性别下的数据分布:
# 3-2-2 不同性别下的数据分布
sns.pairplot(df.drop(["CustomerID"],axis=1), # 删除编号列
hue="Gender", # 分类字段
aspect=1.5)
plt.show()
结果解读:
双变量分布图可以显示:性别因素对其他3个字段的影响不大。
3-2-3 分类变量下连续型变量间的关系:
a) 不同性别下年龄和平均收入的关系
# a) 不同性别下年龄和平均收入的关系#
plt.figure(1,figsize=(15,6)) # 绘图大小
for gender in ["Male", "Female"]:
plt.scatter(x="Age", y="Annual Income (k$)", # 指定两个分析的字段
data=df[df["Gender"] == gender], # 待分析的数据,某个gender下
s=200,alpha=0.5,label=gender # 散点的大小、透明度、标签分类
)
# 横纵轴、标题设置
plt.xlabel("Age")
plt.ylabel("Annual Income (k$)")
plt.title("Age vs Annual Income w.r.t Gender")
# 显示图形
plt.show()
b) 不同性别下平均收入和消费得分的关系
# b)不同性别下平均收入和消费得分的关系
plt.figure(1,figsize=(15,6))
for gender in ["Male", "Female"]: # 解释参考上面
plt.scatter(x = 'Annual Income (k$)',y = 'Spending Score (1-100)',
data=df[df["Gender"] == gender],
s=200,alpha=0.5,label=gender)
plt.xlabel('Annual Income (k$)')
plt.ylabel('Spending Score (1-100)')
plt.title("Annual Income vs Spending Score w.r.t Gender")
plt.show()
3-3 分类变量分组下的连续型变量小提琴图:
这里绘制不同性别下的数据分布情况
# 不同性别下的数据分布情况
# 分簇散点图:Swarmplots
# 小提琴图:violinplot
plt.figure(1,figsize=(15,7))
n = 0
for col in cols:
n += 1 # 子图顺序
plt.subplot(1,3,n) # 第n个子图
plt.subplots_adjust(hspace=0.5,wspace=0.5) # 调整宽高
# 绘制某个col下面的两种图形,通过Gender进行分组显示
sns.violinplot(x=col,y="Gender",data=df,palette = "vlag")
sns.swarmplot(x=col, y="Gender",data=df)
# 轴和标题设置
plt.ylabel("Gender" if n == 1 else '')
plt.title("Violinplots & Swarmplots" if n == 2 else '')
plt.show()
④ 连续型变量间的相关性分析:
这里采用两两之间的线性回归展示其相关性
# 两两之间的线性回归
plt.figure(1,figsize=(15,6))
n = 0
for x in cols:
for y in cols:
n += 1 # 每循环一次n增加,子图移动一次
plt.subplot(3,3,n) # 3*3的矩阵,第n个图形
plt.subplots_adjust(hspace=0.5, wspace=0.5) # 子图间的宽、高参数
sns.regplot(x=x,y=y,data=df,color="#AE213D") # 绘图的数据和颜色
plt.ylabel(y.split()[0] + " " + y.split()[1] if len(y.split()) > 1 else y)
plt.show()
⑤ 采用两个特征进行Kmeans聚类:
这里采用'Age' , 'Spending Score (1-100)'两个特征进行聚类。
# ① 待拟合数据
df1 = df[['Age' , 'Spending Score (1-100)']].iloc[:,:].values # 待拟合数据
# ② K值选取
inertia = [] # 空列表,用来存储到质心的距离之和
for k in range(1,11): # k值的选取默认是在1-10之间,经验值是5或者10
algorithm = (KMeans(n_clusters=k, # k值
init="k-means++", # 初始算法选择
n_init=10, # 随机运行次数
max_iter=300, # 最多迭代次数
tol=0.0001, # 容忍最小误差
random_state=111, # 随机种子
algorithm="full")) # 算法选择 auto、full、elkan
algorithm.fit(df1) # 拟合数据
inertia.append(algorithm.inertia_) # 质心之和
inertia# 查看到质心的距离之和
# 绘制出K值的变化和质心距离之和的关系:
plt.figure(1,figsize=(15,6))
plt.plot(np.arange(1,11), inertia, 'o') # 数据绘制两次,标记不同
plt.plot(np.arange(1,11), inertia, '-', alpha=0.5)
plt.xlabel("Choose of K")
plt.ylabel("Interia")
plt.show()
# k=4是比较合适的。于是采用k=4来进行数据的真实拟合过程
结果解读:
手肘法发现,k=4是比较合适的。于是采用k=4来进行聚类建模。
# ③ 聚类建模
algorithm = (KMeans(n_clusters=4, # k=4
init="k-means++",
n_init=10,
max_iter=300,
tol=0.0001,
random_state=111,
algorithm="elkan"))
algorithm.fit(df1) # 模拟数据
# ④ 获得聚类标签label和4个质心:
labels1 = algorithm.labels_ # 分类的结果(4类)
centroids1 = algorithm.cluster_centers_ # 最终质心的位置
print("labels1:", labels1)
print("centroids1:", centroids1)
# ⑤ 可视化
h = 0.02
x_min,x_max=df1[:,0].min() - 1,df1[:,0].max() + 1
y_min,y_max=df1[:,1].min() - 1,df1[:,1].max() + 1
print(x_min,x_max)
# arange:相当于是range函数,步长为h
# meshgrid:用再两个坐标轴上的点在平面上画网格
xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
xx
yy
# 数据合并
Z=algorithm.predict(np.c_[xx.ravel(),yy.ravel()])
Z
# 可视化绘图
plt.figure(1,figsize=(14,5))
plt.clf()
Z = Z.reshape(xx.shape)
plt.imshow(Z,interpolation="nearest",
extent=(xx.min(),xx.max(),yy.min(),yy.max()),
cmap = plt.cm.Pastel2,
aspect = 'auto',
origin='lower')
plt.scatter(x="Age",
y='Spending Score (1-100)',
data = df ,
c = labels1 ,
s = 200)
plt.scatter(x = centroids1[:,0],
y = centroids1[:,1],
s = 300 ,
c = 'red',
alpha = 0.5)
plt.xlabel("Age")
plt.ylabel("Spending Score(1-100)")
plt.show()
# ⑥ 简单可视化
df3=pd.DataFrame(df1,columns=["Age","Spending Score(1-100)"])
df3
# 添加聚类标签
df3["Labels"]=labels1
df3
# 使用cuddlinks库进行离线化
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import cufflinks as cf
init_notebook_mode(connected=True)
cf.go_offline()
cf.set_config_file(offline=True, world_readable=True)
# 分类可视化
# 绘制动图使用plotly,首先要使用cuddlinks库进行离线化
%matplotlib notebook
import plotly.express as px
fig=px.scatter(df3,x="Age",y="Spending Score(1-100)",color="Labels",color_continuous_scale="rainbow")
fig.show()
⑥ 采用3个特征进行Kmeans聚类并可视化:
3个特征的可视化就需要三维图像了;
根据Age 、 Annual Income 、 Spending Score来进行聚类,最终绘制成3维图形。
# ⑥ 三个特征聚类分析
%matplotlib notebook
# K值选取
X3 = df[['Age' , 'Annual Income (k$)' ,'Spending Score (1-100)']].iloc[:,:].values # 选取3个字段的数据
inertia = []
for n in range(1 , 11):
algorithm = (KMeans(n_clusters = n,
init='k-means++',
n_init = 10 ,
max_iter=300,
tol=0.0001,
random_state= 111 ,
algorithm='full') )
algorithm.fit(X3) # 拟合数据
inertia.append(algorithm.inertia_)
# 绘制肘图确定k:
plt.figure(1 , figsize = (10 ,6))
plt.plot(np.arange(1 , 11) , inertia , 'o')
plt.plot(np.arange(1 , 11) , inertia , '-' , alpha = 0.5)
plt.xlabel('Number of Clusters') , plt.ylabel('Inertia')
plt.show()
# 最终选取k=6来聚类
# 建模拟合
algorithm = (KMeans(n_clusters=6, # 确定的k值
init="k-means++",
n_init=10,
max_iter=300,
tol=0.0001,
random_state=111,
algorithm="elkan"))
algorithm.fit(X3)
labels2 = algorithm.labels_
centroids2 = algorithm.cluster_centers_
print(labels2)
print(centroids2)
# 得到标签和质心:
labels2 = algorithm.labels_
centroids2 = algorithm.cluster_centers_
# plotly库三维可视化展示
df["labels2"] = labels2
trace = go.Scatter3d(
x=df["Age"],
y= df['Spending Score (1-100)'],
z= df['Annual Income (k$)'],
mode='markers',
marker = dict(
color=df["labels2"],
size=20,
line=dict(color=df["labels2"],width=12),
opacity=0.8
)
)
data = [trace]
layout = go.Layout(
margin=dict(l=0,r=0,b=0,t=0),
title="six Clusters",
scene=dict(
xaxis=dict(title="Age"),
yaxis = dict(title = 'Spending Score'),
zaxis = dict(title = 'Annual Income')
)
)
fig = go.Figure(data=data,layout=layout)
fig.show()
如有侵权,请联系本站删除!