聚类算法之划分方法聚类
1,原型聚类(划分方法):给定一个n个对象的集合,划分方法构建数据的K个分区。大部分划分方法是基于距离的,所以只能发现球类簇。为了达到全局最优,K值需要全局遍历。计算量太大。普遍采用了流行的启发式算法。如K均值和k-中心点算法,渐进的提高聚类质量,逼近局部最优解,这些启发聚类算法适合发现中小规模的数据的球状簇。
划分方法的基本特点:
(1) 发现球状互斥的簇
(2) 基于距离
(3) 可以用均值或者中心点代表簇的中心
(4) 对中小规模数据有效
K均值算法
K-均值算法原理:
(1)对于给定的数据集,首先随机选取K个样本作为初始均值向量。
(2)遍历数据集,找到距离最近的中心点,加入该簇。
(3)重新计算K个簇的中心点。
If u(i)!=U(i)
更新中心点
(4)重复(2)(3)直到所有的中心点向量均不在发生改变。
为了避免运行时间过长,通常设置一个最大运行轮数或者最小调整幅度阈值。若达到最大轮数或调整幅度小于阈值,则停止运行。
划分算法这一模块,首先讲K-MEANS算法,从K-MEANS的原理,优缺点,改进方向方面,将其他划分方法的聚类算法引出来。
K均值算法分析:
(1)不能保证K均值算法收敛于全局最优解,常常终止于局部最优解。结果可能依赖于初始簇中心的随机选择。实践中,为了得到好的结果,通常以不同的初始簇中心,多次运行K-均值算法。(初始簇中心的选择对结果的影响)
(2)K-Means算法的时间复杂度为O(nkt),其中n是对象总数,k是簇数,t是迭代次数。对于处理大数据集,该算法是相对可伸缩和有效的。
(3) 需要事先知道要K值是该算法的一个缺点改进之一:提供K值的近似范围,使用分析技术,比较不同K值得到的聚类效果。K均值算法不能够发现非凸状的簇,或者大小差别很大的簇。此外对噪声和离群点敏感,因此少量的这类数据就能够对均值产生极大的影响。
K均值缺点总结:
(1)算法需要人工输入参数K的值,而K值取值的不同,将导致聚类结果的质量和时间的不同。(K值的选取)
(2)算法初始聚类中也的选择直接影响了聚类结果的质量,与算法运行的效率也是息息相关的,随机选取聚类中也,就有陷入局部最优解(即代价函数取极小值)的情况,这样就无法达到最优解,严重影响聚类质量。(初始化的K歌中心的选择)
(3)由于算法的距离计算量为欧几里德距离,用此距离计算,将形成球状或者类球状的簇。对于不同形状的数据分布还有不完善的地方。(球状簇)
(4)对未经过预处理的异常数据非常敏感,因为异常数据的存在严重影响了聚类结果的质量。(对异常值敏感)
(5)算法每次迭代需要计算数据集中各个数据点到聚类中也的距离,根据距离矩阵来重新分配数据到各个簇中,运算量庞大,耗时而低效。(效率低下)
(6)对标称属性无法计算均值,标称属性无法使用K-均值。(标称属性)
(7)算法是无监督的学习式聚类方法,当处理有初始类或者标签类属性的数据时,需要一种半监督半学习式的处理模式,如果任算法自由运算,聚类结果很可能得不到用户的肯定。
接下来根绝K-MEANS的主要缺点,逐一进行改进。
K-MEANS的JAVA代码: 大家可以参考一下,实现比较简单。
package cluster.com;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class KMeans {
private static double[][] DATA = { { 5.1, 3.5, 1.4, 0.2},
{ 4.9, 3.0, 1.4, 0.2 },{ 4.7, 3.2, 1.3, 0.2 },
{ 4.6, 3.1, 1.5, 0.2 },{ 5.0, 3.6, 1.4, 0.2 },
{ 7.0, 3.2, 4.7, 1.4 },{ 6.4, 3.2, 4.5, 1.5 },
{ 6.9, 3.1, 4.9, 1.5 },{ 5.5, 2.3, 4.0, 1.3 },
{ 6.5, 2.8, 4.6, 1.5 },{ 5.7, 2.8, 4.5, 1.3 },
{ 6.5, 3.0, 5.8, 2.2 },{ 7.6, 3.0, 6.6, 2.1 },
{ 4.9, 2.5, 4.5, 1.7 },{ 7.3, 2.9, 6.3, 1.8 },
{ 6.7, 2.5, 5.8, 1.8 },{ 6.9, 3.1, 5.1, 2.3 } };
public int k;//k个中心点
public int[] memberShip;
public int[] centersIndex;
public double[][] centers;
public int[] elementsInCenters;
public static void main(String[] args) {
KMeans kmeans = new KMeans(5);
String lastMembership = "";
String nowMembership = "";
int i=0;
while(true){
i++;
kmeans.randomCenters();
kmeans.calMemberShip();
nowMembership = Arrays.toString(kmeans.memberShip);
System.out.println("DATA聚类之后Membership为:"+nowMembership);
System.out.println("Elements in centers cnt:"+Arrays.toString(kmeans.elementsInCenters));
if(nowMembership.equals(lastMembership)){
System.out.println("本次聚类与上次相同,退出执行!");
System.out.println("一共聚类了 "+i+" 次!");
kmeans.calNewCenters();
System.out.println("新中心点为:"+Arrays.deepToString(kmeans.centers));
double totalDistance = kmeans.computeTotalDistance();
System.out.println("totalDistance : "+totalDistance);
break;
}else{
lastMembership = nowMembership;
}
System.out.println("----------------华丽的分割线----------------");
}
}
public KMeans(int k){
this.k = k;
}
public double manhattanDistince(double []paraFirstData,double []paraSecondData){
double tempDistince = 0;
if((paraFirstData!=null && paraSecondData!=null) && paraFirstData.length==paraSecondData.length){
for(int i=0;i