机器学习篇-聚类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()
结果图
更多推荐





所有评论(0)