K-Means算法和实现代码
来源:互联网 发布:js中如何格式化日期 编辑:程序博客网 时间:2024/04/30 23:02
在数据挖掘中,K-Means算法是一种cluster analysis的算法,其主要是来计算数据聚集的算法,主要通过不断地取离种子点最近均值的算法。
问题
K-Means算法主要解决的问题如下图所示。我们可以看到,在图的左边有一些点,我们用肉眼可以看出来有四个点群,但是我们怎么通过计算机程序找出这几个点群来呢?于是就出现了我们的K-Means算法
K-Means要解决的问题
算法概要
这个算法其实很简单,如下图所示:
从上图中,我们可以看到,A,B,C,D,E是五个在图中点。而灰色的点是我们的种子点,也就是我们用来找点群的点。有两个种子点,所以K=2。
然后,K-Means的算法如下:
- 随机在图中取K(这里K=2)个种子点。
- 然后对图中的所有点求到这K个种子点的距离,假如点Pi离种子点Si最近,那么Pi属于Si点群。(上图中,我们可以看到A,B属于上面的种子点,C,D,E属于下面中部的种子点)
- 接下来,我们要移动种子点到属于他的“点群”的中心。(见图上的第三步)
- 然后重复第2)和第3)步,直到,种子点没有移动(我们可以看到图中的第四步上面的种子点聚合了A,B,C,下面的种子点聚合了D,E)。
这个算法很简单,但是有些细节我要提一下,求距离的公式我不说了,大家有初中毕业水平的人都应该知道怎么算的。我重点想说一下“求点群中心的算法”。
求点群中心的算法
一般来说,求点群中心点的算法你可以很简的使用各个点的X/Y坐标的平均值。不过,我这里想告诉大家另三个求中心点的的公式:
1)Minkowski Distance公式——λ可以随意取值,可以是负数,也可以是正数,或是无穷大。
2)Euclidean Distance公式——也就是第一个公式λ=2的情况
3)CityBlock Distance公式——也就是第一个公式λ=1的情况
这三个公式的求中心点有一些不一样的地方,我们看下图(对于第一个λ在0-1之间)。
(1)Minkowski Distance (2)Euclidean Distance (3) CityBlock Distance
上面这几个图的大意是他们是怎么个逼近中心的,第一个图以星形的方式,第二个图以同心圆的方式,第三个图以菱形的方式。
K-Means的演示
如果你以”K Means Demo“为关键字到Google里查你可以查到很多演示。这里推荐一个演示:http://home.dei.polimi.it/matteucc/Clustering/tutorial_html/AppletKM.html
操作是,鼠标左键是初始化点,右键初始化“种子点”,然后勾选“Show History”可以看到一步一步的迭代。
注:这个演示的链接也有一个不错的K Means Tutorial。
K-Means++算法
K-Means主要有两个最重大的缺陷——都和初始值有关:
- K是事先给定的,这个K值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。(ISODATA算法通过类的自动合并和分裂,得到较为合理的类型数目K)
- K-Means算法需要用初始随机种子点来搞,这个随机种子点太重要,不同的随机种子点会有得到完全不同的结果。(K-Means++算法可以用来解决这个问题,其可以有效地选择初始点)
我在这里重点说一下K-Means++算法步骤:
- 先从我们的数据库随机挑个随机点当“种子点”。
- 对于每个点,我们都计算其和最近的一个“种子点”的距离D(x)并保存在一个数组里,然后把这些距离加起来得到Sum(D(x))。
- 然后,再取一个随机值,用权重的方式来取计算下一个“种子点”。这个算法的实现是,先取一个能落在Sum(D(x))中的随机值Random,然后用Random -= D(x),直到其<=0,此时的点就是下一个“种子点”。
- 重复第(2)和第(3)步直到所有的K个种子点都被选出来。
- 进行K-Means算法。
相关的代码你可以在这里找到“implement the K-means++ algorithm”(墙)另,Apache的通用数据学库也实现了这一算法
K-Means算法应用
看到这里,你会说,K-Means算法看来很简单,而且好像就是在玩坐标点,没什么真实用处。而且,这个算法缺陷很多,还不如人工呢。是的,前面的例子只是玩二维坐标点,的确没什么意思。但是你想一下下面的几个问题:
1)如果不是二维的,是多维的,如5维的,那么,就只能用计算机来计算了。
2)二维坐标点的X,Y 坐标,其实是一种向量,是一种数学抽象。现实世界中很多属性是可以抽象成向量的,比如,我们的年龄,我们的喜好,我们的商品,等等,能抽象成向量的目的就是可以让计算机知道某两个属性间的距离。如:我们认为,18岁的人离24岁的人的距离要比离12岁的距离要近,鞋子这个商品离衣服这个商品的距离要比电脑要近,等等。
只要能把现实世界的物体的属性抽象成向量,就可以用K-Means算法来归类了。
K-Means++算法
K-Means主要有两个最重大的缺陷——都和初始值有关:
- K是事先给定的,这个K值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。(ISODATA算法通过类的自动合并和分裂,得到较为合理的类型数目K)
- K-Means算法需要用初始随机种子点来搞,这个随机种子点太重要,不同的随机种子点会有得到完全不同的结果。(K-Means++算法可以用来解决这个问题,其可以有效地选择初始点)
我在这里重点说一下K-Means++算法步骤:
- 先从我们的数据库随机挑个随机点当“种子点”。
- 对于每个点,我们都计算其和最近的一个“种子点”的距离D(x)并保存在一个数组里,然后把这些距离加起来得到Sum(D(x))。
- 然后,再取一个随机值,用权重的方式来取计算下一个“种子点”。这个算法的实现是,先取一个能落在Sum(D(x))中的随机值Random,然后用Random -= D(x),直到其<=0,此时的点就是下一个“种子点”。
- 重复第(2)和第(3)步直到所有的K个种子点都被选出来。
- 进行K-Means算法。
相关的代码你可以在这里找到“implement the K-means++ algorithm”(墙)另,Apache的通用数据学库也实现了这一算法
K-Means算法应用
看到这里,你会说,K-Means算法看来很简单,而且好像就是在玩坐标点,没什么真实用处。而且,这个算法缺陷很多,还不如人工呢。是的,前面的例子只是玩二维坐标点,的确没什么意思。但是你想一下下面的几个问题:
1)如果不是二维的,是多维的,如5维的,那么,就只能用计算机来计算了。
2)二维坐标点的X,Y 坐标,其实是一种向量,是一种数学抽象。现实世界中很多属性是可以抽象成向量的,比如,我们的年龄,我们的喜好,我们的商品,等等,能抽象成向量的目的就是可以让计算机知道某两个属性间的距离。如:我们认为,18岁的人离24岁的人的距离要比离12岁的距离要近,鞋子这个商品离衣服这个商品的距离要比电脑要近,等等。
只要能把现实世界的物体的属性抽象成向量,就可以用K-Means算法来归类了。
#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((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 (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 (i = 0; i < _NUM; i++) //打印出当前每个簇的特征对象 {
vector<Tuple> temp = classes[i];
cout<<"类"<<i+1<<":"<<endl;
for (j = 0; j < temp.size(); j++)
{
cout<<temp[j].attr1<<" "<<temp[j].attr2<<endl;
}
}
cout<<"--------------------"<<endl;
for (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 (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算法进行聚类分析
}
- K-Means算法和实现代码
- k-means算法MATLAB和opencv代码
- k-means算法MATLAB和opencv代码
- k-means算法代码
- K-means算法实现
- K-means算法实现
- K-means、K-means ++、K-modes和K-prototype聚类算法简述 附Python代码
- K-Means 和K-Medoids算法及其MATLAB实现
- K-Means 和K-Medoids算法及其MATLAB实现
- K-means算法JAVA代码
- 一个K-means聚类算法的实现代码和分析
- K-Means算法的代码实现(Java)
- K-Means算法的代码实现(Java)
- K-Means算法的代码实现(Java)
- 数据分类K—means 算法的python代码实现
- 简单的K-means算法C语言实现代码
- K-means 聚类算法及其代码实现
- K-means 聚类算法及其代码实现
- 整理了一下Xcode快捷键,史上最全!
- Instruments-Automation: 如何连续运行多个测试脚本
- BackgroundWorker Class Sample for Beginners
- EF性能之关联加载
- William Stallings 博士介绍 及 关于一些计算数学基础性的材料 -
- K-Means算法和实现代码
- www
- TopCoder SRM 144 div2
- 解决 MYSQL 8 小时问题
- python 中中文编码及输出问题
- .net webSocket例子
- android-apktool工具在Windows平台使用
- {jsp 循环显示list内容}
- 头寸管理表