在运行Mahout K-means时遇到一种奇怪的情况: 使用一组预先选择的初始质心,我在lucene.vector生成的SequenceFile上运行K-means。该运行用于测试目的,因此文件很小(大约10MB~10000个向量)。
当使用单个映射器执行K-means时(默认情况下,考虑到我的集群中的Hadoop拆分大小为128MB),它在2次迭代中达到给定的聚类结果(情况A)。 但是,我想通过激发更多的映射任务来测试算法的执行速度是否会有任何改进/恶化(Hadoop集群总共有6个节点)。 因此,我将-Dmapred.max.split.size参数设置为5242880字节,以便使mahout fire 2映射任务(案例B)。 我确实成功地启动了两个映射器,但奇怪的是,作业在5次迭代而不是2次之后完成,即使在第一次分配点时,映射器与单映射执行相比做出了不同的选择。我的意思是,在两个案例的第一次迭代中仔细检查了clusterDump之后,我发现在案例B中,某些点没有分配给它们最近的集群。
现有的K-means Mahout实现是否可以证明这种行为是正确的?
答案 0 :(得分:1)
通过快速浏览来源,我看到了Mahout k-means实现的两个问题。
首先,对于大型数据集,保留S0,S1,S2统计数据的方式可能在数值上不稳定。哦,因为k-means实际上甚至不使用S2,所以它也是不必要的慢。我敢打赌,一个好的实现可以至少以2-5倍的优势击败这个版本的k-means。
对于拆分到多台计算机上的小型数据集,计算其均值的方式似乎存在错误。哎哟。如果减速器应用于多个输入,这将放大,特别是当分区很小时。为了更加详细,显然使用先前的均值而不是0向量初始化聚类均值。现在,如果你减少它的't'副本,结果向量将比前一个平均值减去't'。
初始化AbstractCluster
:
setS1(center.like());
更新均值:
getS1().assign(x, Functions.PLUS);
合并群集的多个副本:
setS1(getS1().plus(cl.getS1()));
最终确定新中心:
setCenter(getS1().divide(getS0()));
因此,使用此方法,中心将偏离前一个中心时间t / n
的正确值,其中t
是分割数,n
是对象数。
为了解决数值不稳定性(每当数据集不以0向量为中心时出现),我建议用真实均值替换S1统计量,而不是S0 *均值。使用AFAICT在MacQueen的原始“k-means”出版物(实际上是在线kmeans,而这是Lloyd样式批量迭代)中使用的增量均值公式,可以以很少的成本逐步更新S1和S2。好吧,对于增量k均值,你显然需要可更新的均值向量...我相信Knuth在他的基本书中也讨论了这个公式。我很惊讶Mahout似乎没有使用它。它相当便宜(只需几个CPU指令,没有额外的数据,所以它都发生在CPU缓存行中),并且在处理大型数据集时为您提供额外的精度。