一篇文章讲清楚:K-Means聚类算法

通过这篇文章,我们需要知道什么是聚类,了解聚类算法的应用场景,知道聚类算法的分类,了解Kmeans算法的API,动手实践Kmeans算法,能掌握K-means聚类的实现步骤,了解 SSE 聚类评估指标,了解 SC 聚类评估指标,了解 CH 聚类评估指标,了解肘方法的作用;能使用聚类算法完成客户案例分析,知道怎么求最佳K值。

一、聚类算法-概念

1.什么是聚类算法?
•根据样本之间的相似性,将样本划分到不同的类别中;不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。
•聚类算法的目的是在没有先验知识的情况下,自动发现数据集中的内在结构和模式。
•无监督学习算法

2.使用不同的聚类准则,产生的聚类结果不同

3.聚类算法在现实生活中的应用

二、聚类算法分类

1.根据聚类颗粒度分类

2.根据实现方法分类
•K-means:按照质心分类,主要介绍K-means,通用、普遍
•层次聚类:对数据进行逐层划分,直到达到聚类的类别个数
•DBSCAN聚类是一种基于密度的聚类算法
•谱聚类是一种基于图论的聚类算法

三、聚类算法API

sklearn.cluster.KMeans(n_clusters=8)
•参数: n_clusters:开始的聚类中心数量

整型,缺省值=8,生成的聚类数,即产生的质心(centroids)数。
•方法

estimator.fit(x)

estimator.predict(x)

estimator.fit_predict(x)

计算聚类中心并预测每个样本属于哪个类别,相当于先调用fit(x),然后再调用predict(x)

四、案例-使用KMeans模型数据探索聚类

随机创建不同二维数据集作为训练集,并结合k-means算法将其聚类,尝试分别聚类不同数量的簇,并观察聚类效果:

1.聚类步骤

复制代码
"""
案例:
    演示 KMeans 聚类算法 入门案例。

Kmeans简介:
    它属于 无监督学习,即:有特征,无标签,根据样本间的相似性进行划分。
    所谓的相似性 可以理解为 就是 距离,例如:欧式距离,曼哈顿(城市街区)距离,切比雪夫距离,闵式距离……

    一般大厂,项目初期在没有 先备知识(标签)的情况下可能会用。
"""


# 导包
from sklearn.cluster import KMeans                      # 聚类的API,采用指定 质心 来分簇
import matplotlib.pyplot as plt                         # 绘图的
from sklearn.datasets import make_blobs                 # 默认会按照高斯分布(正态分布)生成数据集,只需要指定均值,标准差
from sklearn.metrics import calinski_harabasz_score     # 评价指标,值越大,聚类效果越好。


# 1.准备数据集
x, y = make_blobs(
    n_samples=1000,     # 参1:样本数量
    n_features=2,       # 参2:样本特征数量(2列)
    centers=[[-1,-1], [0,0], [1,1], [2,2]],          # 参3:样本标签数量
    cluster_std=[0.4,0.2,0.3,0.4],    # 参4:标准差
    random_state=23     # 参5:随机种子
)
# print(x)
# print(y)
# 2.绘制上述的图形
# 参1:横坐标,参2:纵坐标,参3:颜色
plt.scatter(x[:,0],x[:,1])
plt.show()

# 3.创建KMeans对象
# 参1:聚类的数量,参2:随机种子
estimator = KMeans(n_clusters=4, random_state=23)

# 4.模型训练 和 预测
y_pred = estimator.fit_predict(x)  # 预测值

# 5.绘制预测结果
plt.scatter(x[:,0],x[:,1],c=y_pred)
plt.show()

# 6.评价指标
print(f'评价指标(评分):{calinski_harabasz_score(x,y_pred)}')  # 越大越好

五、聚类算法****API

六、KMeans算法实现流程

1 、事先确定常数K ,常数K意味着最终的聚类类别数

2、随机选择 K 个样本点作为初始聚类中心

3、计算每个样本到 K 个中心的距离,选择最近的聚类中心点作为标记类别

4、根据每个类别中的样本点,重新计算出新的聚类中心点(平均值),如果计算得出的新中心点与原中心点一样则停止聚类,否则重新进行第 3 步过程,直到聚类中心不再变化

七、KMeans算法实现流程 -- 举例

已知数据如下表所示,按照KMeans算法实现流程进行聚类:

随机设置K个特征空间内的点作为初始的聚类中心(本案例中设置p1和p2)

2、对于其他每个点计算到K个中心的距离,选择最近的一个聚类中心点作为标记类别

3、接着对标记的聚类中心,重新计算每个聚类的新中心点(平均值)

4、如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束,否则重新进行第二步过程【经过判断,需要重复上述步骤,开始新一轮迭代】

5、当每次迭代结果不变时,认为算法收敛,聚类完成

KMeans****算法实现流程-总结

1 、事先确定常数K ,常数K意味着最终的聚类类别数

2、随机选择 K 个样本点作为初始聚类中心

3、计算每个样本到 K 个中心的距离,选择最近的聚类中心点作为标记类别

4、根据每个类别中的样本点,重新计算出新的聚类中心点(平均值),如果计算得出的新中心点与原中心点一样则停止聚类,否则重新进行第 3步过程,直到聚类中心不再变化

七、误差平方和SSE (The sum of squares due to error)

SSE 越小,表示数据点越接近它们的中心,聚类效果越好

八、"肘"方法 (Elbow method) - K值确定

•"肘" 方法通过 SSE 确定 n_clusters 的值
•对于n个点的数据集,迭代计算 k from 1 to n,每次聚类完成后计算 SSE
•SSE 是会逐渐变小的,因为每个点都是它所在的簇中心本身。
•SSE 变化过程中会出现一个拐点,下降率突然变缓时即认为是最佳 n_clusters 值。
•在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别。

from sklearn.cluster import KMeans

import matplotlib.pyplot as plt

from sklearn.datasets import make_blobs

from sklearn.metrics import calinski_harabasz_score

def dm01_SSE误差平方和求模型参数():
sse_list = \[\]

#产生数据random_state*=22**固定好*x, y = make_blobs(n_samples=1000, n_features=2, centers=\[-1, -1, 0, 0, 1, 1, 2, 2],
cluster_std=0.4, 0.2, 0.2, 0.2, random_state=22)

for clu_num in range(1, 100):
my_kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=0)
my_kmeans.fit(x)
sse_list.append(my_kmeans.inertia_ ) #获取sse**的值plt.figure(figsize=(18, 8), dpi=100)
plt.xticks(range(0, 100, 3), labels=range(0, 100, 3))
plt.grid()
plt.title('sse')
plt.plot(range(1, 100), sse_list, 'or-')
plt.show()
#通过图像可观察到n_clusters*=4sse开始下降趋缓**,最佳值4*

八、SC轮廓系数法(Silhouette Coefficient)

轮廓系数法考虑簇内的内聚程度(Cohesion),簇外的分离程度(Separation)。其计算过程如下

复制代码
"""
案例:
    演示聚类算法的评估指标,即:SSE + 肘部法, SC轮廓系数法, CH轮廓系数法
聚类算法的评估指标:
    思路1:SSE + 肘部法
        SSE:
            所有簇的 所有样本到该簇的质心的 误差平方和。
        特点:
            随着K值的增加,SSE值会逐渐减少
        目标:
            SSE值越小,代表簇内样本越聚集,内聚程度越高。
    肘部法:
        K值增大,SSE值会随之减小,下降梯度陡然变缓的时候,那个K值,就是我们要的最佳值。
    思路2:SC轮廓系数
        考虑簇内 -> 聚集程度,越小越好
        考虑簇外 -> 分离程度,越大越好
    思路3:CH轮廓系数
        考虑簇内 -> 聚集程度,越小越好
        考虑簇外 -> 分离程度,越大越好
        考虑k值 -> k值越小,代表簇内样本越聚集,内聚程度越高
        
"""

# 导包
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.metrics import calinski_harabasz_score, silhouette_score


# 1. 定义函数,演示:SSE + 肘部法
def dm01_sse():
    # 1.定义SSE列表,记录:每个K值的 SSE值
    sse_list = []

    # 2.生成数据集。
    x, y = make_blobs(
        n_samples=1000,
        n_features=2,
        centers=[[-1, -1], [0, 0], [1, 1],[2,2]],
        cluster_std=[0.4, 0.2, 0.2, 0.2],
        random_state=23
    )

    # 3.for训练遍历,获取到每个K值,计算其对应的 sse值,并添加到sse_list列表中
    for k in range(1,100):
        # 3.1 创建KMeans对象,参1:簇的数量,参2:最大迭代数,参3:固定随机种子。
        estimator = KMeans(n_clusters=k, max_iter=100, random_state=23)
        # 3.2 训练模型
        estimator.fit(x)
        # 3.3 模型预测
        # 3.4 获取到每个簇的SSE值
        sse_value = estimator.inertia_
        # 3.5 将每个K值对应的sse值,添加到sse_list列表中
        sse_list.append(sse_value)

    # 4.绘制SSE曲线 -> 数据的可视化。
    # print(sse_list)
    # 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(True)
    # 4.6 绘制折线图。
    plt.plot(range(1,100),sse_list)
    plt.show()

九、聚类效果评估 -- CH轮廓系数法(Calinski-Harabasz Index)

通过图像可观察到 n_clusters=4 取到最大值; 最佳值4

from sklearn.cluster import KMeans

import matplotlib.pyplot as plt

from sklearn.datasets import make_blobs

from sklearn.metrics import calinski_harabasz_score

def dm03_ch系数():
tmp_list = \[\]

#产生数据random_state*=22**固定好*x, y = make_blobs(n_samples=1000, n_features=2, centers=\[-1, -1, 0, 0, 1, 1, 2, 2],
cluster_std=0.4, 0.2, 0.2, 0.2, random_state=22)

for clu_num in range(2, 100):
my_kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=0)
my_kmeans.fit(x)
ret = my_kmeans.predict(x)

tmp_list.append(calinski_harabasz_score(x, ret)) *#*sc

plt.figure(figsize=(18, 8), dpi=100)
plt.xticks(range(0, 100, 3), labels=range(0, 100, 3))
plt.grid()
plt.title('ch')
plt.plot(range(2, 100), tmp_list, 'og-')
plt.show()

通过图像可观察到 n_clusters=4 取到最大值; 最佳值4

十、总结

十一、案例:顾客数据聚类分析
•已知:客户性别、年龄、年收入、消费指数
•需求:对客户进行分析,找到业务突破口,寻找黄金客户


•客户分群效果展示:

1.首先寻找"K"值

复制代码
"""
案例:
    基于用户的 年收入 和消费指数,根据用户的 相似性 进行 聚类

"""
import os
# 解决Windows KMeans MKL警告
os.environ["OMP_NUM_THREADS"] = "1"
# 导包
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.metrics import calinski_harabasz_score, silhouette_score

# 1.定义函数,找 聚类的 质心数(k值)
def dm01_find_k():
    # 1.加载数据集
    df = pd.read_csv('./data/customers.csv')
    # df.info()

    # 2.定义 sse_list, sc_list, 记录:不同k值的 评估效果
    sse_list = []     # sse: 只考虑簇内,越小越好
    sc_list = []      # sc: 考虑 簇内和簇间,越大越好

    # 抽取特征
    x = df.iloc[:, 3:5]
    print(x)
    # y = df.iloc[:, -1]

    # 3.定义for训练,测试不同k值的 评估效果
    for k in range(2,20):
        # 4.创建(KMeans 模型)对象。
        estimator = KMeans(n_clusters=k, max_iter=100, random_state=10)
        # 5.模型训练
        estimator.fit(x)
        # 6.模型预测
        y_pred = estimator.predict(x)
        # 7.分别把评分添加到对应的列表中。
        sse_list.append(estimator.inertia_)
        sc_list.append(silhouette_score(x,y_pred))

    # 4. 绘制折线图,看看k值 哪个最好
    plt.figure(figsize=(10,8))
    plt.plot(range(2,20),sse_list,label='SSE')
    plt.show()
    plt.figure(figsize=(10, 8))
    plt.plot(range(2,20),sc_list,label='Silhouette')
    plt.show()

    # 结论:k=5的时候,效果最好

2.模型聚类

复制代码
# 2.定义函数,实现:模型训练,模型预测,模型评估
def dm02_train_predict_evaluate():
    # 1.加载数据集
    df = pd.read_csv('./data/customers.csv')
    # 2.提取特征
    x = df.iloc[:, 3:5]
    # 3.创建模型
    my_model = KMeans(n_clusters=5,max_iter= 100,random_state=23)
    # 4.训练模型
    my_model.fit(x)
    # 5.模型预测
    y_pred = my_model.predict(x)
    # 6.绘制5个簇的 样本 -> 散点图
    plt.figure(figsize=(10,8))
    plt.scatter(x.values[y_pred == 0, 0], x.values[y_pred == 0, 1], label='HG')    # 0号簇
    plt.scatter(x.values[y_pred == 1, 0], x.values[y_pred == 1, 1])    # 1号簇
    plt.scatter(x.values[y_pred == 2, 0], x.values[y_pred == 2, 1])    # 2号簇
    plt.scatter(x.values[y_pred == 3, 0], x.values[y_pred == 3, 1])    # 3号簇
    plt.scatter(x.values[y_pred == 4, 0], x.values[y_pred == 4, 1])    # 4号簇

    # 7.绘制5个簇的 质心 -> 散点图
    # print(my_model.cluster_centers_)           # 5个质心的坐标
    plt.scatter(my_model.cluster_centers_[:, 0], my_model.cluster_centers_[:, 1], c='black')
    plt.title('Cluster of Clusters')
    plt.xlabel('Annual Income (k$)')
    plt.ylabel('Estimated Income (1-100)')
    plt.legend()
    plt.show()


# 3.测试
if __name__ == '__main__':
    # dm01_find_k()
    dm02_train_predict_evaluate()
相关推荐
白狐_7981 小时前
408 数据结构|KMP做题方法:next、nextval和高频易错点
数据结构·算法
月华路1 小时前
《模型不玄学》第20章 两种评估视角
人工智能·算法·机器学习
禹凕2 小时前
快速幂算法详解与实战
python·算法
xxwl5852 小时前
高斯消元法异或版
人工智能·算法·机器学习
sylviiiiiia2 小时前
leetcode hot 100
python·算法·leetcode
OPEN-F2 小时前
ROS2系列教程:Gazebo插件(关节控制/IMU/激光雷达)
c++·python·数码相机·算法·机器人
luj_17682 小时前
虚实交融中的真实人物塑造
c语言·开发语言·网络·经验分享·算法
haolin123.3 小时前
STL vector底层揭秘:从构造到迭代器失效
开发语言·c++·算法
shehuiyuelaiyuehao3 小时前
算法37,位运算,两个整数之和(不用+符号)
算法