聚类分析是没有给定划分类别的情况下,根据样本相似度进行样本分组的一种方法,是一种非监督的学习算法。聚类的输入是一组未被标记的样本,聚类根据数据自身的距离或相似度划分为若干组,划分的原则是组内距离最小化而组间距离最大化。
常见的聚类分析算法如下:
· 分散性聚类:K-Means聚类也称为快速聚类法,在最小化误差函数的基础上将数据划分为预定的类数K。该算法的原理简单并便于处理大量数据。
· 密度算法:基于密度的方法(Density-Based Methods),与其他方法的根本区别是:它不是基于各种各样的距离的,而是基于密度的。这样就能克服基于距离的算法只能发现“类圆形”的聚类的缺点。这个方法的指导思想是,只要一个区域中的点的密度大过某个阈值,就把它加到与之相近的聚类中去。
· 系统聚类:也称为层次聚类,分类的单位由高到低呈树形结构,且所处的位置越低,其所包含的对象就越少,但这些对象间的共同特征越多。该聚类方法只适合在小数据量的时候使用,数据量大的时候速度会非常慢。
【例1】
为了看鸢尾花的3种聚类算法的直观区别,不用具体的算法实现,只需要调用相应的函数即可。
1.分散性聚类
K-Means算法是典型的基于距离的非层次聚类算法,在最小化误差函数的基础上将数据划分为预定的类数K,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。
算法流程:
(1)选择聚类的个数k。
(2)任意产生k个聚类,然后确定聚类中心,或者直接生成k个中心。
(3)对每个点确定其聚类中心点。
(4)再计算其聚类新中心。
(5)重复以上步骤直到满足收敛要求(通常是确定的中心点不再改变)。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn import datasets
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('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()
estimator = KMeans(n_clusters=3) # 构造聚类器
estimator.fit(X) # 聚类
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('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()
鸢尾花K-Means聚类如图1所示。
图1 鸢尾花K-Means聚类
K-Menas算法试图找到使平方误差准则函数最小的簇。当潜在的簇形状是凸面的,簇与簇之间的区别较明显,且簇大小相近时,其聚类结果比较理想。对于处理大数据集合,该算法非常高效,且伸缩性较好。但该算法除了要事先确定簇数K和对初始聚类中心敏感外,经常以局部最优结束,同时对“噪声”和孤立点敏感,并且该方法不适于发现非凸面形状的簇或大小差别很大的簇。
2.密度聚类之DBSCAN算法
DBSCAN算法需要两个参数,即ε(eps)和minPts形成高密度区域所需要的最少点数。由一个任意未被访问的点开始,然后探索这个点的ε-邻域,如果ε-邻域里有足够的点,就建立一个新的聚类,否则这个点被标记为杂音。注意,这个点之后可能被发现在其他点的ε-邻域里,而该ε-邻域可能有足够的点,届时这个点会被加入该聚类中。
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn.cluster import DBSCAN
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('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()
dbscan = DBSCAN(eps=0.4, min_samples=9)
dbscan.fit(X)
label_pred = dbscan.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('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()
鸢尾花DBSCAN聚类如图2所示。
图2 鸢尾花DBSCAN聚类
3.结构性聚类(层次聚类)
· 凝聚层次聚类(AGNES算法,自底向上):首先将每个对象作为一个簇,然后合并这些原子簇为越来越大的簇,直到某个终结条件被满足。
· 分裂层次聚类(DIANA算法,自顶向下):首先将所有对象置于一个簇中,然后逐渐细分为越来越小的簇,直到达到某个终结条件。
下面使用AGNES算法。
from sklearn import datasets
from sklearn.cluster import AgglomerativeClustering
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
import pandas as pd
iris = datasets.load_iris()
irisdata = iris.data
clustering = AgglomerativeClustering(linkage='ward', n_clusters=3)
res = clustering.fit(irisdata)
print ("各个簇的样本数目:")
print (pd.Series(clustering.labels_).value_counts())
print ("聚类结果:")
print (confusion_matrix(iris.target, clustering.labels_))
plt.figure()
d0 = irisdata[clustering.labels_ == 0]
plt.plot(d0[:, 0], d0[:, 1], 'r.')
d1 = irisdata[clustering.labels_ == 1]
plt.plot(d1[:, 0], d1[:, 1], 'go')
d2 = irisdata[clustering.labels_ == 2]
plt.plot(d2[:, 0], d2[:, 1], 'b*')
plt.xlabel("Sepal.Length")
plt.ylabel("Sepal.Width")
plt.title("AGNES Clustering")
plt.show()
鸢尾花AGNES聚类如图3所示。
图3 鸢尾花AGNES聚类
从上面3种实验截图可以看出,K-Means聚类和AGNES层次聚类分析结果显示为三类,与DBSCAN的结果不一样。这主要取决于算法本身的优缺点。K-Means对于大型数据集简单高效、时间复杂度低、空间复杂度低。最重要的是数据集大时结果容易局部最优。需要预先设定K值,对最先的K个点的选取很敏感,对噪声和离群值非常敏感,只用于numerical类型的数据,不能解决非凸数据。DBSCAN对噪声不敏感,能发现任意形状的聚类,但是聚类的结果与参数有很大的关系。DBSCAN用固定参数识别聚类,但当聚类的稀疏程度不同时,相同的判定标准可能会破坏聚类的自然结构,即较稀的聚类会被划分为多个类,或密度较大且离得较近的类会被合并成一个聚类。