python数据挖掘学习笔记——KMeans聚类分析


Kmeans算法是聚类分析中的一种,根据样本在空间中与K个聚类中心的距离来进行分类,每次可分出K个簇并更新聚类中心,通过不断迭代最终确认出K个分类。
笔记为学习过程中总结内容,仅为个人学习使用,若有错误欢迎讨论指出。
参考资料
理论基础参考:西瓜书,《统计学习方法》
实例分析:《python数据分析与挖掘》

性能度量

分类外部指标和内部指标:前者表示聚类结果与参考模型进行比较、后者表示不借助参考模型进行度量。

  1. 外部指标
    i) 给定以下定义:
    复杂晦涩的数学定义这里不做说明,可参考理论书籍。
    给定样本空间中的任意两个向量 x i , x j x_i,x_j xi,xj
    a:两个应该属于同一类的数据样本被正确分在一类了
    b:两个数据样本不属于同一类但还是被错误地分在了一类
    c:两个数据样本应该属于一类但被错误地分在了不同的类
    d:两个应该属于不同类的数据样本被正确地分开了
    ii) 性能度量:
    · R I = a + d a + b + c + d RI=\frac{a+d}{a+b+c+d} RI=a+b+c+da+d
    · F M I = a a + b ⋅ a a + c FMI=\sqrt{\frac{a}{a+b} ·\frac{a}{a+c}} FMI=a+baa+ca
    这两种度量方式均 ∈ [ 0 , 1 ] \in[0,1] [0,1]且越大表示模型越好。
  2. 内部指标
    D B I = 1 k ∑ i = 1 k m a x j ≠ i ( a v g ( C i ) + a v g ( C j ) d c e n ( C i , C j ) ) DBI=\frac{1}{k}\sum_{i=1}^{k}max_{j\not=i}(\frac{avg(C_i)+avg(C_j)}{d_{cen}(C_i,C_j)}) DBI=k1i=1kmaxj=i(dcen(Ci,Cj)avg(Ci)+avg(Cj))
    D I = m i n i ∈ [ i , k ] m i n i ≠ j d m i n ( C i , C j ) m a x l ∈ [ 1 , k ] d i a m ( C l ) DI =min_{i\in[i,k]}min_{i\not=j}\frac{d_{min}(C_i,C_j)}{max_{l\in[1,k]}diam(C_l)} DI=mini[i,k]mini=jmaxl[1,k]diam(Cl)dmin(Ci,Cj)
    其中,avg为簇内样本间的平均距离, d c e n d_{cen} dcen为簇之间的中心距离, d m i n d_{min} dmin为簇之间的最近样本距离, d d i a m d_{diam} ddiam为簇之间的样本最远距离。
    DBI越小越好而DI相反。

距离度量

  1. 连续属性通常用闵可夫斯基距离来定义: d i s t m k ( x i , x j ) = ( ∑ u = 1 n ∣ x i u − x j u ∣ p ) 1 p dist_{mk}(x_i,x_j)=(\sum_{u=1}^{n} \left | x_{iu} - x_{ju} \right | ^{p})^{\frac{1}{p}} distmk(xi,xj)=(u=1nxiuxjup)p1
    p=2时转换为欧氏距离
    p=1时转换为曼哈顿距离
    实际上,scikit-learn库中的KMeans算法采用的是欧氏距离来进行度量,这是因为其它的度量方法不一定能确保收敛性。
  2. 无序属性可采用VDM距离进行度量: V D M p ( a , b ) = ∑ i = 1 k ∣ m u , a , i m u , a − m u , b , i m u , b ∣ p VDM_p(a, b) = \sum_{i=1}^{k}{\left | \frac{m_{u,a,i}}{m_{u,a}} - \frac{m_{u,b,i}}{m_{u,b}}\right |^p} VDMp(a,b)=i=1k mu,amu,a,imu,bmu,b,i p

k值的确定

该方法的思想即聚类的个数从小到大分别进行聚类计算簇内的离差平方和,通过可视化观察拐点变化情况——斜率突然由大变小则可认为该点即为所需的K数值,即分类的簇数。该可视化图可称为肘部图。
实例:随机生成正态分布的数据来进行举例,聚类情况如下所示:
样本点分布
一、拐点法【肘部图确定】
根据该数据集,绘制该数据集的簇的个数与总的簇内离差平方和之间的折线图如图所示:
肘部图
从图中明显可观察到K = 3,即簇的个数为3个的时候即为最佳的簇数,此使我们可以将KMeans算法的簇数规定为3个。参考代码如下所示:

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

def k_SSE(X, clusters):
    # 选择连续的K种不同的值
    K = range(1,clusters+1)
    # 构建空列表用于存储总的簇内离差平方和
    TSSE = []
    for k in K:
        # 用于存储各个簇内离差平方和
        SSE = []
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(X)
        # 返回簇标签
        labels = kmeans.labels_
        # 返回簇中心
        centers = kmeans.cluster_centers_
        # 计算各簇样本的离差平方和,并保存到列表中
        for label in set(labels):
            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()

# 将三组数据集汇总到数据框中
X = pd.DataFrame(np.concatenate([np.array([x1,y1]),np.array([x2,y2]),np.array([x3,y3])], axis = 1).T)
# 自定义函数的调用
k_SSE(X, 15)

二、轮廓系数确定

  1. 思想:该方法的思想可概括为——簇间大、簇内小。即簇内的样本点应尽可能地靠拢,而不同簇之间的样本点应该尽可能地分散。可根据如下目标函数来进行表示: S ( i ) = b ( i ) − a ( i ) m a x ( a ( i ) , b ( i ) ) S(i) = \frac{b(i) - a(i)}{max(a(i), b(i))} S(i)=max(a(i),b(i))b(i)a(i) 其中, a ( i ) a(i) a(i)表示簇内的密集程度,即第 i i i个样本点与簇内各个样本点的距离的均值; b ( i ) b(i) b(i) 表示簇之间的离散程度,即样本 i i i与非本簇的样本点之间的距离——样本与每个簇的样本之间的距离的平均值的最小值作为 b ( i ) b(i) b(i) S ( i ) S(i) S(i)的数值接近1表示该样本点归于本簇是合理的;0表示该样本点处于边缘地带;-1表示该样本点不应该属于本簇。轮廓系数可通过metrics中的silhouette_score来计算。

  2. 实例:根据上文的数据集进行计算,得到如下的可视化结果:
    轮廓系数
    显然,k = 3时其S的数值最接近1,即说明该情况下的簇的分类效果是最佳的。参考代码如下所示:

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函数,计算轮廓系数
        S.append(metrics.silhouette_score(X, labels, metric='euclidean'))
		# X为所需要计算的数据集、labels为计算标签、metric为度量距离,这里选择的是欧氏距离
    # 中文和负号的正常显示
    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)

实例分析

实例1——鸢尾花类别分析

鸢尾花的类别分析是机器学习中常见的用于练习的数据集,这里我们选用这个经典的数据集来作为Kmeans算法的第一个实例。数据集预览如下所示:
dataSetIris
选取花瓣宽度与长度数据来进行可视化处理得到如下图所示的聚类结果:
在这里插入图片描述
显然四维数据空间很难直观地展示,因此采用雷达图来展示3个类别之间的区别:
雷达图的绘制是基于pygal库,其具有较好的可视化互动功能,可参考其他文章来学习该库。
在这里插入图片描述
参考代码如下所示:

################################# 所需的包 #################################

import pandas as pd
import numpy as np  
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import metrics
import seaborn as sns

################################# 模型建立 #################################
iris = pd.read_csv(r'iris.csv')
# 查看数据集的前几行
iris.head()

# 需要进行建模的数据
X = iris.iloc[:, 0:-1]

# 模型的建立
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
# 保存分类结果
X['cluster'] = kmeans.labels_ 
# 频数统计
X.cluster.value_counts()
'''
cluster
2    61
1    50
0    39
'''

################################# 可视化处理 #################################

# 簇的中心
centers = kmeans.cluster_centers_
# 绘制聚类效果图
# 选取花瓣的长度和宽度进行可视化
sns.lmplot(
  x = 'Petal_Length', y = 'Petal_Width', hue = 'cluster', markers = ['^', 's', 'o'],
  data = X, fit_reg = False, scatter_kws = {'alpha': 0.8}, legend_out = False  
    )
# 绘制聚类中心
plt.scatter(centers[:, 2], centers[:, 3], marker='*', color = 'black', s = 130)
plt.xlabel('花瓣长度')
plt.ylabel('花瓣宽度')
plt.show()



# 导入第三方模块
import pygal
# 调用Radar这个类,并设置雷达图的填充,及数据范围
radar_chart = pygal.Radar(fill = True)
# 添加雷达图各顶点的名称
radar_chart.x_labels = ['花萼长度','花萼宽度','花瓣长度','花瓣宽度']
# 绘制三个雷达图区域,代表三个簇中心的指标值
radar_chart.add('C1', centers[0])
radar_chart.add('C2', centers[1])
radar_chart.add('C3', centers[2])
# 保存图像
radar_chart.render_to_file('radar_chart.svg')


实例2——NBA球员历史数据聚类

前文的案例研究人员已知分类的个数因此可直接进行分类。而当K值未知时就需要进行K值的选取了。

读取数据集预览如下所示,为更好地划分球员, 我们选择得分、命中率、三分命中率、罚球命中率来进行研究。绘制得分与命中率的散点图如下所示。
在这里插入图片描述
在这里插入图片描述
在进行数据处理前应当对数据进行标准化处理以消除量纲的影响,并根据预处理好的数据进行K值的选取,选取方式以及代码实现细节如上文所示,这里我们选取轮廓系数法作为K值的选择依据,结果如下图所示最佳的K值为3.
在这里插入图片描述
可以看出聚类分为3类最为合适,参考代码如下所示:

# 绘制得分与命中率的散点图
sns.lmplot(x = '得分', y = '命中率', data = players, 
           fit_reg = False, scatter_kws = {'alpha':0.8, 'color': 'steelblue'})
plt.show()


from sklearn import preprocessing
# 数据标准化处理
X = preprocessing.minmax_scale(players[['得分','罚球命中率','命中率','三分命中率']])
# 将数组转换为数据框
X = pd.DataFrame(X, columns=['得分','罚球命中率','命中率','三分命中率'])
 
# 使用轮廓系数选择最佳的K值
k_silhouette(X, 15)

根据选择的K值进行Kmeans聚类建模,得到结果如下所示:
在这里插入图片描述
在这里插入图片描述

# 将球员数据集聚为3类
kmeans = KMeans(n_clusters = 3)
kmeans.fit(X)
# 将聚类结果标签插入到数据集players中
players['cluster'] = kmeans.labels_

centers = []
'''
这里由于数据经过了标准化处理,为更好地进行可视化应当对原数据计算其簇中心
'''
for i in players.cluster.unique():
    centers.append(
        players.loc[players.cluster == i, ['得分','罚球命中率','命中率','三分命中率']].mean())



sns.lmplot(x = '得分', y = '命中率', hue = 'cluster', data = players, markers = ['^','s','o'],
           fit_reg = False, scatter_kws = {'alpha':0.8}, legend = False)
# 添加簇中心
plt.scatter(centers[:,0], centers[:,2], c='k', marker = '*', s = 180)
plt.xlabel('得分')
plt.ylabel('命中率')
# 图形显示
plt.show()



# 雷达图
# 调用模型计算出来的簇中心
centers_std = kmeans.cluster_centers_
# 设置填充型雷达图
radar_chart = pygal.Radar(fill = True)
# 添加雷达图各顶点的名称
radar_chart.x_labels = ['得分','罚球命中率','命中率','三分命中率']

# 绘制雷达图代表三个簇中心的指标值
radar_chart.add('C1', centers_std[0])
radar_chart.add('C2', centers_std[1])
radar_chart.add('C3', centers_std[2])
# 保存图像
radar_chart.render_to_file('radar_chart.svg')

本文数据集以及参考源代码:
https://github.com/ChouerGBDTLin/Machine-Learning

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值