分享

Weka开发[43]——OPTICS源代码分析

 lzqkean 2013-07-22

       OPTICS (Ordering points to Identify the Clustering Structure)在论文OPTICS: Ordering Points To Identify the Clustering Structure中提出。这个算法也在wiki中有。

       源代码从buildClusterer开始看:

database = databaseForName(getDatabase_Type(), filteredInstances);

for (int i = 0; i < database.getInstances().numInstances(); i ) {

    DataObject dataObject = dataObjectForName(

           getDatabase_distanceType(), database.getInstances()

                  .instance(i), Integer.toString(i), database);

    database.insert(dataObject);

}

database.setMinMaxValues();

       这部分在DBScan中讲过了。

UpdateQueue seeds = new UpdateQueue();

 

/** OPTICS-Begin */

Iterator iterator = database.dataObjectIterator();

while (iterator.hasNext()) {

    DataObject dataObject = (DataObject) iterator.next();

    if (!dataObject.isProcessed()) {

       expandClusterOrder(dataObject, seeds);

    }

}

       对对样本进行循环,如果没处理过,调用expandClusterOrderexpandClusterOrder调用的第一个函数coreDistance

/**

 * Calculates the coreDistance for the specified DataObject.

 * The returned list contains three elements:

 * At index=0 --> list with all k next-neighbours;

 * At index=1 --> list with all dataObjects within epsilon;

 * At index=2 --> coreDistance as Double-value

 */

public List coreDistance(int minPoints, double epsilon, DataObject dataObject) {

    List list = k_nextNeighbourQuery(minPoints, epsilon, dataObject);

 

    if (((List) list.get(1)).size() < minPoints) {

        list.add(new Double(DataObject.UNDEFINED));

        return list;

    } else {

        List nextNeighbours_List = (List) list.get(0);

        PriorityQueueElement priorityQueueElement =

                (PriorityQueueElement)nextNeighbours_List

.get(nextNeighbours_List.size() - 1);

        if (priorityQueueElement.getPriority() <= epsilon) {

            list.add(new Double(priorityQueueElement.getPriority()));

            return list;

        } else {

            list.add(new Double(DataObject.UNDEFINED));

            return list;

        }

    }

}

       k_nextNeighbourQuery返回的listindex=0是所有的k个邻居,index=1是所有epsilon邻域中的点。如果list.get(1).size()小于minPts,也就是它不是一个核心点,否则就是一个核心点,另外nextNeighbours_List是一个优先队列,所以它最后一个元素就是最远的点。

Weka开发[43]——OPTICS源代码分析 - quweiprotoss - Koala  s blog

        expandClusterOrder前一部分代码为:

List list = database.coreDistance(getMinPoints(), getEpsilon(),

       dataObject);

List epsilonRange_List = (List) list.get(1);

dataObject.setReachabilityDistance(DataObject.UNDEFINED);

dataObject.setCoreDistance(((Double) list.get(2)).doubleValue());

dataObject.setProcessed(true);

 

resultVector.addElement(dataObject);

       得到coreDistance得到的结果,初始化一些变量。

if (dataObject.getCoreDistance() != DataObject.UNDEFINED) {

    update(seeds, epsilonRange_List, dataObject);

    while (seeds.hasNext()) {

       UpdateQueueElement updateQueueElement = seeds.next();

       DataObject currentDataObject = (DataObject) updateQueueElement

              .getObject();

       currentDataObject.setReachabilityDistance(updateQueueElement

              .getPriority());

       List list_1 = database.coreDistance(getMinPoints(),

              getEpsilon(), currentDataObject);

       List epsilonRange_List_1 = (List) list_1.get(1);

       currentDataObject.setCoreDistance(((Double) list_1.get(2))

              .doubleValue());

       currentDataObject.setProcessed(true);

 

       resultVector.addElement(currentDataObject);

 

      if (currentDataObject.getCoreDistance() != DataObject.UNDEFINED) {

           update(seeds, epsilonRange_List_1, currentDataObject);

       }

    }

}

       先看一下update函数:

private void update(UpdateQueue seeds, List epsilonRange_list,

       DataObject centralObject) {

    double coreDistance = centralObject.getCoreDistance();

    double new_r_dist = DataObject.UNDEFINED;

 

    for (int i = 0; i < epsilonRange_list.size(); i ) {

       EpsilonRange_ListElement listElement =

(EpsilonRange_ListElement) epsilonRange_list.get(i);

       DataObject neighbourhood_object = listElement.getDataObject();

       if (!neighbourhood_object.isProcessed()) {

           new_r_dist = Math.max(coreDistance,

listElement.getDistance());

           seeds.add(new_r_dist, neighbourhood_object,

                  neighbourhood_object.getKey());

       }

    }

}

       这里是判断epsilon领域中的点与centralObject的距离,这里seeds中保持的就是可达距离(reachability-distance)

Weka开发[43]——OPTICS源代码分析 - quweiprotoss - Koala  s blog

       中文版的《数据挖掘:概念与技术》第275页,英文版420页有一个例子可以讲清core-distancereachability-distance的关系。

       回到expandClusterOrder中,下面的代码很像是DBScan中的,从一个邻居开始,去扩展这个簇。

       先翻译一段wiki中的解释:

       使用可达图(reachability-plot),簇的层次结构很容易得到,在下图中是一个2维露天,x轴是排过序的点,y轴是可达距离,因为属于一个簇的点s到它们最近的邻居有较低的可达距离值,所以簇在可达图中以谷(valleyby the way,数据挖掘那本书里的翻译有问题)的形式出现,谷越深,簇越紧密(denser)。

       下图中展示了这一概念,在它的上半部分,一个显示了一部分的人工2维数据集。它的下半部分显示了用OPTICS算法计算的可达图,黑色的连线把簇与它对应的谷连起来了。红色的横线表示如何得到一个簇,红线所穿过的谷都是一个簇。如果这个线向下移,就会有更多的簇合并,特别是最上面的簇,即那些变密度特征。

       在这幅图中蓝点被视为噪音,在可达图中没有关于它们的谷。

Weka开发[43]——OPTICS源代码分析 - quweiprotoss - Koala  s blog

       现在的问题是这个图是怎么来的,通过什么方式排的序呢?还是看expandClusterOrder函数,resultVector是最终结果。而且每次都是从seeds中取一个点,seeds是个优先队列,它以升序排序,也就是每次取的都是最小的可达距离,这样就形成了谷状的结构,因为后来越来越找不到一个簇可达距离小的点的了。

 

 

 

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多