每个数据点都含有X、Y坐标,算法初始状态时,指定聚类的具体个数K,初试状态的K个聚类中心由输入文件的前K个数据点来指定。算法在每一次迭代中,需要计算各个点到K个聚类中心坐标的欧氏距离,并选择距离最近的一个聚类,用该聚类的名称标识当前数据点。当所有数据点遍历完后,计算划分到每个聚类中所有数据点X与Y的均值,并将该均值与前一次聚类中心点的坐标相比较。当X与Y的误差小于或者等于1e-6时,则结束迭代并输出收敛后的K歌聚类的中心坐标。
(二)变量和函数说明
(1)定义结构体类型,用于存储数据点坐标、所在聚类、与聚类中心距离
typedef struct point
{
float x,y; //数据点的坐标
string className; //所属的聚类
float distance; //距离聚类中心的距离
}Point;
(2)变量声明
vector<Point> dataVector:存储从文件读取的数据
vector<Point> classPoints:存储聚类坐标
vector<Point> &totalPoints):存储所有的数据点
(3)函数声明
字符串转换函数:将整型变量转换成字符串类型:
string converToString(int x);
读入数据函数:从文件读入坐标数据:
vector<Point> readDataFile(string fileName);
初始化数据集合函数:
void initDataset(int classNum,vector<Point> dataVector,vector<Point> &classPoints,vector<Point> &totalPoints);
计算各个数据点距离聚点中心的欧氏距离的函数:
string computerDistance(Point *p_totalPoints,vector<Point> &classPoints);
将各个点划分到相应类的函数:
void kMeansClustering(int classNum,vector<Point> totalPoints,vector<Point> classPoints);
(三)核心代码(部分)
(1)初始化数据集合函数:
void initDataset(int classNum,vector<Point>dataVector,vector<Point>&classPoints,
vector<Point>&totalPoints)
{
int i,j;
Point point;
for(i=0,j=1; i<dataVector.size(); i++)
{
if(j<=classNum) //classNum表示聚类的编号
{
point.x=dataVector[i].x;
point.y=dataVector[i].y;
point.distance=dataVector[i].distance;
point.className=converToString(j);//将整型类型转换成字符串类型
classPoints.push_back(point);
j++;
}
point.x=dataVector[i].x;
point.y=dataVector[i].y;
point.distance=dataVector[i].distance;
totalPoints.push_back(point);
}
}
(2)K-means函数:
void kMeansClustering(int classNum,vector<Point> totalPoints,vector<Point> classPoints)
{
float tempX=0;//计算聚类中所有数据点X的均值
float tempY=0;//计算聚类中所有数据点Y的均值
int count=0; //记录每一个类中数据点的数目
float errorX=INT_MAX; //假设初始时误差最大
float errorY=INT_MAX;
vector<Point>::iterator p_totalPoints;
vector<Point>::iterator p_classPoints;
Point temp;
int i;
while(errorX > 1e-6 && errorY > 1e-6)
{
for(p_totalPoints=totalPoints.begin(); p_totalPoints!=totalPoints.end(); p_totalPoints++)
{
//将所有的点就近分类
string className=computerDistance(p_totalPoints,classPoints);
(*p_totalPoints).className=className;
}
errorX=0;
errorY=0;
//按照均值重新划分聚类中心点
for(p_classPoints=classPoints.begin(); p_classPoints!=classPoints.end(); p_classPoints++)
{
count=0;
tempX=0;
tempY=0;
cout<<"Partition to cluster center "<<p_classPoints->className<<":";
for(p_totalPoints=totalPoints.begin(); p_totalPoints!=totalPoints.end(); p_totalPoints++)
{
if((*p_totalPoints).className==(*p_classPoints).className)
{
cout<<" ("<<(*p_totalPoints).x<<","<<(*p_totalPoints).y<<") ";
count++;
tempX+=(*p_totalPoints).x;
tempY+=(*p_totalPoints).y;
}
}
cout<<endl;
tempX /=count;
tempY /=count;
errorX +=fabs(tempX - (*p_classPoints).x);
errorY +=fabs(tempY - (*p_classPoints).y);
//计算X与Y均值
(*p_classPoints).x=tempX;
(*p_classPoints).y=tempY;
}
int i=0;
for(p_classPoints=classPoints.begin(); p_classPoints!=classPoints.end(); p_classPoints++,i++)
{
cout<<"Cluster center "<<i+1<<": x="<<(*p_classPoints).x<<" y="<<(*p_classPoints).y<<endl;
}
cout<<"-----------------------------------------------------------------"<<endl;
}
cout<<"Result value convergence"<<endl;
i=0;
for(p_classPoints=classPoints.begin(); p_classPoints!=classPoints.end(); p_classPoints++,i++)
{
cout<<"Cluster center "<<i+1<<": x="<<(*p_classPoints).x<<" y="<<(*p_classPoints).y<<endl;
}
cout<<"-----------------------------------------------------------------"<<endl;
}










