Canopy算法的实现在包org.apache.mahout.clustering.canopy中。
一、算法基本思想
算法基本思想如下:
(1)、将数据集向量化得到一个list后放入内存,选择两个距离阈值:T1和T2,其中T1 > T2,T1和T2的值可以用交叉校验来确定;
(2)、从list中任取一点P,用低计算成本方法快速计算点P与所有Canopy之间的距离(如果当前不存在Canopy,则把点P作为一个Canopy),如果点P与某个Canopy距离在T1以内,则将点P加入到这个Canopy;
(3)、如果点P曾经与某个Canopy的距离在T2以内,则需要把点P从list中删除(不过在在新的mahout采用的 不加入新的Collection 这样后面处理的时候就不包含点P),这一步是认为点P此时与这个Canopy已经够近了,因此它不可以再做其它Canopy的中心了;
(4)、重复步骤2、3,直到list为空结束。
算法思想参考博客http://www.cnblogs.com/vivounicorn/archive/2011/09/23/2186483.html
二、源码分析
下面我们来看一下这个包里面的类。
2.1 CanopyConfigKeys
CanopyConfigKeys类主要定义了Canopy算法中需要使用的一些配置参数的名称。具体每个参数的作用如下:
String T1_KEY = "org.apache.mahout.clustering.canopy.t1";
String T2_KEY = "org.apache.mahout.clustering.canopy.t2";
String T3_KEY = "org.apache.mahout.clustering.canopy.t3";
String T4_KEY = "org.apache.mahout.clustering.canopy.t4";
T1和T2为算法设定的阈值,具体参见前面的算法思想,T3和T4也是,不同之处在与,在单机跑canopy算法时mahout只使用了T1和T2,在运行Map-Reduce版本的Canopys算法时,Map阶段使用的T1和T2,Reduce阶段使用的T3和T4,也就是说Map和Reduce阶段的阈值可以不一样。
String CANOPY_PATH_KEY = "org.apache.mahout.clustering.canopy.path";//这个好像没有见到怎么用的
String DISTANCE_MEASURE_KEY = "org.apache.mahout.clustering.canopy.measure";//canopy算法需要计算每个向量与canopy的距离,使用的就是这个
String CF_KEY = "org.apache.mahout.clustering.canopy.canopyFilter";//这个是一个阈值,当一个canopy里面的样本数目大于这个阈值的时候才算作一个canopy
2.2Canopy
Canopy类继承了类DistanceMeasureCluster,没有做什么事情,真正实现canopy算法的是类CanopyClusterer。
2.3CanopyClusterer
CanopyClusterer的构造函数需要传入一个距离计算类和两个double类型的参数。
public CanopyClusterer(DistanceMeasure measure, double t1, double t2) {
this.t1 = t1;
this.t2 = t2;
this.t3 = t1;
this.t4 = t2;
this.measure = measure;
}
我们也可以通过传入一个Configuration类型的变量来构造一个CanopyClusterer,其中Configuration是hadoop中的类,我们可以在这个Configuration对象中设定距离计算类,T1,T2,T3和T4等参数,
CanopyClusterer的构造函数会利用Configuration初始化类的属性。
public CanopyClusterer(Configuration config) {
this.configure(config);
}
public void configure(Configuration configuration) {
// 初始化距离计算公式
measure = ClassUtils.instantiateAs(
configuration.get(CanopyConfigKeys.DISTANCE_MEASURE_KEY),
DistanceMeasure.class);
measure.configure(configuration);
t1 = Double.parseDouble(configuration.get(CanopyConfigKeys.T1_KEY));
t2 = Double.parseDouble(co