机器学习之聚类算法
一、聚类算法的简介1. 概述聚类算法是一种无监督学习算法主要是根据样本之间的相似度将样本划分到不同分类中来进行结果预测的。2. 相似度样本的相似性可以通过样本点之间的距离来衡量。常见的相似度计算方法有欧式距离样本点的直线距离通过对应坐标点维度的差值求平方和即勾股定理求模长。曼哈顿距离也称城市街区距离横平竖直测量距离通过对应坐标点维度的差值的绝对值求和。切比雪夫距离类似国际象棋中国王的走法直行、横行、斜行测量距离通过对应坐标点维度的差值的绝对值求最大值。3. 应用场景客户细分根据消费习惯、年龄、地域将用户分成不同群组进行精准营销。图像分割把图片中颜色、纹理相近的像素点聚成一类从而分离出前景和背景。文档分类将内容相似的文章自动归类到同一主题。异常检测那些无法归入任何簇或者远离所有簇的数据点可能就是异常值如信用卡欺诈检测。4. 分类按聚类颗粒度划分细聚类粗聚类按实现方法划分K-Means本文重点介绍层次聚类DBSCAN几种常见的聚类算法对比算法名称核心思路优点缺点K-Means预先设定K个中心点质心迭代更新让每个样本点到质心的距离之后最小简单快速适合大数据集需预先指定K值对初识中心点敏感只能发现球形簇层次聚类自底向上合并或自上向下分类最相似的簇形成一个树形结构不用指定K值结果可视化为树形图计算量大不适合大数据集DBSCAN基于密度将紧密相连的样本划分为一簇并自动识别为噪声点能发现任意形状的簇能自动处理异常点对密度参数敏感在高纬数据中表现欠佳高斯混合模型Gaussian Mixture Model, GMM假设数据由多个高斯分布混合生成用概率模型进行软分类可以给出样本属于某个簇的概率灵活性高计算较复杂容易过拟合谱聚类将数据点视为图的顶点根据相似度构建带权图然后对图的拉普拉斯矩阵进行特征分解利用特征向量进行聚类能发现非凸、非球形、环状等复杂形状的簇对高维数据有一定鲁棒性不受数据维度灾难影响严重计算开销大需构建相似度矩阵及特征分解对尺度参数如高斯核带宽敏感聚类结果依赖图构建方式二、K-Means1. 概述K-Means 是一种最经典、最广泛使用的基于原型的划分聚类算法。它的目标是将nnn个样本划分到KKK个互不相交的簇cluster中使得每个样本到它所属簇的中心点centroid的距离平方和最小。简单说让簇内点尽可能紧凑簇间点尽可能分离。2. 实现流程随机设置K个特征空间内的点作为初始的聚类中心对于其他每个点计算到K个中心的距离未知的点选择最近的一个聚类中心点作为标记类别接着对着标记的聚类中心之后重新计算出每个聚类的新中心点平均值如果计算得出的新中心点与原中心点一样质心不再移动那么结束否则重新进行第二步过程3. 常用的评估指标3.1 簇内误差平方和SSE / Inertia定义所有样本点到其所属簇中心点的距离平方之和。SSE 越小表示数据点越接近它们的中心聚类效果越好。不能单独用于选择最佳 K通常配合“肘部法则”使用。公式SSE∑i1k∑p∈Ci∣p−mi∣2SSE \sum_{i1}^{k} \sum_{p \in C_i} |p - m_i|^2SSEi1∑kp∈Ci∑∣p−mi∣2K 表示聚类中心的个数Ci表示簇p 表示样本mi表示簇的质心肘部法则Elbow Method计算不同 K 值下的 SSE簇内误差平方和画出 K-SSE 曲线。当 SSE 下降速度明显变缓时对应的 K 即为“肘部”此时就是最佳的K值。肘部法可以用来确定 K 值对于n个点的数据集迭代计算 k from 1 to n每次聚类完成后计算 SSESSE 是会逐渐变小的因为每个点都是它所在的簇中心本身。SSE 变化过程中会出现一个拐点下降率突然变缓时即认为是最佳 n_clusters 值。在决定什么时候停止训练时肘形判据同样有效数据通常有更多的噪音在增加分类无法带来更多回报时我们停止增加类别。3.2 轮廓系数Silhouette Coefficient定义结合了样本与自身簇的紧密程度凝聚度aaa和与最近邻簇的分离程度分离度bbb。SC值越大聚类效果越好。公式sb−amax(a,b)s \frac{b - a}{\max(a, b)}smax(a,b)b−aa样本iii到同一簇内其他点距离的平均值b样本iii到其他簇内其他点距离的最小值计算过程计算每一个样本 i 到同簇内其他样本的平均距离 ai该值越小说明簇内的相似程度越大计算每一个样本 i 到最近簇 j 内的所有样本的平均距离 bij该值越大说明该样本越不属于其他簇 j计算所有样本的平均轮廓系数轮廓系数的范围为[-1, 1]值越大聚类效果越好3.3 卡林斯基-哈拉巴斯指数Calinski–Harabasz Index, CHI定义结合了聚类的凝聚度Cohesion和分离度Separation、质心的个数希望用最少的簇进行聚类。CHI值越大聚类效果越好。公式CH(k)SSBSSW⋅m−kk−1\text{CH}(k) \frac{SSB}{SSW} \cdot \frac{m - k}{k - 1}CH(k)SSWSSB⋅k−1m−kSSW∑i1m∥xi−Cpi∥2SSW \sum_{i1}^{m} \|x_i - C_{p_i}\|^2SSWi1∑m∥xi−Cpi∥2SSB∑j1knj∥Cj−Xˉ∥2SSB \sum_{j1}^{k} n_j \|C_j - \bar{X}\|^2SSBj1∑knj∥Cj−Xˉ∥2SSW 的含义Cpi表示质心xi表示某个样本SSW 值是计算每个样本点到质心的距离并累加起来SSW 表示表示簇内的内聚程度越小越好m 表示样本数量k 表示质心个数SSB 的含义Cj表示质心X 表示质心与质心之间的中心点nj表示样本的个数SSB 表示簇与簇之间的分离度SSB 越大越好评估指标案例演示 案例: 演示聚类算法的评估指标, 即: SSE 肘部法, SC轮廓系数法, CH轮廓系数法 聚类算法的评估指标: 思路1: SSE 肘部法 SSE: 概述: 所有簇的所有样本到该簇心的误差的平方和 特点: 随着K值的增加, SSE会逐渐减少 目标: SSE值越小, 代表簇内样本越聚集, 内聚程度越高 肘部法: K值增大, SSE值会随之减小, 下降梯度陡然变缓的时候, 那个K值, 就是我们要的最佳值 思路2: SC轮廓系数 考虑簇内 - 聚集程度, 越小越好 考虑簇外 - 分离程度, 越大越好 思路3: CH轮廓系数 考虑簇内 - 聚集程度, 越小越好 考虑簇外 - 分离程度, 越大越好 考虑K值 - K值越小, 代表簇内样本越聚集, 内聚程度越高 # 导包fromsklearn.clusterimportKMeansimportmatplotlib.pyplotaspltfromsklearn.datasetsimportmake_blobsfromsklearn.metricsimportcalinski_harabasz_score,silhouette_score# 1. 定义函数, 演示: SSE 肘部法defdm01_sse():# 1. 定义sse列表, 记录: 每个K值的SSE值sse_list[]# 2. 生成数据集# 参1: 样本数量, 参2: 特征数量, 参3: 4个簇, 参4: 4个簇std标准差, 参5: 随机种子x,ymake_blobs(n_samples1000,n_features2,centers[[-1,1],[0,0],[1,1],[2,2]],cluster_std[0.4,0.2,0.2,0.2],random_state23)# 3. for循环遍历, 获取到每个K值, 计算对应的sse值, 并添加到sse_list列表中forkinrange(1,100):# 3.1 创建KMeans对象, 指定K值, 迭代次数, 随机种子estimatorKMeans(n_clustersk,random_state23)# 3.2 训练模型estimator.fit(x)# 3.3 模型预测, 此处略# 3.4 获取到每个sse值sse_valueestimator.inertia_# 3.5 把sse值添加到sse_list列表中sse_list.append(sse_value)# 4. 绘制SSE曲线 - 数据的可视化# 4.1 创建画布, 指定画布大小plt.figure(figsize(20,10))# 4.2 设置标题plt.title(sse value)# 4.3 设置x轴刻度plt.xticks(range(0,100,3))# 4.4 添加x轴, y轴标签plt.xlabel(k)plt.ylabel(sse)# 4.5 绘制网格plt.grid()# 4.6 绘制折线图# 参1: K值, 参2: 该K值对应的sse值plt.plot(range(1,100),sse_list)# 4.7 显示折线图plt.show()# 2. 定义函数, 演示: SC轮廓系数法defdm02_sc():# 1. 定义sc列表, 记录: 每个K值的sc值sc_list[]# 2. 生成数据集# 参1: 样本数量, 参2: 特征数量, 参3: 4个簇, 参4: 4个簇std标准差, 参5: 随机种子x,ymake_blobs(n_samples1000,n_features2,centers[[-1,1],[0,0],[1,1],[2,2]],cluster_std[0.4,0.2,0.2,0.2],random_state23)# 3. for循环遍历, 获取到每个K值, 计算对应的sc值, 并添加到sc_list列表中forkinrange(2,100):# 考虑簇外, 至少2个簇# 3.1 创建KMeans对象, 指定K值, 迭代次数, 随机种子estimatorKMeans(n_clustersk,random_state23)# 3.2 训练模型estimator.fit(x)# 3.3 模型预测y_predestimator.predict(x)# 3.4 获取到每个sc值sc_valuesilhouette_score(x,y_pred)# 3.5 把sc值添加到sc_list列表中sc_list.append(sc_value)# 4. 绘制sc曲线 - 数据的可视化# 4.1 创建画布, 指定画布大小plt.figure(figsize(20,10))# 4.2 设置标题plt.title(sc value)# 4.3 设置x轴刻度plt.xticks(range(0,100,3))# 4.4 添加x轴, y轴标签plt.xlabel(k)plt.ylabel(sc)# 4.5 绘制网格plt.grid()# 4.6 绘制折线图# 参1: K值, 参2: 该K值对应的sc值plt.plot(range(2,100),sc_list)# 4.7 显示折线图plt.show()# 3. 定义函数, 演示: CH轮廓系数法defdm03_ch():# 1. 定义ch列表, 记录: 每个K值的ch值ch_list[]# 2. 生成数据集# 参1: 样本数量, 参2: 特征数量, 参3: 4个簇, 参4: 4个簇std标准差, 参5: 随机种子x,ymake_blobs(n_samples1000,n_features2,centers[[-1,1],[0,0],[1,1],[2,2]],cluster_std[0.4,0.2,0.2,0.2],random_state23)# 3. for循环遍历, 获取到每个K值, 计算对应的ch值, 并添加到ch_list列表中forkinrange(2,100):# 考虑簇外, 至少2个簇# 3.1 创建KMeans对象, 指定K值, 迭代次数, 随机种子estimatorKMeans(n_clustersk,random_state23)# 3.2 训练模型estimator.fit(x)# 3.3 模型预测y_predestimator.predict(x)# 3.4 获取到每个ch值ch_valuecalinski_harabasz_score(x,y_pred)# 3.5 把ch值添加到ch_list列表中ch_list.append(ch_value)# 4. 绘制ch曲线 - 数据的可视化# 4.1 创建画布, 指定画布大小plt.figure(figsize(20,10))# 4.2 设置标题plt.title(ch value)# 4.3 设置x轴刻度plt.xticks(range(0,100,3))# 4.4 添加x轴, y轴标签plt.xlabel(k)plt.ylabel(ch)# 4.5 绘制网格plt.grid()# 4.6 绘制折线图# 参1: K值, 参2: 该K值对应的ch值plt.plot(range(2,100),ch_list)# 4.7 显示折线图plt.show()# 4. 测试if__name____main__:# dm01_sse()# dm02_sc()dm03_ch()4. 案例演示已知客户性别、年龄、年收入、消费指数需求对客户进行分析找到业务突破口寻找黄金客户数据集共包含顾客的数据, 数据共有 4 个特征, 数据共有 200 条。接下来使用聚类算法对具有相似特征的的顾客进行聚类并可视化聚类结果。 案例: 基于用户的年收入和消费指数, 根据用户的相似性进行聚类 # 导包fromsklearn.clusterimportKMeansimportmatplotlib.pyplotaspltfromsklearn.metricsimportcalinski_harabasz_score,silhouette_scoreimportpandasaspd# 1. 定义函数, 找聚类的脂心数(K值)defdm01_find_k():# 1. 加载数据集dfpd.read_csv(data/customers.csv)# df.info()# print(df.head())# 2. 定义sse_list, sc_list, 记录不同k值评估效果sse_list[]# sse: 只考虑簇内, 越小越好sc_list[]# sc: 考虑簇内和簇间, 越大越好# 抽取特征xdf.iloc[:,3:5]# print(x.head())# 3. 定义for循环, 训练不同k值的评估效果forkinrange(2,20):# 4. 创建模型对象estimatorKMeans(n_clustersk,max_iter100,random_state23)# 5. 模型训练estimator.fit(x)# 6. 模型预测y_predestimator.predict(x)# 7. 分别把评分添加到对应的列表中sse_list.append(estimator.inertia_)sc_list.append(silhouette_score(x,y_pred))# 4. 绘制折线, 看看K值哪个最好plt.figure(figsize(20,10))plt.plot(range(2,20),sse_list,labelSSE)plt.show()plt.figure(figsize(20,10))plt.plot(range(2,20),sc_list,labelSC)plt.show()# 2. 定义函数, 实现: 模型训练, 模型预测, 模型评估defdm02_train_predict_evaluate():# 1. 加载数据集dfpd.read_csv(data/customers.csv)# 2. 提取特征xdf.iloc[:,3:5]# print(x.head())# 3. 模型训练. k5是刚才通过sse 肘部法, SC轮廓系数获取出来的estimatorKMeans(n_clusters5,max_iter100,random_state23)estimator.fit(x)# 4. 模型预测y_predestimator.predict(x)print(f模型的预测结果为:{y_pred})# 5. 绘制5个簇的样本点 - 散点图plt.scatter(x.values[y_pred0,0],x.values[y_pred0,1],cr,labelStandard)plt.scatter(x.values[y_pred1,0],x.values[y_pred1,1])plt.scatter(x.values[y_pred2,0],x.values[y_pred2,1])plt.scatter(x.values[y_pred3,0],x.values[y_pred3,1])plt.scatter(x.values[y_pred4,0],x.values[y_pred4,1])# 6. 绘制5个簇的质心 - 散点图plt.scatter(estimator.cluster_centers_[:,0],estimator.cluster_centers_[:,1],cblack,labelCentroids)# 7. 设置标题, x轴, y轴标签plt.title(Clusters of Customers)plt.xlabel(Annual Income(k$))plt.ylabel(Spending Score(1-100))plt.legend()plt.show()# 3. 测试if__name____main__:# dm01_find_k()dm02_train_predict_evaluate()