K-Means算法

K-Means算法的输入N,K和一个size为N的向量组vector.输出K个两两互不相交的向量组.其本质是将给定的向量组划分成K个类别,使得同类别的向量相似度比较大,而不同类别的向量之间的相似度较小.
    比如以下这个图,人肉眼能看出有四个点团,但计算机不知道,为了让计算机明白这一点,可以将点的坐标提取到向量组中,而向量之间的相似度定义为点之间的距离的相反数或者倒数.从而将这些点分开.
    实现过程:
    (1)从n个数据对象任意选择k个对象作为初始聚类中心;
    (2)根据每个聚类对象的均值(中心对象),计算每个对象与这些中心对象的距离,并根据最小距离重新对相应对象进行划分;
    (3)重新计算每个(有变化)聚类的均值(中心对象);
    (4)计算标准测度函数,当满足一定条件,如函数收敛时,则算法终止,如果条件不满足则回到步骤(2).
    实际应用中的问题:
    事实上,我是一个做ACM的选手,所以我比较感兴趣的是K-Means能否求得一个最优解.对于这样一个问题:从N个点取出K个作为核心,定义两个向量之间的相似度函数f(vector1,vector2),使得所有点与其所对应的核心的相似度之和最大.然而事实让我大失所望,K-Means算法对种子点的选取十分敏感,不同的种子会导致不同的解.

#include<math.h>
#include<stdio.h>
#include<string.h>
#define Convergence (fabs(last-cur)<1e-8)
#define dist(a,b) (sqrt((x[a]-px[b])*(x[a]-px[b])+(y[a]-py[b])*(y[a]-py[b])))
int x[50000],y[50000],qx[50000],qy[50000],px[100],py[100],assign[50000];
int main()
{
freopen("data.txt","r",stdin);
FILE *fp=fopen("output.txt","w");
int N,K,i,j,k;
double ave=0,MIN=1e15;
scanf("%d%d",&N,&K);
for (i=1;i<=N;i++) scanf("%d%d",&x[i],&y[i]);
for (int asd=0;asd<N;asd++)
{
printf("Executing case #%d\n",asd);
if (asd) printf("Current Average:%.6lf\n",ave/asd);
printf("Current Minimize:%.6lf\n",MIN);
printf("----------------------------------------\n");
fprintf(fp,"Executing case #%d\n",asd);
if (asd) fprintf(fp,"Current Average:%.6lf\n",ave/asd);
fprintf(fp,"Current Minimize:%.6lf\n",MIN);
fprintf(fp,"----------------------------------------\n");
for (i=1;i<=K;i++)
{
px[i]=x[(i+asd)%N+1];
py[i]=y[(i+asd)%N+1];
}
double last=1e15,cur=0;
while (!Convergence)
{
printf("%.6lf\n",last);
last=cur;
for (i=1;i<=N;i++)
{
double Min=1e15;
int v;
for (j=1;j<=K;j++)
{
double d=dist(i,j);
if (d<Min)
{
Min=d;
v=j;
}
}
assign[i]=v;
}
for (i=1;i<=K;i++)
{
int cnt=0;
for (j=1;j<=N;j++)
if (assign[j]==i)
{
qx[++cnt]=x[j];
qy[ cnt ]=y[j];
}
double Min=1e15;
int v;
for (j=1;j<=cnt;j++)
{
double tmp=0;
for (k=1;k<=cnt;k++)
tmp+=(sqrt((qx[j]-qx[k])*(qx[j]-qx[k])+(qy[j]-qy[k])*(qy[j]-qy[k])));
if (tmp<Min)
{
Min=tmp;
v=j;
}
}
px[i]=qx[v];
py[i]=qy[v];
}
cur=0;
for (i=1;i<=N;i++) cur+=dist(i,assign[i]);
}
ave+=cur;
MIN=MIN<cur ? MIN:cur;
}
printf("Total average:%.6lf\n",ave/N);
printf("Total MIN:%.6lf\n",MIN);
fprintf(fp,"Total average:%.6lf\n",ave/N);
fprintf(fp,"Total MIN:%.6lf\n",MIN);
return 0;
}

运行结果如图所示:


    另一个问题是算法的收敛速度,重新算了一下,结果如下图所示:


    这个结果让我大吃一惊啊,每次迭代之后更新量都很小,而且最终的值(9259914.963696)跟第一个有意义的值(10352922.175732)相差并不是很多.后来我仔细想了一下,应该是跟输入数据有关,我的数据完全是在一定范围内随机生成的,分布比较均匀,所以即使随便选也可以得到相当不错的效果,这是我生成数据的程序:

program makedata;
var i,N,K:longint;
begin
assign(output,'data.txt');
rewrite(output);
randomize;
N:=random(10000);
K:=random(10000);
writeln(N,' ',K);
for i:=1 to N do
writeln(random(10000),' ',random(10000));
close(output);
end.

于是我重新写了makedada程序,想法是先随机生成K个核心,再在其周围生成其他的点:

#include<stdio.h>
#include<time.h>
#include<math.h>
#include<stdlib.h>
int main()
{
srand(unsigned(time(0)));
freopen("data.txt","w",stdout);
printf("15000 15\n");
for (int i=1;i<=15;i++)
{
int X=rand()%1000000,Y=rand()%1000000;
for (int j=1;j<=1000;j++)
{
int dx=rand()%10000,dy=rand()%10000;
if (rand()&1) dx*=-1;
if (rand()&1) dy*=-1;
printf("%d %d\n",X+dx,Y+dy);
}
}
return 0;
}

再重新运行一下,得到如下结果:


    可以看出,收敛的速度还是可以的,而且最终结果几乎只有最初解得一半.
    初除此之外,还有一个重要问题,核心数K是作为输入给定的,而在实际应用中是无法预知的.对此可以用ISODATA算法作为补充.

 
 
分类: 数据挖掘

K-Means算法的更多相关文章

  1. KNN 与 K - Means 算法比较

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

  2. K-means算法

    K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢?  ...

  3. 机器学习实战笔记--k近邻算法

    #encoding:utf-8 from numpy import * import operator import matplotlib import matplotlib.pyplot as pl ...

  4. 《机器学习实战》学习笔记一K邻近算法

     一. K邻近算法思想:存在一个样本数据集合,称为训练样本集,并且每个数据都存在标签,即我们知道样本集中每一数据(这里的数据是一组数据,可以是n维向量)与所属分类的对应关系.输入没有标签的新数据后,将 ...

  5. [Machine-Learning] K临近算法-简单例子

    k-临近算法 算法步骤 k 临近算法的伪代码,对位置类别属性的数据集中的每个点依次执行以下操作: 计算已知类别数据集中的每个点与当前点之间的距离: 按照距离递增次序排序: 选取与当前点距离最小的k个点 ...

  6. k近邻算法的Java实现

    k近邻算法是机器学习算法中最简单的算法之一,工作原理是:存在一个样本数据集合,即训练样本集,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据和所属分类的对应关系.输入没有标签的新数据之后, ...

  7. 基本分类方法——KNN(K近邻)算法

    在这篇文章 http://www.cnblogs.com/charlesblc/p/6193867.html 讲SVM的过程中,提到了KNN算法.有点熟悉,上网一查,居然就是K近邻算法,机器学习的入门 ...

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

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

  9. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  10. Python实现kNN(k邻近算法)

    Python实现kNN(k邻近算法) 运行环境 Pyhton3 numpy科学计算模块 计算过程 st=>start: 开始 op1=>operation: 读入数据 op2=>op ...

随机推荐

  1. Asp.net MVC + EF + Spring.Net 项目实践3

    Asp.net MVC + EF + Spring.Net 项目实践 这一篇要整合Model层和Repository层,提供一个统一的操作entity的接口层,代码下载地址(博客园上传不了10M以上的 ...

  2. Webbrowser代理支持

    原文:Webbrowser代理支持 1 通过设置注册表,再用InternetSetOption发送INTERNET_OPTION_SETTINGS_CHANGED与INTERNET_OPTION_RE ...

  3. Asp.Net MVC5入门学习系列④

    原文:Asp.Net MVC5入门学习系列④ 添加Model且简单的使用EF 对于EF(EntityFramework)不了解的朋友可以去百度文科或者在园子里搜一些简资源看下,假如和我一样知道EF的概 ...

  4. Robotium源码分析之运行原理

    从上一章<Robotium源码分析之Instrumentation进阶>中我们了解到了Robotium所基于的Instrumentation的一些进阶基础,比如它注入事件的原理等,但Rob ...

  5. php——SoapClient访问webservice

    原文:php--SoapClient访问webservice 通过SoapClient调用天气预报 <?phpheader ( "Content-Type: text/html; ch ...

  6. C语言与sqlserver数据库

    原文:C语言与sqlserver数据库 1.使用C语言来操作SQL SERVER数据库,采用ODBC开放式数据库连接进行数据的添加,修改,删除,查询等操作. step1:启动SQLSERVER服务,例 ...

  7. Python 图论工具

    networkx: 一个用Python语言开发的图论与复杂网络建模工具, 内置了经常使用的图与复杂网络分析算法, 能够方便的进行复杂网络数据分析.仿真建模等工作. 依赖工具: numpy  pypar ...

  8. Oracle 11g 客户端的安装和配置。

    原文:Oracle 11g 客户端的安装和配置. 数据库和客户端在不同的机器之上. 在安装之前,在安装Oracle数据库的服务器上导航到下面的目录. 将listener.ora和tnsnames.or ...

  9. Android 实现用户列表信息的功能,然后选择删除幻灯片删除功能

    在项目开发过程中.经常须要对用户列表的信息进行删除的操作.Android中经常使用的删除操作方式有两种 .一种就是类似微信的滑动出现删除button方式,另一种是通过CheckBox进行选择.然后通过 ...

  10. android微信付费

    原文地址:http://blog.csdn.net/intbird 微信官方文档地址:t=resource/res_main_tmpl&verify=1&lang=zh_CN" ...