K-MEANS算法是输入聚类个数k,以及包含 n个数据对象的数据库,输出满足方差最小标准的k个聚类。
</pre>
基本简介k-means
算法接受输入量 k ;然后将n个数据对象划分为 k个聚类以便使得所获得的聚类满足:同一聚类中的对象相似度较高;而不同聚类中的对象相似度较小。聚类相似度是利用各聚类中对象的均值所获得一个“中心对象”(引力中心)来进行计算的。
k-means 算法基本步骤(1)
从 n个数据对象任意选择 k 个对象作为初始聚类中心;(2) 根据每个聚类对象的均值(中心对象),计算每个对象与这些中心对象的距离;并根据最小距离重新对相应对象进行划分;(3) 重新计算每个(有变化)聚类的均值(中心对象);(4) 计算标准测度函数,当满足一定条件,如函数收敛时,则算法终止;如果条件不满足则回到步骤(2)。
K-means算法C++实现过程示例
<span style="font-size:14px;">#include <iostream></span>
#include <math>#include <vector>
#define k 5 using namespace std;
<span style="font-size:14px;">//计算两元组的欧式距离 float getDist(Element e1,Element e2) { float dist=sqrt((e1.x-e2.x)*(e1.x-e2.x)+(e1.y-e2.y)*(e1.y-e2.y)); return dist; } // 根据质心,决定当前元组属于哪个簇 int clusterOfElement(Element means[],Element elem) { float dist=getDist(means[0],elem); float tmp; int label=0; for(int i=1;i<k;i++) { tmp=getDist(means[i],elem); if(tmp<dist){dist=tmp;label=i;} } return label; } //获得给定簇的平方误差 float getVar(vector<Element> cluster[],Element means[]) { float var=0; for(int i=0;i<k;i++) { vector<Element> elem=cluster[i]; for(int j=0;j<elem.size();j++) { var+=getDist(elem[j],means[i]); } } return var; } //获得当前簇的质心 Element getMeans(vector<Element> cluster) { int num=cluster.size(); double meansX=0,meansY=0; Element elem; for(int i=0;i<num;i++) { meansX+=cluster[i].x; meansY+=cluster[i].y; } elem.x=meansX/num; elem.y=meansY/num; return elem; }</span>
//聚类过程 void KMeans(vector<Element> elems ,vector<Element> clusters[k],Element means[k] ) { //vector<Element> clusters[k]; //Element means[k]; int i=0; //默认一开始将前K个元组的值作为k个簇的质心(均值) for(i=0;i<k;i++) { means[i].x=elems[i].x; means[i].y=elems[i].y; } int lable=0; //根据默认的质心给簇赋值 for(i=0;i!=elems.size();++i) { lable=clusterOfElement(means,elems[i]); clusters[lable].push_back(elems[i]); } 输出刚开始的簇 //for(lable=0;lable<3;lable++) //{ // cout<<"第"<<lable+1<<"个簇:"<<endl; // vector<Element> t = clusters[lable]; // for (i = 0; i< t.size(); i++) // { // cout<<"("<<t[i].x<<","<<t[i].y<<")"<<" "; // } // cout<<endl; // } float oldVar=-1; float newVar=getVar(clusters,means); while(abs(newVar-oldVar)>=0.1) { for (i = 0; i < k; i++) //更新每个簇的中心点 { means[i] = getMeans(clusters[i]); } oldVar = newVar; newVar = getVar(clusters,means); //计算新的准则函数值 for (i = 0; i < k; i++) //清空每个簇 { clusters[i].clear(); } //根据新的质心获得新的簇 for(i=0;i!=elems.size();++i){ lable=clusterOfElement(means,elems[i]); clusters[lable].push_back(elems[i]); } } } //获取距离k个质心距离最近的点的索引 int getIndex(vector<Element> clusters,Element means) { //getDist(Element e1,Element e2) int index=clusters.at(0).index; float temp=getDist(means,clusters.at(0)); for(int i=0;i<clusters.size();i++) { if(getDist(means,clusters.at(i))<temp) { temp=getDist(means,clusters.at(i)); index=clusters.at(i).index; } } return index; }
void main()
{
vector<Element> data;
Element ele;
for(int i=0;i<keypoints.size();i++) //keypoints为预先定义的容器,已赋值(本文省略) { ele.index=i; ele.x=keypoints.at(i).x; ele.y=keypoints.at(i).y; data.push_back(ele); }
vector<Element> clusters[k]; Element means[k]; KMeans(data,clusters,means);
<span style="white-space:pre"> </span>FILE *kmeans=fopen("kmeans.txt","w");// 输出K个簇中的数据 for(int i=0;i<k;i++) { //cout<<means[i].x<<" "<<means[i].y<<endl; fprintf(kmeans,"第%d簇\n",i); for(int j=0;j<clusters[i].size();j++) { fprintf(kmeans,"%.3f %.3f \n",clusters[i].at(j).x,clusters[i].at(j).y); } } fclose(kmeans);
}