机器学习篇-day08-聚类Kmeans算法
一. 聚类算法简介
概念
无监督学习算法
根据样本之间的相似性,将样本划分到不同的类别中;不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。
聚类算法的目的是在没有先验知识的情况下,自动发现数据集中的内在结构和模式。
使用不同的聚类准则, 产生的聚类结果不同
应用场景
聚类算法分类
根据聚类颗粒度分类
根据实现方法分类
-
K-means:按照质心分类,主要介绍K-means,通用、普遍
-
层次聚类:对数据进行逐层划分,直到达到聚类的类别个数
-
DBSCAN聚类是一种基于密度的聚类算法
-
谱聚类是一种基于图论的聚类算法
总结
聚类概念
无监督学习算法,主要用于将相似的样本自动归到一个类别中;计算样本和样本之间的相似性,一般使用欧式距离
聚类分类
颗粒度:粗聚类、细聚类。
实现方法: K-means聚类、层次聚类、 DBSCAN聚类、谱聚类
二. API
Kmeans算法的API
Kmeans-API实践
聚类算法API
构造数据API
数据-结果
流程
代码
import os os.environ["OMP_NUM_THREADS"] = '4' # 解决内存泄露警告 from sklearn.cluster import KMeans from sklearn.datasets import make_blobs from sklearn.metrics import calinski_harabasz_score import matplotlib.pyplot as plt # 1. 构建数据集 # x是样本(点的横纵坐标), y是标签 x, y = make_blobs( n_samples=1000, # 样本数 n_features=2, # 特征数: x, y centers=[[-1, -1], [0, 0], [1, 1], [2, 2]], # 聚类中心, 也可以写数字表示中心点的数量 cluster_std=[0.4, 0.2, 0.2, 0.2], # 聚类标准差, 默认为1, 也可以写数字表示所有点的标准差 random_state=21 ) # print(x) # print(y) # 绘图显示数据集 plt.figure() plt.scatter(x[:, 0], x[:, 1], marker='o') plt.show() # 2. 模型训练预测 model = KMeans( n_clusters=4, # 蕨类中心的数量 random_state=21 ) y_pred = model.fit_predict(x) # 3. 显示聚类效果 plt.scatter(x[:, 0], x[:, 1], c=y_pred) plt.show() # 4. 模型评估 print(calinski_harabasz_score(x, y_pred))
结果
三. ★Kmeans实现流程
★实现流程原理
-
事先确定
常数K
,常数K意味着最终的聚类类别数
-
随机选择
K 个样本点
作为初始聚类中心 -
计算
每个样本到 K 个中心的距离
,选择最近的聚类中心点作为标记类别 -
根据每个类别中的样本点,
重新计算出新的聚类中心点
(各聚类类别内点的平均值),如果计算得出的新中心点与原中心点一样则停止聚类
,否则重新进行第 2 步过程
,直到聚类中心不再变化
举例说明
原始数据
流程
-
随机设置K个特征空间内的点作为初始的聚类中心(本案例中设置p1和p2)
-
对于其他每个点计算到K个中心的距离,选择最近的一个聚类中心点作为标记类别
-
接着对标记的聚类中心,
重新计算每个聚类的新中心点
(平均值) -
如果计算得出的
新中心点与原中心点一样
(质心不再移动),那么结束,否则重新进行第二步过程【经过判断,需要重复上述步骤,开始新一轮迭代】
总结
四. ★★模型评估方法
SSE聚类评估指标👇
原理
误差平方和SSE (The sum of squares due to error)
SSE 越小,表示数据点越接近它们的中心,聚类效果越好
代码演示-肘方法-SSE
肘方法确定K值(n_clusters=聚类中心点个数(肘点))
import os os.environ["OMP_NUM_THREADS"] = '4' # 解决内存泄露警告 from sklearn.cluster import KMeans from sklearn.datasets import make_blobs from sklearn.metrics import calinski_harabasz_score import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 正常显示汉字 plt.rcParams['axes.unicode_minus'] = False # 正常显示负号 # 1. 构建数据集 # data是样本(点的横纵坐标), label是标签 data, label = make_blobs( n_samples=1000, # 样本数 n_features=2, # 特征数: x, y坐标, 特征的两列 centers=[[-1, -1], [0, 0], [1, 1], [2, 2]], # 聚类中心, 也可以写数字表示中心点的数量 cluster_std=[0.4, 0.2, 0.2, 0.2], # 聚类标准差, 默认为1, 也可以写数字表示所有点的标准差 random_state=21 ) sse_list = [] # 2. 遍历不同聚类中心数量, 计算sse for clu_num in range(1, 100): kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=21, n_init='auto') kmeans.fit(data) sse_list.append(kmeans.inertia_) # 误差平方和(sse) # print(kmeans.inertia_) # 根据中心点个数作为横坐标, 误差平方和(sse)作为纵坐标, 画出sse曲线 plt.figure(figsize=(20, 10), dpi=100) plt.xticks(range(1, 100, 3), label=range(1, 100, 3)) plt.xlabel('n_clusters') plt.ylabel('sse') plt.title('SSE肘方法') plt.grid() plt.plot(range(1, 100), sse_list, 'or-') plt.show()
结果图
肘方法的原理-K值
“肘”方法 (Elbow method) - K值确定(聚类中心的个数)
"肘"方法通过SSE
确定n_clusters(聚类中心的个数)的值
-
对于n个点的数据集,迭代计算 k from1 to n,每次聚类完成后计算 SSE
-
SSE 是会逐渐变小的,因为每个点都是它所在的簇中心本身。
-
★SSE 变化过程中会出现一个拐点,
下降率突然变缓时即认为是最佳 n_clusters 值。
-
在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别。
SC聚类评估指标👆
原理
SC轮廓系数法(Silhouette Coefficient)
轮廓系数法考虑簇内的内聚程度(Cohesion)
,簇外的分离程度(Separation)
. 其计算过程如下
-
对计算每一个样本
i 到同簇内其他样本的平均距离 ai
,该值越小,说明簇内的相似程度越大 -
计算每一个样本
i 到最近簇 j 内的所有样本的平均距离 bij
,该值越大,说明该样本越不属于其他簇j -
根据下面公式计算该样本的轮廓系数:S = (b -a)/(max(a, b))
-
计算所有样本的平均轮廓系数
-
轮廓系数的范围为:[-1, 1],
SC值越大聚类效果越好
代码演示
sc_list = [] for clu_num in range(2, 100): kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=21, n_init='auto') kmeans.fit(data) y_pred = kmeans.predict(data) sc_list.append(silhouette_score(data, y_pred)) plt.figure(figsize=(20, 10), dpi=100) plt.xticks(range(1, 100, 3), label=range(1, 100, 3)) plt.xlabel('n_clusters') plt.ylabel('sc') plt.title('SC轮廓系数法') plt.grid() plt.plot(range(2, 100), sc_list, 'or-') plt.show()
结果图
CH聚类评估指标👆
原理
聚类效果评估 – CH轮廓系数法(Calinski-Harabasz Index)
CH 系数考虑簇内的内聚程度
、簇外的离散程度
、质心的个数
CH越大越好
代码演示
ch_list = [] for clu_num in range(2, 100): kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=21, n_init='auto') kmeans.fit(data) y_pred = kmeans.predict(data) ch_list.append(calinski_harabasz_score(data, y_pred)) plt.figure(figsize=(20, 10), dpi=100) plt.xticks(range(1, 100, 3), label=range(1, 100, 3)) plt.xlabel('n_clusters') plt.ylabel('CH') plt.title('CH轮廓系数法') plt.grid() plt.plot(range(2, 100), ch_list, 'ob-') plt.show()
结果图
总结
五. 案例-顾客数据聚类分析
需求
代码
# -*- coding: utf-8 -*- # @FileName : 03-顾客数据分析.py # @Author : YuanLitao # @Time : 2024/10/15 16:06 import os os.environ["OMP_NUM_THREADS"] = '1' # 解决内存泄露警告 import pandas as pd import matplotlib.pyplot as plt import numpy as np from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score plt.rcParams['font.sans-serif'] = ['SimHei'] # 正常显示汉字 plt.rcParams['axes.unicode_minus'] = False # 正常显示负号 def demo01_find_best_k(): # 数据获取 data = pd.read_csv('data/customers.csv') # 获取特征 # 根据顾客的收入和消费水平对客户进行分类 x = data.iloc[:, [3, 4]] # 循环创建多个分类中心点, 找到最优的分类中心点 sse_list = [] sc_list = [] for i in range(2, 21): kmeans = KMeans(n_clusters=i) kmeans.fit(x) y_pred = kmeans.predict(x) sse_list.append(kmeans.inertia_) sc_list.append(silhouette_score(x, y_pred)) # 3. 数据可视化 plt.figure(figsize=(20, 10), dpi=100) plt.title("sse") plt.xticks(range(2, 21)) plt.plot(range(2, 21), sse_list, 'or-') plt.show() plt.figure(figsize=(20, 10), dpi=100) plt.title("sc轮廓系数") plt.xticks(range(2, 21)) plt.plot(range(2, 21), sc_list, 'or-') plt.show() def demo02_kmeans(): # 数据获取 data = pd.read_csv('data/customers.csv') # 获取特征 x = data.iloc[:, [3, 4]] # 模型训练 kmeans = KMeans(n_clusters=5, random_state=21) kmeans.fit(x) # 模型预测 y_pred = kmeans.predict(x) print(y_pred) print(kmeans.cluster_centers_) # 可视化 plt.figure(figsize=(20, 10), dpi=100) plt.scatter(x.values[y_pred == 0, 0], x.values[y_pred == 0, 1], s=100, c='red', label='学生用户') # 把类别是1的, 第0类数据,第1列数据, 作为x/y, 传给plt.scatter函数 plt.scatter(x.values[y_pred == 1, 0], x.values[y_pred == 1, 1], s=100, c='blue', label='正常用户') # 把类别是2的, 第0类数据,第1列数据, 作为x/y, 传给plt.scatter函数 plt.scatter(x.values[y_pred == 2, 0], x.values[y_pred == 2, 1], s=100, c='green', label='低消费用户') plt.scatter(x.values[y_pred == 3, 0], x.values[y_pred == 3, 1], s=100, c='cyan', label='普通用户') plt.scatter(x.values[y_pred == 4, 0], x.values[y_pred == 4, 1], s=100, c='magenta', label='黄金用户') plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=300, c='black', label='质心') plt.title('Clusters of customers') plt.xlabel('Annual Income (k$)') plt.ylabel('Spending Score (1-100)') plt.legend() plt.show() if __name__ == '__main__': # demo01_find_best_k() # 看图得k=5时是最优的聚类中心点数量 demo02_kmeans()