热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mahout探索之旅——kmeans算法(上)

K-Means算法是聚类算法,k在在这里指的是分类的类型数(根据经验指出会出现几个类别),所以在开始设定的时候非常关键,算法的原理是首先假定k个分类点,然后根据欧式距离计算分类,然后去同分类的均

K-Means算法是聚类算法,k在在这里指的是分类的类型数(根据经验指出会出现几个类别),所以在开始设定的时候非常关键,算法的原理是首先假定k个分类点,然后根据欧式距离计算分类,然后去同分类的均值作为新的聚簇中心,循环操作直到收敛。算法的关键在K个值的选取上,如果均值选得恰当将有利于算法的快速收敛。

Kmeans算法的执行过程的伪代码可概括为如下:

Kmeans算法时间复杂度:O(tkmn),其中t为迭代次数,K为簇数目;

Kmeans算法空间复杂度:O((m+k)n),m为记录数,n为维数;

K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一。K-means算法的基本思想是:以空间中k个点为中心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各聚类中心的值,直至得到最好的聚类结果。

距离的度量

常用的距离度量方法包括:欧几里得距离和余弦相似度。两者都是评定个体间差异的大小的。欧几里得距离度量会受指标不同单位刻度的影响,所以一般需要先进行标准化,同时距离越大,个体间差异越大;空间向量余弦夹角的相似度度量不会受指标刻度的影响,余弦值落于区间[-1,1],值越大,差异越小。但是针对具体应用,什么情况下使用欧氏距离,什么情况下使用余弦相似度?

从几何意义上来说,n维向量空间的一条线段作为底边和原点组成的三角形,其顶角大小是不确定的。也就是说对于两条空间向量,即使两点距离一定,他们的夹角余弦值也可以随意变化。感性的认识,当两用户评分趋势一致时,但是评分值差距很大,余弦相似度倾向给出更优解。举个极端的例子,两用户只对两件商品评分,向量分别为(3,3)和(5,5),这两位用户的认知其实是一样的,但是欧式距离给出的解显然没有余弦值合理。

算法的停止条件

一般是目标函数达到最优或者达到最大的迭代次数即可终止。对于不同的距离度量,目标函数往往不同。当采用欧式距离时,目标函数一般为最小化对象到其簇质心的距离的平方和,如下:

                                                                                                      

当采用余弦相似度时,目标函数一般为最大化对象到其簇质心的余弦相似度和,如下:

Kmeans算法特点

该算法的最大优势在于简洁和快速。算法的关键在于初始中心的选择和距离公式。

Kmenas算法试图找到使平均误差准则函数最小的簇。当潜在的簇形状是凸面的,簇与簇之间区别较明显,且簇大小相近时,其聚类结果较理想。前面提到,该算法时间复杂度为O(tKmn),与样本数量线性相关,所以,对于处理大数据集合,该算法非常高效,且伸缩性较好。但该算法除了要事先确定簇数K和对初始聚类中心敏感外,经常以局部最优结束,同时对“噪声”和孤立点敏感,并且该方法不适于发现非凸面形状的簇或大小差别很大的簇。

算法理解

或许对上述描述,有人还是对kmeans算法不太理解,下面通过形象化的图形来加深理解。假设研究的数据点不是很多,小到还是可以用二维坐标来表示(如下图,大概有两个类)。


取K=2,现随机取两个点(点1,点2),计算所有的点到点1、2的距离,形成c图(红色属于点1的类,蓝色属于点2的类),计算各类的平均值(中心点)(如d图);以d图中的两个x点为k均值点,进行第二次迭代,再进行上述同样的距离计算过程,直至图f结束。算法结束的条件是簇质心的距离的平方和最小(一般迭代次数大于k值)。

算法改进意见

由kmeans算法特点知道,算法对噪声和孤立点很敏感,需要作平滑去噪处理,把不必要的点去除;在作数据挖掘时难以确定k值,因此canopy算法比该算法更有用武之地。可以先使用canopy找出最佳k值,然后kmeans聚类。Kmeans算法可用于聚类划分,如净化网络论坛,用户的行为划分寻找水军的共同特征;电子商务客商的消费行为,进而结合推荐系统投递广告。

算法实现(核心代码)

详细介绍链接:http://blog.csdn.net/androidlushangderen/article/details/43373159

         public void kMeansClustering() {

                   double tempX = 0;

                   double tempY = 0;

                   int count = 0;

                   double error = Integer.MAX_VALUE;

                   Point temp;

                   while (error > 0.01 * classNum) {

                            for (Point p_total : totalPoints) {

                                     // 将所有的测试坐标点就近分类,打标签分类的过程,p2遍历两个类点

                                     for (Point p_class : classPoints) {

                                               p_class.computerDistance(p_total);

                                     }

                                     Collections.sort(classPoints); // 小到大排序

                                     // 取出p_total离类坐标点最近的那个点

                                     p_total.setClassName(classPoints.get(0).getClassName());

                            }

                            error = 0;

                            // 按照均值重新计算聚类中心点

                            for (Point p1 : classPoints) {

                                     count = 0;

                                     tempX = 0;

                                     tempY = 0;

                                     for (Point p : totalPoints) {

                                               if (p.getClassName().equals(p1.getClassName())) {

                                                        count++;

                                                        tempX += p.getX();

                                                        tempY += p.getY();

                                               }

                                     }

                                     tempX /= count;

                                     tempY /= count; // 类质心

                                     error += Math.abs((tempX - p1.getX()));

                                     error += Math.abs((tempY - p1.getY()));

                                     // 计算均值

                                     p1.setX(tempX);

                                     p1.setY(tempY);

                            }

 

                            for (int i = 0; i

                                     temp = classPoints.get(i);

                                     System.out.println(MessageFormat.format("聚类中心点{0},x={1},y={2}",

                                                        (i + 1), temp.getX(), temp.getY()));

                            }

                            System.out.println("----------");

                   }

 

                   System.out.println("结果值收敛");

                   // classPoints.size()=类数目

                   for (int i = 0; i

                            temp = classPoints.get(i);

                            System.out.println(MessageFormat.format("聚类中心点{0},x={1},y={2}",

                                               (i + 1), temp.getX(), temp.getY()));

                   }

         }

 


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
author-avatar
幼儿之家燕郊_880
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有