无监督学习算法K-means算法总结与c++编程实现




Figure 1: K-means algorithm. Training examples are shown as dots, and cluster centroids are shown as crosses. (a) Original dataset. (b) Random initial cluster centroids (in this instance, not chosen to be equal to twotrainingexamples). (c-f) Illustration of running two iterations of k-means. In each iteration, we assign each training example to the closest cluster centroid(shown by “painting” the training examples the same color as the cluster centroid to which is assigned); then we move each cluster centroid to the mean of the points assigned to it. (Best viewed in color.) Images courtesy Michael Jordan.

注意:

问题1:K值选取问题

K的选取通常是我们的目标,也就是说,我们要将这队数据分为几类。因此,是相对明确的。

问题2:初始值的选取问题

初始值的选取对于迭代的结果有较大的影响,选取不当,会出现所有点都归为一类的情况。一个通常的解决方案是:随机选取多组初始值进行分类,选取损失函数最小的分类结果。

编程举例:

将如下三维空间的点进行k-means分类:

[input.txt]

1.0 , 5.7 , 2.8

4.5 , 5.2 , -0.3

-0.9 , 8.1 , 1.4

0.5 , 6.6 , 2.3

3.5 , 4.7 , 0.2

4.7 , 5.9 , -1

5.1 , 8.2 , 0.9

2.1 , 7.4 , 3.0

0.6 , 6.5 , 3.8

在三维空间的图及k-means分类的结果


K-means算法的c++实现代码:

#include 
#include 
#include 
#include 
#define dim  3//输入特征x的维数
#define K    2//分类的个数
#define MAX_NUM 100//读取输入数据的最大数目
using namespace std;
//定义类,封装输入向量x,及它要分到哪个类别
class InputFeature
{
public:
	double x[dim];//保存输入数据的向量坐标
	int cluster;//标志分类的哪一类(0,1,...,K)
	InputFeature(double x[dim])//构造函数
	{
       memcpy(this->x,x,sizeof(double)*dim);
	   cluster=-1;
	}
	//输入函数
	void print()
	{
		cout<<"cluster="< InputVector;//保存输入特征向量
void inputData()//从文件中读取数据
{
	ifstream ifile("input.txt");  
    if(!ifile)  
    {  
        cout<<"input.txt cannot be opened!"<err)
			{
				return false;
			}
		}
   }
	return true;
}
//k-means算法核心
void k_means(double U[K][dim])
{
   double U0[K][dim];
   memcpy(U0,U,sizeof(double)*K*dim);
   while (true)
   {
	   //第一步 标定集合中的点,离哪个U点最近,即将其cluster修改为对应的分类
	   int j;
	   vector::iterator it;
	   for(it = InputVector.begin(); it != InputVector.end(); ++it)
	   {
		   double dist[K];
		   for (j=0;jdistanceOf(U[j]);
		   }
		   double minDist=dist[0];//初始化最小距离
		   it->cluster=0;//初始化分类
		   for (j=1;jcluster=j;
			   }
		   }
	   }
	   //第二步 更新重心U
	   double sum[K][dim],num[K];
	   memset(&sum,0,sizeof(double)*K*dim);
	   memset(&num,0,sizeof(double)*K);
       for(it = InputVector.begin(); it != InputVector.end(); ++it)
	   {
		   for (int d=0;dcluster][d]+=it->x[d];
		   }
		   num[it->cluster]++;//计算相同分类的数目
	   }
	   for (j=0;j::iterator it;
   for(it = InputVector.begin(); it != InputVector.end(); ++it)
   {
	   it->print();
   }
   //计算误差函数
   double J=0;
   for(it = InputVector.begin(); it != InputVector.end(); ++it)
   {
	   J+=it->distanceOf(U[it->cluster]);
   }
   cout<<"误差函数J(c,u)="<

实验结果:


matlab plot code

% *@author:郑海波 [email protected]
% *http://blog.csdn.net/nuptboyzhb/
clear all;
clc;
close all;
x=[1.0 , 5.7 , 2.8
4.5 , 5.2 , -0.3
-0.9 , 8.1 , 1.4
0.5 , 6.6 , 2.3
3.5 , 4.7 , 0.2
4.7 , 5.9 , -1
5.1 , 6.2 , 0.9
2.1 , 7.4 , 3.0];
subplot(1,2,1);
plot3(x(:,1),x(:,2),x(:,3),'o');
hold on;
U1=[4.5,8.1,2.8];
U2=[-0.9,4.7,-0.3];
plot3(U1(1),U1(2),U1(3),'+');
hold on;
plot3(U2(1),U2(2),U2(3),'r+');
hold on;
title('o--原始数据,+初始的迭代点');
x1=[1.0 , 5.7 , 2.8
-0.9 , 8.1 , 1.4
0.5 , 6.6 , 2.3
2.1 , 7.4 , 3.0];
x2=[4.5 , 5.2 , -0.3
3.5 , 4.7 , 0.2
4.7 , 5.9 , -1
5.1 , 6.2 , 0.9];
subplot(1,2,2);
plot3(x1(:,1),x1(:,2),x1(:,3),'o');
hold on;
plot3(x2(:,1),x2(:,2),x2(:,3),'ro');
hold on;
U1=[4.45 5.5 -0.05];
U2=[0.675 6.95 2.125];
plot3(U1(1),U1(2),U1(3),'r*');
hold on;
plot3(U2(1),U2(2),U2(3),'*');
hold on;
title('迭代结果,*为聚类点的中心');

未经允许不得用于商业目的




你可能感兴趣的:(【算法】)