Kmeans

聚类算法(无监督的数据挖掘算法)

作用

  1. 将数据实现分割
  2. 用于异常点的监控

分类

  1. Kmeans聚类
  2. K中心聚类
  3. 谱系聚类
  4. EM聚类算法
  5. 基于密度的聚类
  6. 基于网格的聚类

Kmeans聚类分析

利用距离远近的思想将目标数据剧为指定的k个簇,簇类样本越相似,表明簇类效果越好。

Kmeans 具体实现

  • 从数据中随机挑选k个样本点作为原始的簇中心。
  • 计算剩余样本与簇中心的距离,并把各样本标记为离k个簇中心最近的类别。
  • 重新计算各簇中样本点的均值,并以均值作为新的k个簇中心。
  • 不断重复(2)和(3),直到簇中心的变化趋于稳定,形成最终的k个簇。

过程示意图

Kmeans_第1张图片

子图1,从原始样本中随机挑选两个数据点作为初始的簇中心,即子图中的两个五角星;子图2,将其余样本点与这两个五角星分别计算距离(距离的度量可选择欧氏距离、曼哈顿距离等),然后将每个样本点划分到离五角星最近的簇,即子图中按虚线隔开的两部分;子图3,计算两个簇内样本点的均值,得到新的簇中心,即子图中的五角星;子图4,根据新的簇中心,继续计算各样本与五角星之间的距离,得到子图5的划分结果和子图6中新的簇内样本均值;以此类推,最终得到理想的聚类效果,如子图9所示,图中的五角星即最终的簇中心点。

算法实现

KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001,
    precompute_distances='auto', verbose=0, random_state=None,
    copy_x=True, n_jobs=1, algorithm='auto')
  • n_clusters:用于指定聚类的簇数。
  • init:用于指定初始的簇中心设置方法,如果为’k-means++’,则表示设置的初始簇中心之间相距较远;如果为’random’,则表示从数据集中随机挑选k个样本作为初始簇中心;如果为数组,则表示用户指定具体的簇中心。
  • n_init:用于指定Kmeans算法运行的次数,每次运行时都会选择不同的初始簇中心,目的是防止算法收敛于局部最优,默认为10。
  • max_iter:用于指定单次运行的迭代次数,默认为300。
  • tol:用于指定算法收敛的阈值,默认为0.0001。
  • precompute_distances:bool类型的参数,是否在算法运行之前计算样本之间的距离,默认为’auto’,表示当样本量与变量个数的乘积大于1200万时不计算样本间距离。
  • verbose:通过该参数设置算法返回日志信息的频度,默认为0,表示不输出日志信息;如果为1,就表示每隔一段时间返回一次日志信息。
  • random_state:用于指定随机数生成器的种子。
  • copy_x:bool类型参数,当参数precompute_distances为True时有效,如果该参数为True,就表示提前计算距离时不改变原始数据,否则会修改原始数据。
  • n_jobs:用于指定算法运算时使用的CPU数量,默认为1,如果为-1,就表示使用所有可用的CPU。
  • algorithm:用于指定Kmeans的实现算法,可以选择’auto’‘full’和’elkan’,默认为’auto’,表示自动根据数据特征选择运算的算法。

原理

对于每个簇而言,就是保证这些簇的**离差平方和(方差)**的总和最小。

当簇的个数与样本个数一致时(每个样本代表一个类),就可以得到最小值0。确实不假,簇被划分得越细,总和肯定会越小,但这样的簇不一定是合理的。所谓合理,就是随着簇的增加,离差平方和之和趋于稳定(波动小于某个给定的阈值)。

该函数的表达式为:

Kmeans_第2张图片

cj表示第j个簇的簇中心,xi属于第j个簇的样本i,nj表示第j个簇的样本总量。对于该目标函数而言,cj是未知的参数。由于J为凸函数,可以通过求导获得cj。

Kmeans_第3张图片

Kmeans_第4张图片

只有当簇中心cj为簇内的样本均值时,目标函数才会达到最小,获得稳定的簇。推导出来的簇中心正好与Kmeans聚类思想中的样本均值相吻合。

最佳k值的确定

对于Kmeans算法来说,如何确定簇数k值是一个至关重要的问题。

分类

  • 拐点法
  • 轮廓系数法
  • 间隔统计量法

拐点法

Kmeans聚类算法的目标函数J,随着簇数量的增加,簇中的样本量会越来越少,进而导致目标函数J的值也会越来越小。通过可视化方法,重点关注的是斜率的变化,当斜率由大突然变小时,并且之后的斜率变化缓慢,则认为突然变化的点就是寻找的目标点,因为继续随着簇数k的增加,聚类效果不再有大的变化。

绘制三组1000个点的散点图。

# 导入第三方包
import pandas as pd
import numpy as np  
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics

# 随机生成三组二元正态分布随机数 
"""
函数可使得随机数具有预见性,
即当参数相同时使得每次生成的随机数相同;
"""
np.random.seed(1234)
# 均值矩阵
mean1 = [0.5, 0.5]
# 协方差矩阵
cov1 = [[0.3, 0], [0, 0.3]]
#生成1000个点,满足mean1和cov1
x1, y1 = np.random.multivariate_normal(mean1, cov1, 1000).T

mean2 = [0, 8]
cov2 = [[1.5, 0], [0, 1]]
x2, y2 = np.random.multivariate_normal(mean2, cov2, 1000).T

mean3 = [8, 4]
cov3 = [[1.5, 0], [0, 1]]
x3, y3 = np.random.multivariate_normal(mean3, cov3, 1000).T

# 绘制三组数据的散点图
plt.scatter(x1,y1)
plt.scatter(x2,y2)
plt.scatter(x3,y3)
# 显示图形
plt.show()

Kmeans_第5张图片

虚拟的数据呈现三个簇,接下来基于这个虚拟数据,使用拐点法,绘制簇的个数与总的簇内离差平方和之间的折线图,确定该聚为几类比较合适。

# 构造自定义函数,用于绘制不同k值和对应总的簇内离差平方和的折线图
def k_SSE(X, clusters):
    # 选择连续的K种不同的值
    K = range(1,clusters+1)
    # print(K)
    # 构建空列表用于存储总的簇内离差平方和
    TSSE = []
    for k in K:
        # 用于存储各个簇内离差平方和
        SSE = []
        # 传入簇数
        kmeans = KMeans(n_clusters=k)
        # 传入数据
        kmeans.fit(X)
        # 返回簇标签(返回array,即表示每个ID所属的簇)
        labels = kmeans.labels_
        # print(k,"==",labels)
        # 返回簇中心(返回k*2的array)
        centers = kmeans.cluster_centers_
        # print(k,"==",centers)
        # 计算各簇样本的离差平方和,并保存到列表中
        for label in set(labels):
            # append 将所有的参数视为一个列表元素插入到列表尾部
            SSE.append(np.sum((X.loc[labels == label,]-centers[label,:])**2))
        # 计算总的簇内离差平方和 
        TSSE.append(np.sum(SSE))

    # 中文和负号的正常显示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 设置绘图风格
    plt.style.use('ggplot')
    # 绘制K的个数与GSSE的关系
    plt.plot(K, TSSE, 'b*-')
    plt.xlabel('簇的个数')
    plt.ylabel('簇内离差平方和之和')
    # 显示图形
    plt.show()

# 将三组数据集汇总到数据框中
# np.concatenate 按轴axis连接array组成一个新的array
# pd.DataFrame Pandas库中的一种数据结构,它类似excel,是一种二维表。
X = pd.DataFrame(np.concatenate([np.array([x1,y1]),np.array([x2,y2]),np.array([x3,y3])], axis = 1).T)
# 自定义函数的调用
k_SSE(X, 15)

Kmeans_第6张图片

当簇的个数为3时形成了一个明显的拐点,因为k值从1到3时,折线的斜率都比较大,但是k值为4时斜率突然就降低了很多,并且之后的簇对应的斜率都变动很小。所以,合理的k值应该为3。

轮廓系数法

考虑了簇的密集性分散性两个信息,如果数据集被分割为理想的k个簇,那么对应的簇内样本会很密集,而簇间样本会很分散。

轮廓系数的计算公式可以表示为:

在这里插入图片描述

Kmeans_第7张图片

a(i)体现了簇内的密集性,代表样本i与同簇内其他样本点距离的平均值;b(i)反映了簇间的分散性,它的计算过程是,样本i与其他非同簇样本点距离的平均值,然后从平均值中挑选出最小值。当S(i)接近于-1时,说明样本i分配的不合理,需要将其分配到其他簇中;当S(i)近似为0时,说明样本i落在了模糊地带,即簇的边界处;当S(i)近似为1时,说明样本i的分配是合理的。

需要对所有点的轮廓系数求平均值,得到总轮廓系数。当总轮廓系数小于0时,说明聚类效果不佳;当总轮廓系数接近于1时,说明簇内样本的平均距离a非常小,而簇间的最近距离b非常大,进而表示聚类效果非常理想。

有关轮廓系数的计算,可以直接调用sklearn子模块metrics中的函数,即silhouette_score。需要注意的是,该函数接受的聚类簇数必须大于等于2。

# 构造自定义函数,用于绘制不同k值和对应轮廓系数的折线图
def k_silhouette(X, clusters):
    K = range(2,clusters+1)
    # 构建空列表,用于存储个中簇数下的轮廓系数
    S = []
    for k in K:
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        labels = kmeans.labels_
        # 调用字模块metrics中的silhouette_score函数,计算轮廓系数
        # sklearn.metrics.silhouette_score(X, labels, *, metric='euclidean', sample_size=None, random_state=None, **kwds)
        # 适用于二维
        S.append(metrics.silhouette_score(X, labels, metric='euclidean'))

    # 中文和负号的正常显示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 设置绘图风格
    plt.style.use('ggplot')    
    # 绘制K的个数与轮廓系数的关系
    plt.plot(K, S, 'b*-')
    plt.xlabel('簇的个数')
    plt.ylabel('轮廓系数')
    # 显示图形
    plt.show()
    
# 自定义函数的调用
k_silhouette(X, 15)

Kmeans_第8张图片

间隔统计量法(Gap Statistic)

学习中…

Kmeans聚类的应用

注意事项

  1. 聚类前必须指定具体的簇数k值,如果k值是已知的,可以直接调用cluster子模块中的Kmeans类,对数据集进行分割;如果k值是未知的,可以根据行业经验或前面介绍的三种方法确定合理的k值。

  2. 对原始数据集做必要的标准化处理,由于Kmeans的思想是基于点之间的距离实现“物以聚类”的,所以,如果原始数据集存在量纲上的差异,就必须对其进行标准化的预处理,否则可以不用标准化。数据集的标准化处理可以借助于sklearn子模块preprocessing中的scale函数或minmax_scale实现。

你可能感兴趣的:(大创,知识点)