今天聊聊k均值聚类分析,我们先要知道什么是类,在大数据时代,我们每个人都被打上很多个性标签,比如:宅男,月光族,手机控,非主流等等,每个标签都可以算是一个类,因此,可以不严谨的说:类是一些有特殊属性个体的集合。而聚类分析的目的,就是要把这些个人找出来并区别出来,聚类分析属于无监督机器学习的一个重要内容,今天我们来聊聊K均值聚类分析,那么k均值聚类分析和之前的层级聚类分析有什么不同呢?
K-Means算法是发展最成熟且原理简单、算法流程清晰,经典算法的步骤描述,分为如下5步完成。
①随机选取K个样本作为n个样本点类中心center_K;
②计算各样本点plot (x[i], y[i])与各类中心cen⁃ter_K的距离;
③将各样本归于最近的类中心点;
④求各类的样本的均值,作为新的类的中心center_K_new;
⑤判定:若类中心不再发生变动或达到迭代次数,算法结束,否则回到第②步。
如图下图所示: 在图中一共有a至e这5个数据以及2个随机的质心点(灰色点)。图
3(a)为算法经过初始化后的状态, 图3(b)和图3(d)是两个更新过程, 图3©和图3(e)是两个更新后的状态。经过2轮更新该算法达到稳定如图3(e)所示。
我们继续使用之前的肉类数据(关注公众号回复:肉类数据可以获得该数据)来进行k均值聚类分析,需要factoextra,dplyr,pacman,cluster包,需要事先下载好,我们先导入数据和包
library(factoextra)
library(dplyr)
library(pacman)
library(cluster)
bc<-read.csv("E:/r/test/roulei.csv",sep=',',header=TRUE)
names(bc)
数据有5个参数,energy代表食物能量(卡路里),protein蛋白质,fat脂肪,calcium钙含量,iron铁含量,竖排是各种肉的名字,我就不一一解释了。
数据的变量差别很大,我们首先要把数据标准化,然后计算欧式距离
bc.scaled<-scale(bc[2:6])##标准化数据
d<-dist(bc.scaled)###计算欧氏距离
在K均值聚类分析中, K的个数(即分成几类)这个参数非常重要,我们先用NbClust的投票功能来看看
这里显示2,3类都有4次投票,即分层2类和3类都是可以的。
我们还可以使用cluster函数做增强k均值聚类分析,可以自己聚类,自动分类,在这里函数倾向于分成2类
km <- eclust(bc[2:6], "kmeans", nstart = 25) #聚类的散点图
也可以通过fviz_gap_stat函数来投票
fviz_gap_stat(km$gap_stat) # 不同K值下Gap 统计图,指导选择最佳K值
fviz_silhouette(km) # 轮廓图,每种聚类下面的分布情况
函数fviz_gap_stat也倾向分成2类
那么问题来了,我们到底应该分成2类还是3类呢,我们可以根据我们的临床需要进行判断,我们可以先把图都做出来比较一下
2类的
set.seed(666)
kmeans1<-kmeans(bc.scaled,centers=2,nstart = 25)
fviz_cluster(object=kmeans1,data=bc[2:6],
ellipse.type = "euclid",star.plot=T,repel=T,
geom = ("point"),palette='jco',main="",
ggtheme=theme_minimal())+
theme(axis.title = element_blank())
3类的
kmeans1<-kmeans(bc.scaled,centers=3,nstart = 25)
fviz_cluster(object=kmeans1,data=bc[2:6],
ellipse.type = "euclid",star.plot=T,repel=T,
geom = ("point"),palette='jco',main="",
ggtheme=theme_minimal())+
theme(axis.title = element_blank())
我们可以见到,分成3类后的第1类(红色箭头部分)虽然数据很少,但是离第3类还是很远的,我个人觉得不应该被归入第一类(个人看法),我们就先按3类来分看看。
summary(kmeans1)
kmeans1$cluster
kmeans1$size
上图可以看到,各种肉类被分进了组,第一组2种,第二组9种,第三组16种
我们把数据集整理一下,如下图,数据被我们分类整理了
aaa <- data.frame(bc[2:6], kmeans1$cluster)
aaa<-arrange(aaa,kmeans1.cluster)
我们对每组的数据进行平均值统计
by_fenzu<-group_by(aaa,kmeans1.cluster)
summarize(by_fenzu,energy=mean(energy),protein=mean(protein),
fat=mean(fat),calcium=mean(calcium),iron=mean(iron))
由上图我们可以得出每组数据的各类指标平均数,因此我们可知,第一种肉类含能量少,蛋白质少,脂肪少,属于没有什么营养的肉类。第二种肉类:能量很多,脂肪也很多,可以参考为油炸的高脂肪垃圾食品。第三种为:低热量,高蛋白质,低脂肪,并且富含钙的肉类,比较适合我们中国人的饮食理念和习惯。这样得出的结论可以在饮食上给出建议。
我们还可以得出每组指标的密度分布情况:
先对数据分组
Data1 <- aaa[which(aaa$kmeans1.cluster == 1), ]
Data2 <- aaa[which(aaa$kmeans1.cluster == 2), ]
Data3 <- aaa[which(aaa$kmeans1.cluster == 3), ]
做能量的分布曲线
par(mfrow = c(1,3))
plot(density(Data1[, 1]), col = "red", main = "1.energy")
plot(density(Data2[, 1]), col = "red", main = "2.energy")
plot(density(Data3[, 1]), col = "red", main = "3.energy")
脂肪的分布曲线
par(mfrow = c(1,3))
plot(density(Data1[, 3]), col = "red", main = "1.fat")
plot(density(Data2[, 3]), col = "red", main = "2.fat")
plot(density(Data3[, 3]), col = "red", main = "3.fat")
其他的指标也可以同理做出来,这里就不一一演示了
我们还可以通过散点图矩阵,将每组的数据关系表示出来,并且以不同颜色区分
pairs(energy~protein+fat+calcium,data = aaa,pch = 21,
bg = c("red", "green3", "blue")[unclass(aaa$kmeans1.cluster)])