聚类分析
- 聚类的定义
聚类分析是根据在数据中发现的描述对象及其关系的信息,将数据对象分组。是一种归约技术,旨在揭露一个数据集中观测的子集。它可以把大量的观测值归约为若干个类。组内的对象相互之间是相似的(相关的),而不同组中的对象是不同的(不相关的)。组内相似性越大,组间差距越大,说明聚类效果越好。
图1-1 聚类分析示意图
最常用的两种聚类方法是层次聚类和划分聚类。
1.1层次聚类
1.1.1层次聚类定义与特点
基于层次的聚类方法是指对给定的数据进行层次分解,直到满足某种条件为止。该算法根据层次分解的顺序分为自底向上法和自顶向下法,即凝聚式层次聚类算法和分裂式层次聚类算法。
(1)自底向上法
首先,每个数据对象都是一个簇,计算数据对象之间的距离,每次将距离最近的点合并到同一个簇。然后,计算簇与簇之间的距离,将距离最近的簇合并为一个大簇。不停地合并,直到合成了一个簇,或者达到某个终止条件为止。簇与簇的距离的计算方法有最短距离法、中间距离法、类平均法等,其中,最短距离法是将簇与簇的距离定义为簇与簇之间数据对象的最短距离。自底向上法的代表算法是AGNES(AGglomerativeNESing)算法。
(2)自顶向下法
该方法在一开始所有个体都属于一个簇,然后逐渐细分为更小的簇,直到最终每个数据对象都在不同的簇中,或者达到某个终止条件为止。自顶向下法的代表算法是 DIANA(DivisiveANAlysis)算法。
基于层次的聚类算法的主要优点包括,距离和规则的相似度容易定义,限制少,不需要预先制定簇的个数,可以发现簇的层次关系。基于层次的聚类算法的主要缺点包括,计算复杂度太高,奇异值也能产生很大影响,算法很可能聚类成链状。
1.1.2层次聚类算法
对与层次聚类来说,最常用的算法是单联动、全联动、平均联动、质心和ward方法。
层次聚类方法 |
|
单联动 |
一个类中的点和另一个类中点的最小距离 |
全联动 |
一个类中的点和另一个类中点的最大距离 |
平均联动 |
一个类中的点和另一个类中点的平均距离 |
质心 |
两类中质心之间的距离。对单个变量来说,质心就是变量的值 |
Ward法 |
两个类之间的所有变量的方差分析的平方和 |
1.1.3层次聚类分析
首先载入数据,在这里使用平均联动聚类方法处理营养数据,目的是基于27种食物的营养信息辨别其相似性、相异性并分组。
data(nutrient, package="flexclust")
row.names(nutrient) <- tolower(row.names(nutrient))
nutrient.scaled <- scale(nutrient)
d <- dist(nutrient.scaled)
fit.average <- hclust(d, method="average")
plot(fit.average, hang=-1, cex=.8, main="Average Linkage Clustering")
图1-2 营养数据的平均联动
如果最终目标是这些食品分配到的类较少,因此需要额外的分析来选择聚类的适当个数。Nbclust()函数的输入包括需要做聚类的矩阵或是数据框,使用的距离测度和聚类方法,并考虑最小和最大聚类的个数来进行聚类。他返回每一个聚类指数,同时输出建议聚类的最佳数目。下面为该方法处理营养数据的平均联动聚类。
代码如下:
library(NbClust)
nc <- NbClust(nutrient.scaled, distance="euclidean",
min.nc=2, max.nc=15, method="average")
par(opar)
table(nc$Best.n[1,])
barplot(table(nc$Best.n[1,]),
xlab="Numer of Clusters", ylab="Number of Criteria",
main="Number of Clusters Chosen by 26 Criteria")
图1-3 推荐聚类个数
通过分析上图,可以通过“投票”最多的聚类个数,并选择其中一个使的解释最有意义,下面的代码清单展示了五类聚类的方案。
clusters <- cutree(fit.average, k=5)
table(clusters)
aggregate(nutrient, by=list(cluster=clusters), median)
aggregate(as.data.frame(nutrient.scaled), by=list(cluster=clusters),
median)
plot(fit.average, hang=-1, cex=.8,
main="Average Linkage Clustering\n5 Cluster Solution")
rect.hclust(fit.average, k=5)
cutree()函数用来把树状图分成五类,结果有原始度量和标准度量两种形式,树状图被重新绘制,rect.hclust()函数用来叠加五类的解决方案。
图1-4 通过五类解决方案
1.2划分层次聚类
在划分方法中,观测值被分为K组并根据给定的规则改组成最有粘性的类。
1.2.1 K均值聚类
最常见的划分方法是K均值聚类分析。从概念上讲,K均值算法如下:
(1) 选择K个中心点(随机选择K行);
(2) 把每个数据点分配到离它最近的中心点;
(3) 重新计算每类中的点到该类中心点距离的平均值(也就说,得到长度为p的均值向量,这里的p是变量的个数);
(4) 分配每个数据到它最近的中心点;
(5) 重复步骤(3)和步骤(4)直到所有的观测值不再被分配或是达到最大的迭代次数(R把10次作为默认迭代次数)。
K均值聚类能处理比层次聚类更大的数据集。在R中K均值的函数格式是kmeans(x,centers),这里x表示数值数据集(矩阵或数据框),centers是要提取的聚类数目。函数返回类的成员、类中心、平方和(类内平方和、类间平方和、总平方和)和类大小。
由于K均值聚类在开始要随机选择k个中心点,在每次调用函数时可能获得不同的方案。使用set.seed()函数可以保证结果是可复制的。此外,聚类方法对初始中心值的选择也很敏感。
kmeans()函数有一个nstart选项尝试多种初始配置并输出最好的一个。例如,加上nstart=25会生成25个初始配置。通常推荐使用这种方法。
不像层次聚类方法,K均值聚类要求你事先确定要提取的聚类个数。同样,NbClust包可以用来作为参考。另外,在K均值聚类中,类中总的平方值对聚类数量的曲线可能是有帮助的。可根据图中的弯曲选择适当的类的数量。
data(wine, package="rattle")
head(wine)
df <- scale(wine[-1])
wssplot(df)
library(NbClust)
set.seed(1234)
nc <- NbClust(df, min.nc=2, max.nc=15, method="kmeans")
par(opar)
table(nc$Best.n[1,])
barplot(table(nc$Best.n[1,]),
xlab="Numer of Clusters", ylab="Number of Criteria",
main="Number of Clusters Chosen by 26 Criteria")