聚类-birch(层次方法的平衡迭代规约和聚类)
2017-02-04 11:54
465 查看
birch简述
birch全名利用层次方法的平衡迭代规约和聚类。 birch只需要单遍扫描数据集就可以进行聚类,它最小化IO,天生来应对大数据。brich是通过聚类特征树(CF-tree/ClusterFeature-tree)实现的,单遍扫描数据集后建立一棵存放于内存中的CF-tree,可以看作是数据的多层压缩。
聚类特征
每一个CF是一个三元组,可以用(N,LS,SS)表示。其中N代表这个CF中拥有的样本点的数量;LS代表了这个CF中拥有的样本点各特征维度的和向量,SS代表了这个CF中拥有的样本点各特征维度的平方和。 CF有一个很好的性质,就是满足线性关系,也就是CF1+CF2=(N1+N2,LS1+LS2,SS1+SS2)。 一棵CF树,还需要几个重要参数: B:内部节点平衡因子,每个内部节点的子节点最大个数 L:叶子节点平衡因子,每个叶子节点的子节点最大个数 T:簇直径阈值,每个簇直径最大阈值,超过后,簇分裂
聚类特征树构造
一个聚类特征树样例:算法最初,扫描数据集,拿到第一个数据点,创建一个空的Leaf和MinCluster,MinCluster座位Leaf的一个孩子。
当后续点需要插入树中时,把这个点封装为一个MinCluster,把新到的数据点记为CF_new,从树的根节点开始,根据D2(欧式距离)来找到CF_new与那个节点最近,就把CF_new加入那个子树上面去。这是一个递归的过程。递归的终止点是要把CF_new加入到一个MinCluster中,如果加入之后MinCluster的直径没有超过T,则直接加入,否则CF_new要单独作为一个簇,成为MinCluster的兄弟结点。插入之后注意更新该节点及其所有祖先节点的CF值。
插入新节点后,可能有些节点的孩子数大于了B(或L),此时该节点要分裂对于Leaf,它现在有L+1个MinCluster,我们要新创建一个Leaf,使它作为原Leaf的兄弟结点,同时注意每新创建一个Leaf都要把它插入到双向链表中。L+1个MinCluster要分到这两个Leaf中,怎么分呢?找出这L+1个MinCluster中距离最远的两个Cluster(根据D2),剩下的Cluster看离哪个近就跟谁站在一起。分好后更新两个Leaf的CF值,其祖先节点的CF值没有变化,不需要更新。这可能导致祖先节点的递归分裂,因为Leaf分裂后恰好其父节点的孩子数超过了B。
代码描述
private ClusteringFeature buildCFTree() { NonLeafNode rootNode = null; LeafNode leafNode = null; Cluster cluster = null; for (String[] record : totalDataRecords) { cluster = new Cluster(record); if (rootNode == null) { // CF树只有1个节点的时候的情况 if (leafNode == null) { leafNode = new LeafNode(); } leafNode.addingCluster(cluster); if (leafNode.getParentNode() != null) { rootNode = leafNode.getParentNode(); } } else { if (rootNode.getParentNode() != null) { rootNode = rootNode.getParentNode(); } // 从根节点开始,从上往下寻找到最近的添加目标叶子节点 LeafNode temp = rootNode.findedClosestNode(cluster); temp.addingCluster(cluster); } } // 从下往上找出最上面的节点,返回根节点 LeafNode node = cluster.getParentNode(); NonLeafNode upNode = node.getParentNode(); if (upNode == null) { return node; } else { while (upNode.getParentNode() != null) { upNode = upNode.getParentNode(); } return upNode; } }
可以看出,插入过程是从根节点开始找到最近的添加目标叶子节点,然后调用叶子节点的addingCluster方法把节点添加到树中。
leafNode的addingCluster方法
public void addingCluster(ClusteringFeature clusteringFeature) { //更新聚类特征值 directAddCluster(clusteringFeature); // 寻找到的目标集群 Cluster findedCluster = null; Cluster cluster = (Cluster) clusteringFeature; double disance = Integer.MAX_VALUE; double errorDistance = 0; boolean needDivided = false; if (clusterChilds == null) { clusterChilds = new ArrayList<>(); clusterChilds.add(cluster); cluster.setParentNode(this); } else { for (Cluster c : clusterChilds) { errorDistance = ClusteringFeature.computerClusterDistance(c, cluster); if (errorDistance < disance) { // 选出簇间距离最近的 disance = errorDistance; findedCluster = c; } } ArrayList<double[]> data1 = (ArrayList<double[]>) findedCluster.getData().clone(); ArrayList<double[]> data2 = cluster.getData(); data1.addAll(data2); // 如果添加后的聚类的簇间距离超过给定阈值,需要额外新建簇 if (ClusteringFeature.computerInClusterDistance(data1) > BIRCHTool.T) { // 如果添加后簇的簇间距离超过T,当前簇作为新的簇 clusterChilds.add(cluster); cluster.setParentNode(this); // 叶子节点的孩子数不能超过平衡因子L if (clusterChilds.size() > BIRCHTool.L) { needDivided = true; } } else { findedCluster.directAddCluster(cluster); cluster.setParentNode(this); } } if(needDivided){ if(parentNode == null){ parentNode = new NonLeafNode(); }else{ parentNode.getLeafChilds().remove(this); } LeafNode[] nodeArray = divideLeafNode(); for(LeafNode n: nodeArray){ parentNode.addingCluster(n); } } }
先找到距离最近的簇,把当前簇添加到最近的簇中,如果添加后簇的簇间距离超过T,当前簇作为新的簇,如果叶子节点的孩子数超过平衡因子L,则叶子节点需要分裂。分裂后分裂为2个叶子节点,然后调用非叶子节点的addingCluster方法,依次向上更新父节点。
NonLeafNode的addingCluster方法:
public void addingCluster(ClusteringFeature clusteringFeature) { LeafNode leafNode = null; NonLeafNode nonLeafNode = null; NonLeafNode[] nonLeafNodeArrays; boolean neededDivide = false; // 更新聚类特征值 directAddCluster(clusteringFeature); if (clusteringFeature instanceof LeafNode) { leafNode = (LeafNode) clusteringFeature; } else { nonLeafNode = (NonLeafNode) clusteringFeature; } if (nonLeafNode != null) { neededDivide = addingNeededDivide(nonLeafNode); if (neededDivide) { if (parentNode == null) { parentNode = new NonLeafNode(); } else { parentNode.nonLeafChilds.remove(this); } nonLeafNodeArrays = this.nonLeafNodeDivided(); for (NonLeafNode n1 : nonLeafNodeArrays) { parentNode.addingCluster(n1); } } } else { neededDivide = addingNeededDivide(leafNode); if (neededDivide) { if (parentNode == null) { parentNode = new NonLeafNode(); } else { parentNode.nonLeafChilds.remove(this); } nonLeafNodeArrays = this.leafNodeDivided(); for (NonLeafNode n2 : nonLeafNodeArrays) { parentNode.addingCluster(n2); } } } }
非叶子节点分裂与叶子节点分裂类似。
详细代码参考:
https://github.com/zhanggw/algorithm/tree/master/machine-learning/Birch-Cluster/src/main/java/com/zhanggw/cluster/birch
参考:
http://blog.csdn.net/androidlushangderen/article/details/43532111
http://blog.csdn.net/jiutianhe/article/details/39313333
http://www.cnblogs.com/pinard/p/6179132.html
相关文章推荐
- python中做层次聚类,使用scipy.cluster.hierarchy.fclusterdata方法
- 层次聚类——自底向上方法
- python中做层次聚类,使用scipy.cluster.hierarchy.fclusterdata方法
- 挑子学习笔记:BIRCH层次聚类
- 读书笔记 -- 008_数据挖掘_聚类_基于层次的方法
- 机器学习(34)之BIRCH层次聚类详解
- python中做层次聚类,使用scipy.cluster.hierarchy.fclusterdata方法 - Waleking的专栏 - 博客频道 - CSDN.NET
- 层次聚类——linkage方法
- 聚类方法简介(转)
- 层次聚类的时间控制
- MATLAB解线形方程组的迭代方法
- 使用匿名方法、迭代程序和局部类来创建优雅的代码
- DOM的基本方法 结点 引用 表格 层次
- CIO们,是用什么方法去平衡IT建设的价值与成本?
- 数据挖掘--聚类方法
- 共引聚类分析方法研究
- 利用VS“生成方法存根”—放空层次调用 专注写代码结构
- 聚类分析方法
- C# 2.0:使用匿名方法、迭代程序和局部类来创建优雅的代码
- 自己写的递归方法复制文件夹里面的内容(从源文件(里面可以有多个层次的子文件夹)到一个文件夹)