机器学习西瓜书第九章聚类------k均值算法(附c++代码)

本文是在学习机器学习期间,参考机器学习西瓜书得出的一些结论,其中的一些公式推导就不一一列出。作为一个初学者,有可能对其理解不太深,如有错误,请见谅。文章最后给出一次迭代的c++代码,此代码只适用于西瓜书上的样例,仅供给看不懂伪代码的朋友进行参考,感兴趣的朋友可以自己将其补全,使其能够满足更一般的k均值。本文有错误的地方欢迎指出。

k均值算法

原理:对于给定的数据集D,k均值算法主要针对聚类所得簇划分的最小化平方误差。这一算法采用了贪心策略,通过迭代的方式一步一步的优化来求近似解。

步骤:一、从数据集D中随机选择k个样本作为初始向量

          二、遍历数据集中的每个样本,求出数据集中每个样本关于第一步随机选出的k个初始向量的欧式距离,然后在这些距离中选出最小的距离,并将这个样本进行标记,标记的内容是这个样本属于哪一簇。

          三、这一步基于第二步已经得出了数据集D中的每个样本属于哪个簇。将每个簇中的样本进行求均值运算,这样就会得到k个新的初始向量。

          四、进行迭代运算,反复重复第一步到第三步的操作,直到迭代得到的新的初始向量和上一次迭代得到的初始向量相同,算法结束。

代码:数据集为西瓜书表9.1的数据

0.697 0.460
0.774 0.376
0.634 0.264
0.608 0.318
0.556 0.215
0.403 0.237
0.481 0.149
0.437 0.211
0.666 0.091
0.243 0.267
0.245 0.057
0.343 0.099
0.639 0.161
0.657 0.198
0.360 0.370
0.593 0.042
0.719 0.103
0.359 0.188
0.339 0.241
0.282 0.257
0.748 0.232
0.714 0.346
0.483 0.312
0.478 0.437
0.525 0.369
0.751 0.489
0.532 0.472
0.473 0.376
0.725 0.445
0.446 0.459
//原始聚类的k均值算法 
#include<iostream>
#include<cmath>

using namespace std;

struct Dataset{
	float md;//密度
	float sugar;//含糖量 
	int flag;//作为标记,显示属于哪个簇 
};

//计算欧式距离 
//6->(0.403;0.237) 12->(0.343;0.099) 27->(0.532;0.472)
float euclidean(float ax,float ay,float bx,float by)
{
	float a=pow((bx-ax),2);
	float b=pow((by-ay),2);
	float result =sqrt(a+b); 
	return result;
}
//找出最小值 
int findMin(float a,float b,float c)
{
	int flag=1;
	float min=a;
	if(b<min)
	{
		min=b;
		flag=2;
	}
	if(c<min)
	{
		min=c;
		flag=3;
	}
	return flag;
}

int main()
{
    int m,k,i,n1=0,n2=0,n3=0;//m为数据集的个数、k为划分的簇的个数 ,n1,n2,n3分别为每个簇内样本的数量 
    float x1=0.403,y1=0.237,x2=0.343,y2=0.099,x3=0.532,y3=0.472; //初始的三个均值向量的值 
    float dist1,dist2,dist3; 
	cin>>m;
	Dataset ds[m+1];
	for(i=1;i<=m;++i)
	{
		cin>>ds[i].md>>ds[i].sugar;
	}
    //对样本进行初次划分簇,给每个样本加上标记 
	for(i=1;i<=m;++i)
	{
	    dist1 = euclidean(ds[i].md,ds[i].sugar,x1,y1);
	    dist2 = euclidean(ds[i].md,ds[i].sugar,x2,y2);
	    dist3 = euclidean(ds[i].md,ds[i].sugar,x3,y3);
	    int min = findMin(dist1,dist2,dist3);//找到欧式距离最小的一个下标,然后将该样本的标记设为该簇的下标 
	    if(min==1)
		{
			n1++;
		}
		if(min==2)
		{
			n2++;
		} 
		if(min==3)
		{
			n3++;
		}
	    ds[i].flag = min;
	} 
	//求出三个新的均值向量 
	float s1x=0,s1y=0,s2x=0,s2y=0,s3x=0,s3y=0;
	for(i=1;i<=m;++i)
	{
		 if(ds[i].flag==1)
		 {
		 	s1x+=ds[i].md;
		 	s1y+=ds[i].sugar;
		 }
		 if(ds[i].flag==2)
		 {
		 	s2x+=ds[i].md;
		 	s2y+=ds[i].sugar;
		 }
		 if(ds[i].flag==3)
		 {
		 	s3x+=ds[i].md;
		 	s3y+=ds[i].sugar;
		 }
	}
	float nx1,ny1,nx2,ny2,nx3,ny3;
	//新的均值向量的坐标 
	nx1=s1x/n1;
	nx2=s2x/n2;
	nx3=s3x/n3;
	ny1=s1y/n1;
	ny2=s2y/n2;
	ny3=s3y/n3;
	cout<<"m1("<<nx1<<","<<ny1<<") m2("<<nx2<<","<<ny2<<") m3("<<nx3<<","<<ny3<<")"<<endl; 
	return 0;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值