算法描述

  K-means算法是一种被广泛使用的基于划分的聚类算法,目的是将n个对象会分成k个簇。算法的具体描述如下:

随机选取k个对象作为簇中心;

Do

          计算所有对象到这k个簇中心的距离,将距离最近的归入相应的簇;

          重新计算每个簇的中心;

          计算准则函数V;

While 准则函数的值稳定(或变化小于某个阈值)

  其中准则函数V的定义如下:

         

  其中,ui表示第i个簇Si的中心。最终经过T次迭代获取到最终的分类结果,对于第t+1次迭代之后得到的中心,有如下定义:

          

算法的优缺点

  优点:

    1)         算法描述简单,高效;

    2)         适合用于处理大数据,得到的算法的复杂度大约为O(nkt),n表示对象的数量,k是划分的簇数量,t为迭代次数。通常情况下能够保证k<<n,算法的效率有一定的保障;

    3)         算法比较适合处理簇之间划分明确的对象集合;

  缺点:

    1)         k值必须手动的给出,选取k值就显得特别重要了;

    2)         不同的初始对象会带来不同的划分结果;

    3)         如果对象集合内部包含一些小范围孤立对象,这种基于局部最优的聚类划分算法可能会产生一些错误的划分;

    4)         通常判断对象之间远近的依据是欧拉距离,可以尽快得到结果,但同时也带来了一些缺点,比如采用K-means算法处理一下非凸面的簇时。

Kmeans算法的Java实现

 import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set; import ocr.algorithm.KMeans.Cluster;
import ocr.algorithm.KMeans.KMeansNode; /**
* 这是一个简单的Kmeans算法实现
* 假设前提包括:
* 1.集合中每个对象都是一个位于二维平面的点
* 2.对象之间的距离判定以欧氏距离为标准
* 3.这只是一个样例程序,主要用于叙述K-means算法的主干部分,一些特殊的情况未曾考虑(数据溢出,性能优化)
* @author yahokuma
* @email Hazin.lu@gmail.com
*/
public class KMeans { private List<KMeansNode> datas = new ArrayList<KMeans.KMeansNode>(); public static class KMeansNode {
private double x;
private double y; public double getX() {
return x;
} public double getY() {
return y;
} public KMeansNode(double x,double y){
this.x = x;
this.y = y;
} public double distance(KMeansNode n){
return
Math.pow( x - n.x , 2 ) + Math.pow( y - n.y , 2 );
} } public static class Cluster{
private List<KMeansNode> nodes = new ArrayList<KMeans.KMeansNode>();
private KMeansNode center = null;
public KMeansNode getCenter() {
return center;
}
public void addNode(KMeansNode n){
this.nodes.add(n);
}
public Cluster(KMeansNode c){
this.center = c;
}
public void calculateCenter(){
double x = 0,y = 0;
for (KMeansNode n : nodes) {
x += n.x;
y += n.y;
}
this.center = new KMeansNode( x / nodes.size(), y / nodes.size());
} public double criterion(){
double criterion = 0;
calculateCenter();
for (KMeansNode n : nodes) {
criterion += center.distance(n);
} return criterion;
} public void clear(){
this.nodes.clear();
} public List<KMeansNode> getNodes(){
return this.nodes;
} public void print(){
System.out.println("Contains "+ nodes.size() + " Nodes !");
System.out.println("Center Node is ( "+ getCenter().x + "," + getCenter().y + " )");
}
} public KMeans(List<KMeansNode> datas){
this.datas = datas;
} private List<KMeansNode> findRandNodes(int k){
List<KMeansNode> rNodes = new ArrayList<KMeans.KMeansNode>();
Set<Integer> rIndexes = new HashSet<Integer>();
Random r = new Random();
Integer rInt = null;
for (int i = 0; i < k; i++) {
rInt = r.nextInt(datas.size());
while(rIndexes.contains(rInt))
rInt = r.nextInt(datas.size()); rIndexes.add(rInt);
rNodes.add( datas.get(rInt));
} return rNodes;
} private double calculateCriterion(List<Cluster> clusters){
double res = 0;
for (Cluster c : clusters) {
res += c.criterion();
}
return res;
} public List<Cluster> partition(int k){
List<KMeansNode> centerNodes = findRandNodes(k);
List<Cluster> clusters = new ArrayList<KMeans.Cluster>();
for (KMeansNode c : centerNodes) {
clusters.add(new Cluster(c));
} double minDistance = Double.MAX_VALUE , distance;
Cluster minCluster = null;
double lastCriterion , criterion= Double.MAX_VALUE; do{
for (Cluster c : clusters) {
c.clear();
}
lastCriterion = criterion; for (KMeansNode n : datas) {
minDistance = Double.MAX_VALUE;
for (Cluster c : clusters) {
distance = c.getCenter().distance(n);
if( distance < minDistance ){
minDistance = distance;
minCluster = c;
}
}
minCluster.addNode(n);
}
criterion = calculateCriterion(clusters); }while( criterion != lastCriterion); return clusters; } /**
*随机生成了1000个平面点,将其划分为4个簇(k=4)
*由于点的坐标都是随机生成的,在空间上分布均匀;
*从结果中可以看出K-means对于处理这种边界不分明的对象集合时并不能很好的进行区分;
*但是一般情况,经过处理还是会将整个平面均匀得划分成四个部分
**/
public static void main(String args[]){
Random r = new Random();
List<KMeansNode> nodes = new ArrayList<KMeans.KMeansNode>();
for (int i = 0; i < 1000; i++) {
nodes.add(new KMeansNode(r.nextDouble() * 1000, r.nextDouble() * 1000));
} KMeans kmeans = new KMeans(nodes);
List<Cluster> clusters = kmeans.partition(4);
for( Cluster c : clusters){
c.print();
} Frame frame = new Frame("K-means Test!");
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.add(new KMeansCanvas(clusters),BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
} } /**
*
* @author yahokuma
* @email Hazin.lu@gmail.com
*/
class KMeansCanvas extends Canvas {
public final static Paint[] PAINT_COLOR = {Color.BLUE,Color.RED, Color.ORANGE, Color.BLACK}; private List<Cluster> clusters = null;
public KMeansCanvas(List<Cluster> clusters) {
this.setBackground(Color.WHITE);
this.clusters = clusters;
}
@Override
public void paint(Graphics g) {
drawKarel(g);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(1000,1000);
} private void drawKarel(Graphics g) { Random r = new Random();
int i = 0 ;
for (Cluster c : clusters) {
Graphics2D g2d= (Graphics2D) g;
g2d.setPaint(PAINT_COLOR[i++]);
for (KMeansNode n : c.getNodes()) {
g2d.drawRect((int)n.getX(), (int)n.getY() , 2, 2);
g2d.fillRect((int)n.getX(), (int)n.getY() , 2, 2);
}
}
}
private static final long serialVersionUID = 1L;
}

参考资料

http://en.wikipedia.org/wiki/K-means_clustering

http://blog.csdn.net/aladdina/article/details/4141177

http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006910.html

http://zh.wikipedia.org/wiki/K%E5%B9%B3%E5%9D%87%E7%AE%97%E6%B3%95

数据挖掘经典算法——K-means算法的更多相关文章

  1. 第4章 最基础的分类算法-k近邻算法

    思想极度简单 应用数学知识少 效果好(缺点?) 可以解释机器学习算法使用过程中的很多细节问题 更完整的刻画机器学习应用的流程 distances = [] for x_train in X_train ...

  2. 聚类算法:K-means 算法(k均值算法)

    k-means算法:      第一步:选$K$个初始聚类中心,$z_1(1),z_2(1),\cdots,z_k(1)$,其中括号内的序号为寻找聚类中心的迭代运算的次序号. 聚类中心的向量值可任意设 ...

  3. 分类算法----k近邻算法

    K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一.该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的 ...

  4. 机器学习(四) 机器学习(四) 分类算法--K近邻算法 KNN (下)

    六.网格搜索与 K 邻近算法中更多的超参数 七.数据归一化 Feature Scaling 解决方案:将所有的数据映射到同一尺度 八.scikit-learn 中的 Scaler preprocess ...

  5. 机器学习(四) 分类算法--K近邻算法 KNN (上)

    一.K近邻算法基础 KNN------- K近邻算法--------K-Nearest Neighbors 思想极度简单 应用数学知识少 (近乎为零) 效果好(缺点?) 可以解释机器学习算法使用过程中 ...

  6. python 机器学习(二)分类算法-k近邻算法

      一.什么是K近邻算法? 定义: 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别. 来源: KNN算法最早是由Cover和Hart提 ...

  7. KNN 与 K - Means 算法比较

    KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...

  8. 分类算法——k最近邻算法(Python实现)(文末附工程源代码)

    kNN算法原理 k最近邻(k-Nearest Neighbor)算法是比较简单的机器学习算法.它采用测量不同特征值之间的距离方法进行分类,思想很简单:如果一个样本在特征空间中的k个最近邻(最相似)的样 ...

  9. 【学习笔记】分类算法-k近邻算法

    k-近邻算法采用测量不同特征值之间的距离来进行分类. 优点:精度高.对异常值不敏感.无数据输入假定 缺点:计算复杂度高.空间复杂度高 使用数据范围:数值型和标称型 用例子来理解k-近邻算法 电影可以按 ...

  10. 【机器学习】聚类算法——K均值算法(k-means)

    一.聚类 1.基于划分的聚类:k-means.k-medoids(每个类别找一个样本来代表).Clarans 2.基于层次的聚类:(1)自底向上的凝聚方法,比如Agnes (2)自上而下的分裂方法,比 ...

随机推荐

  1. Idea 部署非Maven项目

    参考:http://m.blog.csdn.net/z69183787/article/details/78030857 以前一直很好奇,在idea中运行tomcat,把项目部署到其中,运行起来,然后 ...

  2. eclipse更改web项目的WebContent目录

    在使用eclipse 中 , 相信大家比我更是轻车熟路了 ( 我平常一般用 Intellij idea 的 ), 下面讲解一下在eclipse web项目中 , 如何设置 webroot 目录指向问题 ...

  3. bzoj4886 [Lydsy2017年5月月赛]叠塔游戏

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4886 [题解] 跟bzoj4883:http://www.cnblogs.com/galax ...

  4. [BZOJ2243][SDOI2011]染色 解题报告|树链剖分

    Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ ...

  5. linux知识复习1-dup dup2

    #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <stdio.h& ...

  6. 怎么重启shell ubuntu

    sunosfind . -type f  | xargs grep count 怎么重启shell ubuntu方法一:退出,重新登录方法二:source /etc/profile

  7. Linux指令详解useradd groupadd passwd chpasswd chage 密码修改

    Linux指令详解useradd groupadd passwd chpasswd chage 密码修改 http://speediness.blog.51cto.com/760841/1783661 ...

  8. Page.Response.Buffer与Response.Redirect一起用报错“无法在发送 HTTP 标头之后进行重定向”

    Page.Response.Buffer与Response.Redirect一起用报错“无法在发送 HTTP 标头之后进行重定向” 原因还未知..

  9. 配置iptables,把80端口转到8080

    在Linux的下面部署了tomcat,为了安全我们使用非root用户进行启动,但是在域名绑定时无法直接访问80端口号.众所周知,在unix下,非root用户不能监听1024以上的端口号,这个tomca ...

  10. discuz自定义生成单页面

    在pc端,若要生成一个单页面,有一个比较方便的方法是生成新的专题页,然后diy其中的内容. 不过这种做法有两个缺点 1 url太过冗赘 2 只有一个插入url代码功能,没有文本编辑功能 而且文本框小的 ...