R语言实现聚类kmeans

栏目: 编程工具 · 发布时间: 5年前

R语言实现聚类kmeans

作者:张丹,R语言中文社区专栏特邀作者,《R的极客理想》系列图书作者,民生银行大数据中心数据分析师,前况客创始人兼CTO。

个人博客  http://fens.me , Alexa全球排名70k。

前言

聚类属于无监督学习中的一种方法,k-means作为数据挖掘的十大算法之一,是一种最广泛使用的聚类算法。我们使用聚类算法将数据集的点,分到特定的组中,同一组的数据点具有相似的特征,而不同类中的数据点特征差异很大。PAM是对k-means的一种改进算法,能降低异常值对于聚类效果的影响。

聚类可以帮助我们认识未知的数据,发现新的规律。

目录

  1. k-means实现

  2. PAM实现

  3. 可视化和段剖面图

1.k-means实现

k-means算法,是一种最广泛使用的聚类算法。k-means以k作为参数,把数据分为k个组,通过迭代计算过程,将各个分组内的所有数据样本的均值作为该类的中心点,使得组内数据具有较高的相似度,而组间的相似度最低。

k-means工作原理:

  1. 初始化数据,选择k个对象作为中心点。

  2. 遍历整个数据集,计算每个点与每个中心点的距离,将它分配给距离中心最近的组。

  3. 重新计算每个组的平均值,作为新的聚类中心。

  4. 上面2-3步,过程不断重复,直到函数收敛,不再新的分组情况出现。

k-means聚类,适用于连续型数据集。在计算数据样本之间的距离时,通常使用欧式距离作为相似性度量。k-means支持多种距离计算,还包括maximum, manhattan, pearson, correlation, spearman, kendall等。各种的距离算法的介绍,请参考文章 R语言实现46种距离算法

1.1

kmeans()函数实现

在R语言中,我们可以直接调用系统中自带的kmeans()函数,就可以实现k-means的聚类。同时,有很多第三方算法包也提供了k-means的计算函数。当我们需要使用kmeans算法,可以使用第三方扩展的包,比如flexclust, amap等包。

本文的系统环境为:

  • Win10 64bit

  • R: 3.4.4 x86_64-w64-mingw32

接下来,让我们做一个k-means聚类的例子。首先,创建数据集:

 1# 创建数据集
2> set.seed(0)
3> df <- rbind(matrix(rnorm(100, 0.5, 4.5), ncol = 2),
4+ matrix(rnorm(100, 0.5, 0.1), ncol = 2))
5> colnames(df) <- c("x", "y")
6> head(df)
7 x y
8[1,] 6.1832943 1.6976181
9[2,] -0.9680501 -1.1951622
10[3,] 6.4840967 11.4861408
11[4,] 6.2259319 -3.0790260
12[5,] 2.3658865 0.2530514
13[6,] -6.4297752 1.6256360

使用stats::kmeans()函数,进行聚类。

 1> cl <- kmeans(df,2); cl
2K-means clustering with 2 clusters of sizes 14, 86
3
4Cluster means: # 中心点坐标
5 x y
61 5.821526 2.7343127
72 -0.315946 0.1992429
8
9Clustering vector: # 分组的索引
10 [1] 1 2 1 1 2 2 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 2 2 2 2 2 2 2 1 1 2 1 2 1 2 2 2 2 2 2 1 1 2
11 [51] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
12
13Within cluster sum of squares by cluster:
14[1] 316.0216 716.4009 # withinss,分组内平方和
15 (between_SS / total_SS = 34.0 %) # 组间的平方和/总平方和,用于衡量点聚集程度
16
17Available components: # 对象属性
18[1] "cluster" "centers" "totss" "withinss" "tot.withinss" "betweenss"
19[7] "size" "iter" "ifault"
20
21# 查看数据分组情况,第1组86个,第2组14个
22> cl$size
23[1] 86 14

对象属性解读:

  • cluster,每个点的分组

  • centers,聚类的中心点坐标

  • totss,总平方和

  • withinss,每个分组内的平方和

  • tot.withinss,分组总和,sum(withinss)

  • betweenss,组间的平方和,totss – tot.withinss

  • size,每个组中的数据点数量

  • iter,迭代次数。

  • ifault,可能有问题的指标

1.2

kcca()函数实现

我们再使用flexclust::kcca()函数,进行聚类。

 1# 安装flexclust包
2> # install.packages("flexclust")
3> library(flexclust)
4
5# 进行聚类
6> clk<-kcca(df,k=2);clk
7kcca object of family ‘kmeans’
8
9call:
10kcca(x = df, k = 2)
11
12cluster sizes: # 聚类的分组大小
13 1 2
1484 16
15
16# 聚类的中心
17> clk@centers
18 x y
19[1,] -0.3976465 0.2015319
20[2,] 5.4832702 2.4054118
21
22# 查看聚类的概览信息
23> summary(clk)
24kcca object of family ‘kmeans’
25
26call:
27kcca(x = df, k = 2)
28
29cluster info: # 每个组的基本信息,包括分组数量,平均距离、最大距离、分割值
30 size av_dist max_dist separation
311 84 2.102458 9.748136 3.368939
322 16 3.972920 9.576635 3.189891
33
34convergence after 5 iterations # 5次迭代
35sum of within cluster distances: 240.1732 # 聚类距离之和

我们比较2个不同包的k-means算法,所得到的分组数据都是一样的,中心点位置略有一点偏差。接下来,我们可以把聚类画图。

1> plot(df, col = cl$cluster, main="Kmeans Cluster")
2> points(cl$centers, col = 1:3, pch = 10, cex = 4) # 画出kmeans()函数效果

R语言实现聚类kmeans

从上图中看到k-means的总分2组,每个组的中心点分别用红色十字圆圈和黑色十字圆圈表示,为组内的所有数据样本的均值。再叠加上kcca()函数聚类后的中心点画图。

1> points(clk@centers, col = 3:4, pch = 10, cex = 4)  # 画出kcca()函数效果

R语言实现聚类kmeans 新的中心点,分别用别用绿色十字圆圈和蓝色十字圆圈表示。虽然我们使用了相同的算法,分组个数也相同,但中心点还有一些不同的。

这里其实就要对聚类的稳定性进行判断了,有可能是聚类迭代次数过少,就会出现不同的聚类结果,就需要增加迭代次数,达到每次计算结果是一致的。也有可能是因为不同的包,实现的代码有所区别导致的。

k-means算法,也有一些缺点就是对于孤立点是敏感的,会被一些极端值影响聚类的效果。一种改进的算法是PAM,用于解决这个问题。PAM不使用分组平均值作为计算的参照点,而是直接使用每个组内最中心的对象作为中心点。

2.PAM实现

PAM(Partitioning Around Medoids),又叫k-medoids,它可以将数据分组为k个组,k为数量是要事前定义的。PAM与k-means一样,找到距离中心点最小点组成同一类。PAM对噪声和异常值更具鲁棒性,该算法的目标是最小化对象与其最接近的所选对象的平均差异。PAM可以支持混合的数据类型,不仅限于连续变量。

PAM算法分为两个阶段:

  1. 第1阶段BUILD,为初始集合S选择k个对象的集合。

  2. 第2阶段SWAP,尝试用未选择的对象,交换选定的中心点,来提高聚类的质量。

PAM的工作原理:

  1. 初始化数据集,选择k个对象作为中心。

  2. 遍历数据点,把每个数据点关联到最近中心点m。

  3. 随机选择一个非中心对象,与中心对象交换,计算交换后的距离成本

  4. 如果总成本增加,则撤销交换的动作。

  5. 上面2-4步,过程不断重复,直到函数收敛,中心不再改变为止。

优点与缺点:

  • 消除了k-means算法对于孤立点的敏感性。

  • 比k-means的计算的复杂度要高。

  • 与k-means一样,必须设置k的值。

  • 对小的数据集非常有效,对大数据集效率不高。

在R语言中,我们可以通过cluster包来使用pam算法函数。cluster包的安装很简单,一条命令就安装完了。

1> install.packages("cluster")
2> library(cluster)

pam()函数定义:

1pam(x, k, diss = inherits(x, "dist"), metric = "euclidean",
2 medoids = NULL, stand = FALSE, cluster.only = FALSE,
3 do.swap = TRUE,
4 keep.diss = !diss && !cluster.only && n < 100,
5 keep.data = !diss && !cluster.only,
6 pamonce = FALSE, trace.lev = 0)

参数列表:

  • x,数据框或矩阵,允许有空值(NA)

  • k,设置分组数量

  • diss,为TRUE时,x为距离矩阵;为FALSE时,x是变量矩阵。默认为FALSE

  • metric,设置距离算法,默认为euclidean,距离矩阵忽略此项

  • medoids,指定初始的中心,默认为不指定。

  • stand,为TRUE时进行标准化,距离矩阵忽略此项。

  • cluster.only,为TRUE时,仅计算聚类结果,默认为FALSE

  • do.swap,是否进行中心点交换,默认为TRUE;对于超大的数据集,可以不进行交换。

  • keep.diss,是否保存距离矩阵数据

  • keep.data,是否保存原始数据

  • pamonce,一种加速算法,接受值为TRUE,FALSE,0,1,2

  • trace.lev,日志打印,默认为0,不打印

我们使用上面已创建好的数据集df,进行pam聚类,设置k=2。

 1> kclus <- pam(df,2)
2
3# 查看kclus对象
4> kclus
5Medoids: # 中心点
6 ID x y
7[1,] 27 5.3859621 1.1469717
8[2,] 89 0.4130217 0.4798659
9
10Clustering vector: # 分组
11 [1] 1 2 1 1 2 2 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 1 2 1 1 2 2 2 2 2 2 2 1 1 1 2 1 2 1 2 2 2 2 2 2 1 1 2
12 [51] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
13
14Objective function: # 目标函数的局部最小值
15 build swap
162.126918 2.124185
17
18Available components: # 聚类对象的属性
19 [1] "medoids" "id.med" "clustering" "objective" "isolation" "clusinfo" "silinfo"
20 [8] "diss" "call" "data"
21
22> kclus$clusinfo # 聚类的分组数量,每个组的平均距离、最大距离、分割值
23 size max_diss av_diss diameter separation
24[1,] 15 10.397323 4.033095 17.35984 1.556862
25[2,] 85 9.987604 1.787318 15.83646 1.556862

属性解读:

  • medoids,中心点的数据值

  • id.med,中心点的索引

  • clustering,每个点的分组

  • objective,目标函数的局部最小值

  • isolation,孤立的聚类(用L或L*表示)

  • clusinfo,每个组的基本信息

  • silinfo,存储各观测所属的类、其邻居类以及轮宽(silhouette)值

  • diss,不相似度

  • call,执行函数和参数

  • data,原始数据集

把聚类画图输出。

1# 画图
2> plot(df, col = kclus$clustering, main="Kmedoids Cluster")
3> points(kclus$medoids, col = 1:3, pch = 10, cex = 4)

R语言实现聚类kmeans

图中,PAM聚类后分为2组,红色一组,黑色一组,用十字圆圈表示2个中心点,可以清晰地看到中心点就是数据点。

我们可以在开始计算时,设置聚类的中心点,为索引1,2坐标点,打印聚类的日志,查看计算过程。

 1# 设置聚类的中心为1,2
2> kclus2<-pam(df,2,medoids=c(1,2),trace.lev=20)
3C pam(): computing 4951 dissimilarities from 100 x 2 matrix: [Ok]
4pam()'s bswap(*, s=21.837, pamonce=0): medoids given
5 after build: medoids are 1 2
6 and min.dist dysma[1:n] are
7 0 0 9.79 4.78 3.63 6.15 5.23 0.929 8.44 8.59
8 2.29 2.69 4.48 1.19 1.98 2.81 5.39 4.2 3.72 4.56
9 1.84 3.99 2.4 2.7 4.84 5.08 0.969 2.01 4.94 5.06
10 1.94 7.4 5.19 1.62 3.94 3.12 3.51 0.65 4.46 4.61
11 5.16 4.57 1.82 3.21 5.79 4.01 5.59 5.38 1.95 6.2
12 2.41 2.09 2.2 2.43 2.24 2.26 2.09 2.39 2.21 2.33
13 2.24 2.14 2.45 2.37 2.2 2.37 2.13 2.33 2.25 2.18
14 2.38 2.19 2.15 2.14 2.1 2.39 2.24 2.24 2.12 2.14
15 2.34 2.18 2.25 2.26 2.33 2.17 2.18 2.12 2.17 2.27
16 2.29 2.26 2.38 2.12 2.25 2.33 2.09 2.21 2.24 2.13
17 swp new 89 <-> 2 old
; decreasing diss. 306.742 by -93.214
18 swp new 27 <-> 1 old; decreasing diss. 213.528 by -1.10916
19end{bswap()}, end{cstat()}
20
21# 查看中心
22> kclus2$id.med
23[1] 27 89

通过日志查看,我们可以清楚地看到,2个中心的选择过程,分别用89替换1,距离成本减少93.214,用27替换2,距离成本减少1.1。

PAM作为k-means的一种改进算法,到底结果是否更合理,还要看最终哪种结果能够准确地表达业务的含义,被业务人员所认可,就需要不断地和业务人员来沟通。

3.可视化和段剖面图

我们实现了聚类计算后,通常需要把复杂的数据逻辑,用简单的语言和图形来解释给业务人员,聚类的可视化就很重要的。如果数据量不太大,参与聚类的指标维度不太多的时候,我们可以用2维散点图,把指标两两画出来。

我们对iris数据集,进行k-means聚类分成3组,画出聚类后的2维散点图结果。

1> res <- kmeans(iris[,1:4], centers=3)
2> pairs(iris, col = res$cluster + 1)

R语言实现聚类kmeans 每2个维度就会生成一张图, 我们可以全面直观的看到聚类的效果。

高级画图工具,使用GGally包中的ggpairs()函数。

1> library(GGally)
2> ggpairs(iris,columns = 1:5,mapping=aes(colour=as.character(res$cluster)))

R语言实现聚类kmeans

图更漂亮了而且包含更多的信息,除了2维散点图,还包括了相关性检查,分布图,分箱图,频率图等。用这样的可视化效果图与业务人员沟通,一定会非常愉快的。

但是如果数据维度,不止3个而是30个,数据量也不是几百个点,而是几百万个点,再用2维散点图画出来就会很难看了,而且也表达不清,还会失去重点,计算的复杂度也是非常的高。

当数据量和数据维度多起来,我们就需要用段剖面图来做展示了,放弃个体特征,反应的群体特征和规律。

使用flexclust包中的barchart()函数,画出段剖面图,我们还是用iris数据集进行举例。

 1> library(flexclust)
2> clk2 <- cclust(iris[,-5], k=3);clk2
3kcca object of family ‘kmeans’
4
5call:
6cclust(x = iris[, -5], k = 3)
7
8cluster sizes:
9 1 2 3
1039 61 50
11
12# 画出段剖面图
13> barchart(clk2,legend=TRUE)

R语言实现聚类kmeans

如上图所示,每一区块是一个类别,每行是不同的指标。红点表示均值,柱状是这个类别每个指标的情况,透明色表示不重要指标。

查看段剖面图,可以清楚的看到,每个分组中特征是非常明显的。

  • Cluster1中,有39个数据点占26%,Sepal.Width指标在均值附近,其他指标都大于均值。

  • Cluster2中,有61个数据点占41%,Sepal.Width指标略小于均值,其他指标在均值附近。

  • Cluster3中,有50个数据点占33%,Sepal.Width略大于均值,其他指标都小于均值。

从段剖面图,我们可以一眼就能直观地发现数据聚类后的每个分组的总体特征,而不是每个分组中数据的个体特征,对于数据的解读是非常有帮助的。

对于段剖面图,原来我并不知道是什么效果。在和业务人员沟通中,发现他们使用SAS软件做出了很漂亮的段剖面图,而且他们都能理解,后来我发现R语言也有这个 工具 函数,图确实能极大地帮助进行数据解读,所以写了这篇文章记录一下。

本文介绍了k-means的聚类计算方法和具体的使用方法,也是对最近做了一个聚类模型的总结。作为数据分析师,我们不仅自己能发现数据的规律,还要让业务人员看明白你的思路,看懂数据的价值,这也是算法本身的价值。

R语言实现聚类kmeans

往期精彩:

R语言实现聚类kmeans

公众号后台回复关键字即可学习

回复  爬虫             爬虫三大案例实战

回复  Python        1小时破冰入门

回复  数据挖掘      R语言入门及数据挖掘

回复  人工智能      三个月入门人工智能

回复  数据分析师   数据分析师成长之路 

回复  机器学习      机器学习的商业应用

回复  数据科学      数据科学实战

回复  常用算法     

常用数据挖掘算法

本文由R语言中文社区 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。

转载、引用前需联系作者,并署名作者且注明文章出处。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

机器学习实战:基于Scikit-Learn和TensorFlow

机器学习实战:基于Scikit-Learn和TensorFlow

Aurélien Géron / 王静源、贾玮、边蕤、邱俊涛 / 机械工业出版社 / 2018-8 / 119.00

本书主要分为两个部分。第一部分为第1章到第8章,涵盖机器学习的基础理论知识和基本算法——从线性回归到随机森林等,帮助读者掌握Scikit-Learn的常用方法;第二部分为第9章到第16章,探讨深度学习和常用框架TensorFlow,一步一个脚印地带领读者使用TensorFlow搭建和训练深度神经网络,以及卷积神经网络。一起来看看 《机器学习实战:基于Scikit-Learn和TensorFlow》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具