您的位置:首页 > 编程语言 > C语言/C++

数据挖掘-聚类分析:k-平均(k-Means)算法实现(C++)

2013-07-12 22:33 676 查看

数据挖掘-聚类分析:k-平均(k-Means)算法实现(C++)

k-Means算法主要思想:将所有特征对象划分为k个簇,每个簇至少拥有一个对象,每个对象只属于一个簇。

每个簇中的对象之间相似度最高,不同簇之间的相似度最低。

k-Means算法以对象到簇的中心点的距离作为相似度的衡量标准,以准则函数作为聚类质量的衡量标准。

算法所涉及的距离采用欧基米德距离。

算法首先给出一个初始的划分方法,以后通过反复迭代的方法改变划分,使得每一次改进之后的划分方案

都较前一次更好。好的标准就是同一簇中的对象越近越好,而不同簇中的对象越远越好。

算法的准则是最小化所有对象与其参照点(相应簇的中心点)之间的相异度(距离)之和。

// ceshi.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <iostream>

#include <math.h>

#include <vector>

#define _NUM 3 //预定义划分簇的数目

using namespace std;

/**

特征对象,表示一个元组,一个元组有两个数值属性

**/

struct Tuple

{

int attr1;

int attr2;

};

/**

获取两个特征对象之间的距离,在此以欧基米德距离作为距离度量标准

**/

double getDistXY(Tuple t1, Tuple t2)

{

return sqrt((double)(t1.attr1 - t2.attr1) * (t1.attr1 - t2.attr1) + (t1.attr2 - t2.attr2) * (t1.attr2 - t2.attr2));

}

/**

计算簇的中心点,在此以簇中所有对象的平均距离来计算中心点

**/

Tuple getMeansC(vector<Tuple> c)

{

int num = c.size();

double meansX = 0, meansY = 0;

Tuple t;

for (int i = 0; i < num; i++)

{

meansX += c[i].attr1;

meansY += c[i].attr2;

}

t.attr1 = meansX / num;

t.attr2 = meansY / num;

return t;

}

/**

获取算法的准则函数值,当准则函数收敛时算法停止

**/

double getE(vector<Tuple> classes[], Tuple means[])

{

double sum = 0;

for (int i = 0; i < _NUM; i++)

{

vector<Tuple> v = classes[i];

for (int j = 0; j< v.size(); j++)

{

sum += (v[j].attr1 - means[i].attr1) * (v[j].attr1 - means[i].attr1) + (v[j].attr2 - means[i].attr2) *(v[j].attr2 - means[i].attr2);

}

}

cout<<"sum:"<<sum<<endl;

return sum;

}

/**

对当前的特征对象,查找与其最临近的簇,最临近即到簇中心点的距离最短

**/

int searchMinC(Tuple t, Tuple means[_NUM])

{

int c = 0;

int d = (t.attr1 - means[0].attr1) * (t.attr1 - means[0].attr1) + (t.attr2 - means[0].attr2) * (t.attr2 - means[0].attr2);

for (int i = 1; i < _NUM; i++)

{

int temp = (t.attr1 - means[i].attr1) * (t.attr1 - means[i].attr1) + (t.attr2 - means[i].attr2) * (t.attr2 - means[i].attr2);

if (temp < d)

{

c = i;

d = temp;

}

}

return c;

}

/**

k-Means算法

**/

void kMeans(vector<Tuple> init)

{

vector<Tuple> classes[_NUM]; //定义簇数组,共需划分_NUM个簇

int c;

Tuple means[_NUM]; //定义中心点数组,每个簇对应一个中心点

double newE, oldE = -1; //定义准则函数值

for (int i = 0; i < _NUM; i++) //对每个簇初始赋予一个特征对象

{

cin >> c;

classes[i].push_back(init[c - 1]);

means[i] = getMeansC(classes[i]); //计算当前每个簇的中心点

cout<<"means["<<i<<"]:"<<means[i].attr1<<" "<<means[i].attr2<<endl;

}

newE = getE(classes, means); //计算当前准则函数值

cout<<"newE:"<<newE<<" oldE:"<<oldE<<endl;

for (int i = 0; i < _NUM; i++) //清空每个簇

{

classes[i].clear();

}

while(abs(newE - oldE) >= 1) //当新旧函数值相差不到1即准则函数值不发生明显变化时,算法终止

{

for (int j = 0; j < init.size(); j++) //遍历所有特征对象,将其加入到离它最近的簇

{

int toC = searchMinC(init[j], means);

classes[toC].push_back(init[j]);

}

cout<<"--------------------"<<endl;

for (int i = 0; i < _NUM; 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 (int i = 0; i < _NUM; i++) //更新每个簇的中心点

{

means[i] = getMeansC(classes[i]);

cout<<"means["<<i<<"]:"<<means[i].attr1<<" "<<means[i].attr2<<endl;

}

oldE = newE;

newE = getE(classes, means); //计算新的准则函数值

for (int i = 0; i < _NUM; i++) //清空每个簇

{

classes[i].clear();

}

}

}

/**

程序入口

**/

void main(int args, char * arg[])

{

int n1, n2;

vector<Tuple> init; //保存所有输入的特征对象

while ((cin >> n1 >> n2) && n1 != -1 && n2 != -1) //输入特征对象

{

Tuple p;

p.attr1 = n1;

p.attr2 = n2;

init.push_back(p);

}

kMeans(init); //调用k-Means算法进行聚类分析

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐