赞
踩
机器学习方法主要分为监督学习方法和非监督学习方法两种。监督学习方法是在样本类别标签已知的条件下进行的,可以统计出各类训练样本的概率分布、特征空间分布区域等描述量,然后利用这些参数进行分类器设计。在实际应用中,很多情况是无法预先知道样本标签的,因而只能利用非监督机器学习方法进行分析。聚类分析就是典型的非监督学习方法,它在没有给定划分类别的情况下,根据数据自身的距离或相似度进行样本分组。
本章将介绍以下内容:
所谓聚类分析,就是给定一个元素集合 D,其中每个元素具有n 个观测属性,对这些属性使用某种算法将 D 划分成 K 个子集,要求每个子集内部的元素之间相似度尽可能高,而不同子集的元素相似度尽可能低。聚类分析是一种非监督的观察式学习方法,在聚类前可以不知道类别甚至不用给定类别数量。目前聚类分析广泛应用于统计学、生物学、数据库技术和市场营销等领域。
聚类方法可以分成两大类,一类是基于概率密度函数估计的直接方法,其原理是设法找到各类别在特征空间的分布参数再进行分类。另一类是基于样本之间相似性度量的间移聚类方法,其原理是设法找出不同类别的核心或初始类核,再依据样本与这些核心之间然相似性度量将样本聚集成不同类别。
最常用的基于概率密度估计的直接方法的例子是直方图方法。通过对样本的直方图统计,根据直方图分布高峰之间的谷点就能把样本分成不同的类别。下图所示就是一种基干概率统计的聚类分析方法。图示二维空间中有两类样本数据,将样本沿着图中两条平行的直线投影,样本的分布呈现出较好的高峰和低谷,将峰值分别划分在不同的区域中,把聚在同一高峰下的样本划分为一类,就实现了样本聚类。这种方法常将样本投影到某个特定的坐标轴,一般称为投影法。
对于一般的样本数据集,投影法的具体操作步骤如下。
在子样本相似度的聚类方法,一般把相似度表示成在特征空间中的某种距离度量,根据样本在特征空间中的距离长短进行动态分类,这种方法又称为基于距离度量的方法。在目标检测和识别等图像处理应用中,就可利用图像像素颜色的相似性对图像进行聚类,检测出特定的区域和目标。下图所示就是一种基于颜色空间聚类的道路识别方法,从中可以看出,图像中包含天空、地面和建筑等不同的区域,每个区域的额色较为接近,在聚类算法中,把类别数定为 3,从结果图像中可以看出这三部分在图像中所占比例基术等,通过适当聚类和处理能够将道路区域成功地提取出来。
数据集中的样本如何聚类则取决于聚类的准则函数,以使某种聚类准则达到极值为最佳。对数据集进行聚类的方法有两种:迭代的动态聚类算法和非迭代的分级聚类算法。
动态聚类是在数据点分类过程中按照某种准则动态调整其类型归属。聚类过程一般先从各聚类的代表点或初始中心点开始,再按各样本到中心点的最短矩离将样本分到该类。但是由于初始代表点很可能不甚合理,以至于影响到聚类的结果。这就需要有一个对聚类的结果进行修改或迭代的过程,使聚类结果逐步趋向合理。迭代的过程需要一个准则函数来指导,使迭代朝实现准则函数的极值化方向收敛。因此,动态聚类算法需要实现以下几:①选定某种距离度量作为样本间的相似性度量;②确定样本合理的初始分类,包括代表点的选择、初始分类的方法选择等;③ 确定某种评价聚类结果质量的准则函数,用以调整初始分类直至达到该准则函数的极值。
生活中的很多事情需要将杂乱的东西变得有序,如生物分类、图书分类等。这需要各种事物按其相似性或内在联系组织起来,组成有层次的结构,这就是分级聚类方法要解决的问题。首先把各种事物相似或本质上最接近的划归一类,然后把相近的几个类合并成一个类。分级聚类方法的目的井不是把 N 个样本分成某一个预定的类别数,而是把样本集按不同的相似程度要求分成不同类别,一种极端的情况是每个样本各自为一类,没有任何聚类,另一种极端则是将所有样本归一类。分级聚类一般采用树形结构进行表示,第一层次的样本自成一类,其类内相似度是 100%,从第二层开始逐渐将上一层的样本进行合并,使类别数逐渐减少,而类别内样本的相似程度要求也随之下降。
聚类算法有很多种,如 K-means (K 均值聚类)、K 中心聚类、密度聚类、谱系聚类、最大期望聚类等。这里重点介绍 K-means 聚类算法,该算法的基本思想是以空间中 K 个点为中心进行聚类,对最靠近它们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果。K-means 算法实现简单、计算速度快、原理易于理解、具有理想的聚类效果,因此该算法是公认的经典数据挖掘方法之一。
下面就以欧氏距离为例,来说明 K-means 算法是如何完成聚类任务的,其步骤如下
首先是初始K 值的确定,即聚类之前必须清楚数据应该聚为几类。确定聚类数 K 没有最佳的方法,通常是需要根据具体的问题由人工进行选择。实际中,为了确定最优聚类数 K 可以尝试使用“肘部法”(Elbow method)。如下图所示,使用数据点与聚类质心的平均距离作为 K 值的度量,增加聚类数量总是会减少数据点的距离,根据距离函数与K值的变化曲线,再选择变化率急副下降的“肘点”,即用来大致确定 K 值。当然,还可以使用许多其他技术去人 K 值,包括交又验证、信息标准、影像法和G-means算法等。
K-means 算法常使用的距离度量有欧氏距离和余弦相似度两种。这两种度量都可以用来评定个体间的差异大小,其中,欧氏距离会受指标不同单位刻度的影响,所以一般需要先进行标准化,同时距离越大,个体间差异越大;空间向量余弦相似度度量不会受指标刻度的影响,余弦值落于区间[-1,1],度量值越大个体间的差异越小。
K-means 算法属于一种迭代算法,那么迭代何时结束呢? 一般情况下,当目标函数达到最优或达到最大的迭代次数即可终止。对于不同的距离度量,目标函数也不同。当采用欧式距离时,目标函数一般为最小化对象到其簇质心的距离平方和。当采用余弦相似度时目标函数一般为最大化对象到其簇质心的余弦相似度和。另外,为了防止程序进入死循环会设置最大的迭代次数,当达到预定的迭代次数时即可将算法终止。
尽管K均值聚类算法具有其原理易于理解及聚类效果理想这些优点,但还是存在一些缺点。例如,需要事先指定生成的簇K,只有对要分析的数据对象比较熟悉才能对 K 值进行较好的估计,还可以通过交叉验证等处理方法确定最佳的K值。其次是对噪声数据或离群点数据敏感,少量的异常数据会对均值产生极大的影响。最后,对于不同的初始值,可能导致不同的聚类结果,有的初始值会使结果陷入局部最优解,同时在大规模数据集上收敛较慢。
(左有效聚类,右不够有效)
有效聚类
针对以文件存储的数据集,使用 K-means 算法进行聚类分析的 Python 函数设计及处理流程如下。
[实例15-1]对于常见的二维数据集,设计 K-means 聚类方法,对80个二维数据点进行聚类分析。K-means 算法的 Python 语言实现及处理过程如下。
下图所示的 80 个二维样本数据集,存储为 testSet 文本文档。经过数据预处理和简单分析,得知该数据集共有 4 个类别,因而能确定聚类数 K 为4。
首先导入必要的模块
import kmeans
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt
(1)从文件中加载数据集。
构建数据矩阵,从文本中逐行读取数据,形成供后续使用的数据矩阵
dataSet=[]
fileIn=open('testSet.txt')
for line in fileIn.readlines():
lineArr=line.strip().split('\t')
dataSet.append([float(lineArr[0]), float(lineArr[1])])
(2)调用 K-means 算法进行数据聚类。
通过以下命令调用设计的 K-means 模块,进行数据聚类
dataSet=np.mat(dataSet)
k=4
centroids,clusterAssment=kmeans.kmeanss(dataSet, k)
K-means 模块主要包含以下几个函数。
距离度量函数。这里使用的是欧氏距离,计算过程如下.
def eucDistance(vec1,vec2):
return sqrt(sum(pow(vec2 - vec1, 2)))
初始聚类中心选择。从数据集中随机选择K个数据点,用作初始聚类中心
def initCentroids(dataSet, k):
numSamples, dim=dataSet.shape
centroids=np.zeros((k, dim))
for i in range(k):
index=int(np.random.uniform(0, numSamples))
centroids[i, :]=dataSet[index, :]
return centroids
K-means 聚类算法。该算法会创建 K个质心,再将每个点分配到最近的质心,然后重新计算质心。这个过程重复数次,直到数据点的簇分配结果不再改变位置。
def kmeanss(dataSet, k): numSamples=dataSet.shape[0] clusterAssement=np.mat(np.zeros((numSamples, 2))) clusterChanged=True #step1:init centroids centroids=initCentroids(dataSet, k) while clusterChanged: clusterChanged=False for i in range(numSamples): minDist = 100000.0 minIndex=0 ##step2 find the centroid who is closest for j in range(k): distance=eucDistance(centroids[j, :], dataSet[i, :]) if distance < minDist: minDist=distance minIndex=j ##step3: update its cluster clusterAssement[i, :]=minlndex, minDist ** 2 if clusterAssement[i,0] != minlndex: clusterChanged=True ##step4: update centroids for j in range(k): pointsInCluster=dataSet[np.nonzero(clusterAssement[:, 0].A==j)[0]] centroids[j, :]=np.mean(pointsInCluster, axis=0) print ('Congratulations,cluster complete!') return centroids,clusterAssement
聚类结果显示。将聚类划分为不同簇的数据,用不同的颜色和符号进行显示,同时画出最终的聚类中心。
def showCluster(dataSet, k, centroids, clusterAssement):
numSamples, dim = dataSet.shape
mark=['or', 'ob', 'og', 'ok', '^r', '+r', '<r', 'pr']
if k > len(mark):
print("Sorry!")
return 1
for i in np.xrange(numSamples):
markIndex=int(clusterAssementli,0)
plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize=12)
plt.show()
(3)聚类结果显示。
对 80个二维数据,使用 K-means 方法进行聚类,聚类结果如下图所示,迭代后的聚类中心用方形表示,其他数据用不同颜色的原点表示
Scikit-learn 是 Python 的一个开源机器学习模块,它建立在NumPy、SciPy和matplotlib 模块之上。Scikit-learn 最先是由 David Cournapeau 于2007 年发起的一个Google Summer of Code 项目,后来得到很多机器学习爱好者的贡献,目前该项目由一个志愿者团队在维护。Scikit-learn 为用户提供各种机器学习算法接口,可以让用户简单、高效地进行数据挖掘和数据分析。
Scikit-learn 中有多种 K-means 算法,如传统的 K-means算法和基于采样的 Mini Batch K-means 算法等。这些算法分别对应KMeans 类和 MiniBatchKMeans 类。一般来说,传统K-means 法的调参是比较简单的,首先需要注意的是聚类数 K 值的选择,即参数n_clusters。当然KMeans 类和 MiniBatchKMeans 类还有许多其他的参数,但是这些参数大多不需要去调参。例如,KMeans 类的主要参数如下。
聚类问题的首要参数是聚类数K,那么什么样的 K 值才能使聚类结果更好呢? 非监督聚类没有比较直接的聚类评估方法,但是可以从簇内的稠密程度和簇间的离散程度来评估聚类的效果,常见的方法有轮廓系数 Silhouette Coefficient和 Calinski-Harabasz Index。其中,Calinski-Harabasz Index计算简单直接,得到的 Calinski-Harabasz 分数值越大则聚类效果越好。Calinski-Harabasz 分数值s 的计算公式为:
s
(
k
)
=
(
t
r
(
B
k
)
t
r
(
W
k
)
m
−
k
k
−
1
)
s(k)=(\frac{tr(B_{k})}{tr(W_{k})} \frac{m-k}{k-1})
s(k)=(tr(Wk)tr(Bk)k−1m−k)
式中,m 为训练集样本数;k 为类别数;B:为类别之间的协方差矩阵;Mk为类别内部数据的协方差矩阵;tr 为矩阵的迹。
也就是说,类别内部数据的协方差越小越好,类别之间的协方差越大越好,这样对应的 Calinski-Harabasz分数会越高。在 Scikit-learn 中,Calinski-Harabasz Index 对应的方法是metrics.calinski_harabaz_score。
[实例15-2]生成二维多类数据,调用机器学习块 Scikit-learn 中的聚类函数进行聚类分析。分析不同参数对聚类结果的影响,重点分析聚类数K的取值及其评估方法。
导入一些必要的模块,为了方便进行可视化显示,随机创建 1000 个具有二维持征的数据集,样本大致分为4类。生成随机数据的函数为make_blobs,用散点图观察绘制的数据。
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
# 1000个样本点,4个簇,4个簇中心分别为[-1,-1],[0,0],[1,1],[2,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=9)
plt.scatter(X[:, 0], X[:, 1], marker='o')
plt.show()
聚类效果用散点图表示如下图所示:
选择聚类数 K=2,调用 K-means 聚类方法对生成的数据集进行聚类,聚类效果用散点图表示如下图所示。
y_pred = KMeans(n_clusters=2, random_state=9).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
使用 Calinski-Harabasz Index 来评估聚类分数,其结果如下,
from sklearn import metrics
print(metrics.calinski_harabasz_score(X, y_pred))
输出:
Out[2]: 3116.1706763322227
修改聚类数K=3,使用 K-means 方法的聚类效果如下图所示
y_pred = KMeans(n_clusters=3, random_state=9).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
聚类数K为3时,Calinski-Harabasz Index 评估分数为 2931.6,聚类数虽然更接真实的类别数 4,但是评估分数却较聚类数为 2 时下降了。
print(metrics.calinski_harabasz_score(X, y_pred))
Out[2]: 2931.625030199556
修改聚类数K=4,使用 K-means 方法的聚类效果如下图所示
from sklearn.cluster import KMeans
y_pred = KMeans(n_clusters=4, random_state=9).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
此时,Calinski-Harabasz lndex 评估分数为 5924.050613480169,聚类评估分数最高。如果再增加聚类,这个评估分数会有不同程度的下降,因此 K=4 是最佳的聚类数。
Out[2]: 5924.050613480169
[实例15-3]对多维特征数据进行聚类分析。现有 4种类型的鱼类
(Bream、Roach、Smelt、Pike),数据集中有 85 个观测值,每个观测值有7个变量: species(种类)、weight( 重量)、length1(长度1)、length2(长度2)、length3(长度3)、height(高度)、width(宽度)。如果不考虑数据集中的种类属性,使用 K-means 方法对观测数据进行聚类分析。
如下图所示,鱼类数据集具有多种观测特征,每个特征观测值的度量单位也不一致,因此不方便进行二维可视化显示,这里重点介绍聚类分析的过程。
species | weight | length1 | length2 | length3 | height | width |
---|---|---|---|---|---|---|
Bream | 242 | 23.2 | 25.4 | 30 | 38.4 | 13.4 |
Bream | 290 | 24 | 26.3 | 31.2 | 40 | 13.8 |
Bream | 340 | 23.9 | 26.5 | 31.1 | 39.8 | 15.1 |
Bream | 363 | 26.3 | 29 | 33.5 | 38 | 13.3 |
Bream | 430 | 26.5 | 29 | 34 | 36.6 | 15.1 |
Bream | 450 | 26.8 | 29.7 | 34.7 | 39.2 | 14.2 |
Bream | 500 | 26.8 | 29.7 | 34.5 | 41.1 | 15.3 |
Bream | 390 | 27.6 | 30 | 35 | 36.2 | 13.4 |
Bream | 450 | 27.6 | 30 | 35.1 | 39.9 | 13.8 |
首先,从sklearn和pandas 导入相应的模块
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
import pandas as pd
其次,从 fish.csv文件载入数据集,聚类分析时要删除类别属性,并查看前5项观测数据。
df = pd.read_csv('fish.csv) species = list(df['species']) del df['species'] df.head() In[2]:df=pd.read_csv('fish.csv') ...:#forget the species column for now-we'll use it later! ...:species=list(df['species']) ...:del df['species'] ...: In[3]:df.head() Out[3l: weight length1 length2 length3 leigth width 0 242 23.2 25.4 30.0 38.4 13.4 1 290 24.0 26.3 31.2 40.0 13.8 2 340 23.9 26.5 31.1 39.8 15.1 3 363 26.3 29.0 33.5 38.0 13.3 4 430 26.5 29.0 34.0 36.6 15.1
由于数据集各属性中,重量用克表示,长度和高度用厘米表示,因此数据具有不同的尺度,为了更有效地对数据进行聚类,很有必要对各属性进行标准化处理。可以使用sklearn.preprocessing.StandardScaler类,它将数据按列进行标准化处理,每个属性都换成均值为0、方差为1的归一化数据。使用以下命令抽取测量数据的二维数组形成样本集再指定标准化处理方法为 StandardScaler。
samples = df.values
scaler = StandardScaler()
创建具有4 个聚类数的 K-means 实例,将该聚类模型与刚才定义的标准化处理方法一起形成聚类分析处理流程。
means = KMeans(n_clusters=4)
pipeline = make_pipeline(scaler, kmeans)
将该聚类分析模型应用到鱼类观测数据 samples 上,对聚类模型进行训练,其调用格乃聚类分析的详细参数如下。
In[7]:pipeline.fit(samples) Out[7]: pipeline(steps=[('standardscaler', standardscaler(copy=True, with_mean=True, with_std=True)), ('kmeans', kmeans(algorithm='auto', copy_x=True,init='k-means++', max_iter=300, n_clusters=4, n_init=10, n_jobs=1, precompute_distances='auto', random_state=None,tol=0.0001, verbose=0))])
对观测数据 samples 使用 pipeline.predict()方法进行预测,得到观测数据的聚类类别号。
labels = pipeline.predict(samples)
创建一个包含两列数据的 pandas 数据框,装入鱼类数据的聚类类别号和真实种类。使用 crosstab 函数分析聚类结果与实际种类之间的关系,并用交叉表的形式表示。
df = pd.DataFrame(['labels': labels,'species': species])
ct = pd.crosstab(df['labels'],df['species'])
In[16]:df=pd.DataFrame({'Labels':Labels,'species':species})
...:ct=pd.crosstab(df['labels'],df['species'])
...:print(ct)
Species Bream Pike Roach Smelt
labels
0 0 17 0 0
1 1 0 19 1
2 33 0 1 0
3 0 0 0 13
从以上结果可以看出,有一个 Bream 类型的样本聚类到 Roach 类型了,Roach种类中有两个错误聚类的样本,总体聚类精度达到了 96.5%,证明采用K-means 方法对上述样本进行聚类分析还是比较可靠的。
(1)对二维数据进行聚类分析。文件 point_2D.csv 包含 300 个二维样本数据集,首先从文件读取数据,绘制散点图观察数据的聚类形式,确定基本聚类数K,其次调用 sklearn 中的 K-means 类进行模型训练和预测,最后输出聚类类别号和聚类结果散点图。
300个二维数据如下图所示
聚类结果标签号及散点图如下图所示。
(2)UCI 提供了3 种小麦种子的观测数据集,共有 3 种类型的小麦 (Kama wheat、Rosa wheat、Canadian wheat),数据集中有 201 个观测值,每个观测值有8个变量area、perimeter、compactness、length、width、asymmetry_coefficient、、。如果不考虑数据集中的种类属性,使用 K-means 方法对观测数据进行聚类分析,如下图所示。
area | perimeter | compactness | length | width | asymmetry_coefficient | groove_length | grain_variety |
---|---|---|---|---|---|---|---|
15.26 | 14.84 | 0.871 | 5.763 | 3.312 | 2.221 | 5.22 | Kama wheat |
14.88 | 14.57 | 0.8811 | 5.554 | 3.333 | 1.018 | 4.956 | Kama wheat |
14.29 | 14.09 | 0.905 | 5.291 | 3.337 | 2.699 | 4.825 | Kama wheat |
13.84 | 13.94 | 0.88955 | 5.324 | 3.379 | 2.259 | 4.805 | Kama wheat |
16.14 | 14.99 | 0.9034 | 5.658 | 3.562 | 1.355 | 5.175 | Kama wheat |
14.38 | 14.21 | 0.8951 | 5.386 | 3.312 | 2.462 | 4.956 | Kama wheat |
14.69 | 14.49 | 0.8799 | 5.563 | 3.259 | 3.586 | 5.219 | Kama wheat |
14.11 | 14.1 | 0.8911 | 5.42 | 3.302 | 2.7 | 5 | Kama wheat |
16.63 | 15.46 | 0.8747 | 6.053 | 3.465 | 2.04 | 5.877 | Kama wheat |
16.44 | 15.25 | 0.888 | 5.884 | 3.505 | 1.969 | 5.533 | Kama wheat |
15.26 | 14.85 | 0.8696 | 5.714 | 3.242 | 4.543 | 5.314 | Kama wheat |
采用 sklearn.cluster 中的 K-means 聚类分析方法,通过载入数据、建立 K-means聚类分析模型、对观测数据进行测试等步骤,最后通过交叉表的方式显示聚类结果和实际种子类型的关系。下面是本练习所附代码的运行结果,供读者参考。直接使用 K-means 模型进行聚类预测的结果如下图所示。
对观测数据各属性进行标准化预处理,然后调用 K-means 聚类模型,得到的聚类结果有一定程度的提高,结果如下图所示。
基于sklearn实现鸢尾花聚类
导入相关包
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn import datasets
直接从sklearn.datasets中加载数据集
# 直接从sklearn中获取数据集
iris = datasets.load_iris()
X = iris.data[:, :4] # 表示我们取特征空间中的4个维度
print(X.shape)
绘制二维数据分布图,每个样本使用两个特征,绘制其二维数据分布图
# 取前两个维度(萼片长度、萼片宽度),绘制数据分布图
plt.scatter(X[:,0],X[:,1],c="red",marker='o',label='see')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend(loc=2)
plt.show()
实例化K-means类,并且定义训练函数
def Model(n_clusters):
estimator = KMeans(n_clusters=n_clusters)# 构造聚类器
return estimator
def train(estimator):
estimator.fit(X) # 聚类
训练
# 初始化实例,并开启训练拟合
estimator=Model(3)
train(estimator)
可视化展示
label_pred = estimator.labels_ # 获取聚类标签
# 绘制k-means结果
x0 = X[label_pred == 0]
x1 = X[label_pred == 1]
x2 = X[label_pred == 2]
plt.scatter(x0[:, 0], x0[:, 1], c="red", marker='o', label='label0')
plt.scatter(x1[:, 0], x1[:, 1], c="green", marker='*', label='label1')
plt.scatter(x2[:, 0], x2[:, 1], c="blue", marker='+', label='label2')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.legend(loc=2)
plt.show()
本文内容主要参照了《Python3 数据分析与机器学习实战》, 龙马高新教育编著,对应的ISBN号为978-7-301-29566-3,如有需要,请购买正版图书。
参考文章:基于k-means实现鸢尾花聚类
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。