你可能用了一个"假的"Kmeans
年三十晚,想起之前写Kmeans聚类的一些感悟。
今天在高铁上,看了一本书,书上又再次出现了这么一句话,我觉得挺好,大体意思是:
在写代码这个事情上,没有人能告诉你怎么做一定对,但是总有人能告诉你,怎么做一定不对
其实在数据分析上,也是如此。分享成功是没有意义的,或者并没有太多价值,反而,分享失败或总结错误,往往能给自己甚至是别人带来更多警示。
在我的认知里面,聚类的方法有很多,但我基本只会用层次聚类里面的hclust(这里以R语言内置函数为例,因为TBtools的聚类算法都是重新用Java实现并以R语言的算法为参照)和动态聚类里面的Kmeans。
其中,今天主要要聊的是R语言Kmeans函数的 坑!!!
Kmeans聚类的大概逻辑是:
1. 设置K个初始聚类中心(存在非常多的选择方法,随机选择几个样本点是比较常用的做法)
2. 按照样本点与聚类中心的距离,将所有样本点各自分配到一个中心(距离最近),这样就得到K个聚类中心
3. 针对K个聚类中心,分别重新计算聚类中心的中心点(存在较多的中心点计算方法,一般直接计算平均值)
4. 分别计算每个聚类中心的平方差,并加和
5. 比较4.计算得到的平方差总和与上一次迭代结果的平方差总和,如果大于上一次平方差总和,那么就结束并输出上一迭代的结果,如果小于上一次平方差综合,那么就继续重复2-5,直到收敛。
这个算法的实现简单粗暴,但是算法本身也存在一些问题
1. 初始聚类中心的个数,和初始聚类中心的选择,直接影响最终结果
2. 按照迭代终止条件,很容易得到一个局部最优值
前者已有报道的改善方法,包括先做hclust,然后kmeans,取距离最大的点
后者也有较多的改善方法提出,包括后续用退火算法,遗传算法等...嗯。。。我差点也在TBtools里面加上退火算法了....
虽然有以上问题,也有挺多的应对方法被提出,然而,被广泛使用的,依然是default mode的Kmeans(虽然默认的Kmeans本身也有很多类别,类别之间没有太多差距,无需担心)
以下必然是中文资料,甚至包括英文资料里面,我个人对R语言内置函数Kmeans的参数理解,
kmeans(x, centers, iter.max = 10, nstart = 1,
algorithm = c("Hartigan-Wong", "Lloyd", "Forgy",
"MacQueen"), trace=FALSE)
x: numeric matrix of data, or an object that can be coerced to
such a matrix (such as a numeric vector or a data frame with
all numeric columns). # 输入的向量
centers: either the number of clusters, say k, or a set of initial
(distinct) cluster centres. If a number, a random set of
(distinct) rows in 'x’ is chosen as the initial centres. # 输入初始聚类中心向量 或者 初始聚类中心个数
iter.max: the maximum number of iterations allowed. # 设置迭代次数
nstart: if 'centers’ is a number, how many random sets should be
chosen? # 如果前述输入的是 初始聚类中心个数,那么设置重复进行Kmeans的次数,最终会从所有Kmeans执行结果中选择一个最优的
algorithm: character: may be abbreviated. Note that '"Lloyd"’ and
'"Forgy"’ are alternative names for one algorithm. # 以下略,因为确实没太大影响
object: an R object of class '"kmeans"’, typically the result
'ob’ of 'ob <- kmeans(..)’.
method: character: may be abbreviated. '"centers"’ causes
'fitted’ to return cluster centers (one for each input
point) and '"classes"’ causes 'fitted’ to return a vector
of class assignments.
trace: logical or integer number, currently only used in the default
method ('"Hartigan-Wong"’): if positive (or true), tracing
information on the progress of the algorithm is produced.
Higher values may produce more tracing information.
R语言内置Kmeans函数里面,设置了两个默认参数,往往并不合适
1. iter.max = 10 设置这个参数,意味着迭代10次之后,即使未收敛, 也直接终止并输出结果,这就意味着,连局部最优都尚未达到...这个当然可能节省时间,但是在我们做数据分析过程中,Kmeans实在太快,没必要卡10次,或者最好不要只卡10次,建议更高....如果不是脚本执行,那么可以直接默认10次出结果,因为如果未收敛,R会出警告信息;然而脚本执行,那么就要注意啦。。。比如夸张点,你调整到100
2. nstart = 1 这个参数,怎么说呢,存在风险。往往我们并没有预制的聚类心中列表,那么就会随机选择K个样本点并开始迭代,nstart的次数,意味着重新选择并迭代的次数。也就相当于对统一数据运行多少次Kmeans聚类分析,这样会得到多个结果,Kmeans这个函数会选择一个最优的输出(也就是聚类内平方差总和最低的结果)。如果这个设置为1,那么得到局部最优的几率就比较大,相反这个值设置越高,那么就是对不同起始聚类中心集合进行不同次数的Kmeans,那么就更有可能得到全局最优(这个才是我们想要的)。...R语言是不会提示是不是全局最优的。一般,不是很着急的话,这个值应该调整在20~25(运行时间也会大概在20~25倍,一般一样是秒速,除非数据集合真的也不小)
总体上,我只是想说,其实,你可能用了一个“假的”Kmeans。。。。