k-均值算法及其实现
1.1 算法描述
K均值算法也称为C-均值算法,是根据函数准则进行分类的聚类算法,基于使聚类准则最小化。所使用的聚类准则
函数为模式集中每一个样本点到该类聚类中心的距离平方和。聚类中心的选择应使得距离平方和最小。
假设共有N个模式样本,算法执行步骤如下:
(1) 任选K个初始聚类中心Z1(1),Z2(1),...,Zk(1),K<N。括号中为第几次迭代。一般选择前K个样本作为初始聚类中心。(2) 使用欧几里得公式计算其余样本点到初始聚类中心的距离,基于欧几里得最小距离为其余样本分配聚类中
心,并将迭代次数加1。
其中X为模式集,Sj为第j个聚类集,小写k为迭代次数,大写K为聚类中心个数,Dj(k)为到聚类中心的距
离。
(3) 计算各个聚类中心的新向量值作为新的聚类中心。
(4) 如果,则继续步骤(2),否则,算法收敛,计算结束。
1.2 算法实现
算法实现效果如下图1所示。
图1 50个点使用k-均值聚为两类的算法实现效果
1.3 代码如下:
本代码使用了OpenGL图形程序接口,需要使用glut库,具体使用方法请自行查找相关文档,此处不再介绍。
/*
k-均值算法,聚为两类
*/
#define N1 50
#define R 2.0f
#define Pi 3.1415926f
#include <stdio.h>
#include <vector>
#include <time.h>
#include <GL/glut.h>
//模式结构体
struct Pattern
{
float x1,x2;//x1,x2表示特征
};
//定义初始聚类中心A,B以及初始数据w1
int p,q;
Pattern w1[N1],w2[N1],w3[N1];
void init()
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void display()
{
//画点
glPointSize(10.0);
glBegin(GL_POINTS);
for(int i = 0;i < p; i++)
{
glColor3f(1.0,0.0,0.0);
glVertex2f(w2[i].x1,w2[i].x2);
}
glEnd();
glFlush();
for (int i = 0; i < q; i++)
{
glBegin(GL_LINE_LOOP);
for(int j = 0;j < q; j++)
{
glColor3f(0.0,0.0,1.0);
glVertex2f(w3[i].x1+R*cos(2*Pi/q*j),w3[i].x2+R*sin(2*Pi/q*j));
}
glEnd();
glFlush();
}
}
int main(int argc,char *argv[])
{
Pattern A,B,C,D,E,F;//定义初始聚类中心A,B
Pattern distance[N1];
//产生随机数的种子
printf("这是K-均值算法的初始点数据\n");
srand((unsigned)time(NULL));
for (int i = 0; i < N1; i++)
{
w1[i].x1=rand()%100;
w1[i].x2=rand()%100;
//打印随机产生的点
printf("%.3f %.3f\n",w1[i].x1,w1[i].x2);
}
//执行k-均值算法更新,赋值初始聚类中心
A.x1=w1[0].x1;
A.x2=w1[0].x2;
B.x1=w1[1].x1;
B.x2=w1[1].x2;
int m,n;
E.x1=A.x1;E.x2=A.x2;
F.x1=B.x1;F.x2=B.x2;
int temp =0;
while(true)
{
temp++;
m=0;
n=0;
p=0;
q=0;
C.x1=0;
C.x2=0;
D.x1=0;
D.x2=0;
for(int j = 0;j < N1;j++)
//计算各样本距离聚类中心的距离
{
distance[j].x1=sqrt((w1[j].x1-E.x1)*(w1[j].x1-E.x1)+(w1[j].x2-E.x2)*(w1[j].x2-E.x2));
distance[j].x2=sqrt((w1[j].x1-F.x1)*(w1[j].x1-F.x1)+(w1[j].x2-F.x2)*(w1[j].x2-F.x2));
if(distance[j].x1<distance[j].x2)
{
m++;
w2[p].x1=w1[j].x1;
w2[p].x2=w1[j].x2;
C.x1+=w2[p].x1;
C.x2+=w2[p].x2;
p++;
}
else
{
n++;
w3[q].x1=w1[j].x1;
w3[q].x2=w1[j].x2;
D.x1+=w3[q].x1;
D.x2+=w3[q].x2;
q++;
}
}
C.x1=(float)C.x1/m;
C.x2=(float)C.x2/m;
D.x1=(float)D.x1/n;
D.x2=(float)D.x2/n;
if(E.x1 != C.x1 || E.x2 != C.x2 || F.x1 != D.x1 || F.x2 != D.x2)
{
E.x1=C.x1;E.x2=C.x2;
F.x1=D.x1;F.x2=D.x2;
}
else
{
printf("第1类点的个数为:");
printf("%d\n",m);
printf("第2类点的个数为:");
printf("%d\n",n);
printf("最终的聚类中心为:\n");
printf("%f,%f\n",C.x1,C.x2);
printf("%f,%f\n",D.x1,D.x2);
break;
}
}
glutInit(&argc,argv);//初始化glut
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);//设置显示属性为RGB颜色,单缓冲
glutInitWindowSize(400,400);//设置窗口大小
glutInitWindowPosition(200,100);//设置窗口位置
glutCreateWindow("k-均值算法的设计");//生成窗口
init();
gluOrtho2D(-10,100,-10,100);
glutDisplayFunc(display);//显示回调
glutMainLoop();
system("pause");
return 0;
}