现在的位置: 首页 > 综合 > 正文

K-means聚类之一(多维整型数据)

2019年04月22日 ⁄ 综合 ⁄ 共 2541字 ⁄ 字号 评论关闭

算法介绍

    k-means 算法接受输入量 k ;然后将n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。

k-means 算法基本步骤:

(1) 从 n个数据对象任意选择 k 个对象作为初始聚类中心;
(2) 根据每个聚类对象的均值(中心对象),计算每个对象与这些中心对象的距离;并根据最小距离重新对相应对象进行划分;
(3) 重新计算每个(有变化)聚类均值(中心对象);
(4) 计算标准测度函数,当满足一定条件,如函数收敛时,则算法终止;如果条件不满足则回到步骤(2)。
 
  算法的时间复杂度上界为O(n*k*t),
其中t是
迭代次数。
 
完整代码如下:
/*简易的K-means算法:对二维整型数据进行聚类 */

#include <iostream> 
#include <math.h> 
#include <vector> 
#define K 3 //预定义划分簇的数目
#define N 7
using namespace std; 

//特征对象,表示一个元组,一个元组有两个数值属性
struct Tuple 
{ 
	int attr1; 
	int attr2; 
}; 

Tuple getCentreC(vector<Tuple> e)
{
	int num=e.size();
	double centreX=0,centreY=0;
	Tuple t;
	for(int i=0;i<num;i++)
	{
		centreX +=e[i].attr1;
		centreY +=e[i].attr2;
	}
	t.attr1=centreX/num;
	t.attr2=centreY/num;
	return t;
}//计算簇的中心点

double getE(vector<Tuple> classes[], Tuple centre[])
{
	double sum = 0; 
	for (int i = 0; i < K; i++) 
	{ 
		vector<Tuple> v = classes[i]; 
		for (int j = 0; j< v.size(); j++) 
		{ 
			sum += (v[j].attr1 -centre[i].attr1) * (v[j].attr1 - centre[i].attr1) + 
				(v[j].attr2 -centre[i].attr2) *(v[j].attr2 - centre[i].attr2); 
		} 
	} 
	cout<<"sum:"<<sum<<endl; 
	return sum; 
}//获取算法的准则函数值,当准则函数收敛时算法停止

int searchMinC(Tuple t,Tuple centre[])
{
	int c = 0; 
	int d = (t.attr1 -centre[0].attr1) * (t.attr1 - centre[0].attr1) + 
		(t.attr2 - centre[0].attr2) * (t.attr2 - centre[0].attr2); 
	for (int i = 1; i < K; i++) 
	{ 
		int temp = (t.attr1 - centre[i].attr1) * (t.attr1 - centre[i].attr1) + 
			(t.attr2 - centre[i].attr2) * (t.attr2 - centre[i].attr2); 
		if (temp < d) 
		{ 
			c = i; 
			d = temp; 
		} 
	} 
	return c; 
}//对象选择距离最小的中心点

void kMeans(vector<Tuple> in)
{
	vector<Tuple> classes[K];//定义簇数组,共需划分K个簇
	Tuple centre[K];
	double newE,oldE = -1;
	for(int i=0;i<K;i++)
	{
		classes[i].push_back(in[i]);     //把in的前k个值初始化为k个中心
		centre[i]=getCentreC(classes[i]);   //计算中心点
		cout<<"centre["<<i<<"]:"<<centre[i].attr1<<" "<<centre[i].attr2<<endl;
	}
	newE=getE(classes,centre);//计算当前准则函数值
	cout<<"newE:"<<newE<<" oldE:"<<oldE<<endl;

	for(i=0;i<K;i++) //清空每个簇
		classes[i].clear();

	while(abs(newE-oldE) >= 1)
	{
		for(i=0;i<in.size();i++) //遍历所有特征对象,将其加入到离它最近的簇
		{
			int toC=searchMinC(in[i],centre);
			classes[toC].push_back(in[i]);
		}

		cout<<"---------------------"<<endl;
		for(i=0;i<K;i++) //打印每个簇的对象
		{
			vector<Tuple> temp=classes[i];
			cout<<"簇"<<i+1<<":"<<endl;
			for(int j=0;j<temp.size();j++)
			{
				cout<<temp[j].attr1<<" "<<temp[j].attr2<<endl;
			}
		}
		cout<<"---------------------"<<endl;
		for(i=0;i<K;i++) //更新簇中心
		{
			centre[i]=getCentreC(classes[i]);
			cout<<"centre["<<i<<"]:"<<centre[i].attr1<<" "<<centre[i].attr2<<endl;
		}

		oldE=newE;
		newE=getE(classes,centre);
		for(i=0;i<K;i++)
			classes[i].clear();
	}

}

int main()
{
	vector<Tuple> in;
	Tuple t[N]={{2,4},{5,1},{65,22},{100,55},{12,8},{11,7},{45,5}};
	for(int i=0;i<N;i++)
		in.push_back(t[i]);

	for(i=0;i<in.size();i++)
		cout<<in[i].attr1<<" "<<in[i].attr2<<endl;

	kMeans(in);
    return 0;
}

抱歉!评论已关闭.