写mapreduce程序实现kmeans算法,我们的思路可能是这样的
1. 用一个全局变量存放上一次迭代后的质心
2. map里,计算每个质心与样本之间的距离,得到与样本距离最短的质心,以这个质心作为key,样本作为value,输出
3. reduce里,输入的key是质心,value是其他的样本,这时重新计算聚类中心,将聚类中心put到一个全部变量t中。
4. 在main里比较前一次的质心和本次的质心是否发生变化,如果变化,则继续迭代,否则退出。
本文的思路基本上是按照上面的步骤来做的,只不过有几个问题需要解决
1. hadoop是不存在自定义的全局变量的,所以上面定义一个全局变量存放质心的想法是实现不了的,所以一个替代的思路是将质心存放在文件中
2. 存放质心的文件在什么地方读取,如果在map中读取,那么可以肯定我们是不能用一个mapreduce实现一次迭代,所以我们选择在main函数里读取质心,然后将质心set到configuration中,configuration在map和reduce都是可读
3. 如何比较质心是否发生变化,是在main里比较么,读取本次质心和上一次质心的文件然后进行比较,这种方法是可以实现的,但是显得不够高富帅,这个时候我们用到了自定义的counter,counter是全局变量,在map和reduce中可读可写,在上面的思路中,我们看到reduce是有上次迭代的质心和刚刚计算出来的质心的,所以直接在reduce中进行比较就完全可以,如果没发生变化,counter加1。只要在main里比较获取counter的值就行了。
梳理一下,具体的步骤如下
1. main函数读取质心文件
2. 将质心的字符串放到configuration中
3. 在mapper类重写setup方法,获取到configuration的质心内容,解析成二维数组的形式,代表质心
4. mapper类中的map方法读取样本文件,跟所有的质心比较,得出每个样本跟哪个质心最近,然后输出<质心,样本>
5. reducer类中重新计算质心,如果重新计算出来的质心跟进来时的质心一致,那么自定义的counter加1
6. main中获取counter的值,看是否等于质心,如果不相等,那么继续迭代,否在退出
具体的实现如下
1. pom依赖
这个要跟集群的一致,因为如果不一致在计算其他问题的时候没有问题,但是在使用counter的时候会出现问题
java.lang.IncompatibleClassChangeError: Found