目前玩机器学习的小伙伴,上来就是使用现有的sklearn机器学习包,写两行代码,调调参数就能跑起来,看似方便,实则有时不利于个人能力发展,要知道现在公司需要的算法工程师,不仅仅只是会调参(这种工作,入门几个月的人就可以干了),而是要深入底层,能优化代码,能自己搭。
本文章适合以下几类人:
1)初学者,了解机器学习的实现过程
2)想提升自己的代码能力
第一步:原理
什么是k-均值聚类?
k-均值聚类算法是一种经典的聚类算法,其基本原理是将样本数据集分为k个簇,使得同一个簇内的样本相似度较高,不同簇之间的样本相似度较低。具体实现步骤如下:
1. 随机选择k个点作为初始质心;
2. 将每个样本点分配到最近的质心所在的簇中;
3. 重新计算每个簇的质心;
4. 重复步骤2和3,直到质心不再变化或达到最大迭代次数。
在进行k-均值聚类时,需要选择合适的k值,可以通过手肘法或轮廓系数法等方式进行确定。
regression的推导,百度一下很多,这里就做一下搬运工了,可参考:机器学习实战 第十章 利用k-均值聚类算法对未标注数据分组_利用k均值聚类算法根据样本分小组组-CSDN博客
第二步:代码实现
/**
Kmeans算法致命的就是聚成空类的出现,值得分析一下kmeans什么情况下会出现空类,
该程序中未对此作处理,后面肯定还是会遇到这个问题的,以后再分析
**/
#include <iostream>
#include <stdlib.h>
#include <random>
#include <time.h>
#include "matrix.h"
using namespace std;
#define MAX 1000000
#define MIN -100000
#define MAXK 10
/**
Kmeans聚类中心数据结构
*/
struct CenAndDis
{
Matrix cen;
Matrix dis;
};
double distances(Matrix xOne, Matrix kCen)
{
int i,j;
double dis = 0;
for (i = 0; i < xOne.row; i++)
{
dis += pow((xOne.mat[0][i] - kCen.mat[0][i]),2);
}
return dis;
}
/**
随机初始化一个聚类中心,初始化的方式有两种,一种是随机从样本中选一个作为聚类中心,
一种是在样本空间内初始化一个聚类中心,可以不是具体某个样本,类中心的初始化非常关键
下面采用的是从样本中选择作为聚类中心,从样本中选取聚类中心同样也会出现聚成空类的现象,对此解决办法是
**/
Matrix randCent(Matrix x,int kNum)
{
int i,j,k;
Matrix initmeans;
initmeans.initMatrix(&initmeans,kNum,x.row);
double min[2];
double max[2];
/**
在样本空间内随机初始化k个类中心
**/
for(j=0; j<x.row; j++)
{
min[j]=MAX;
max[j]=MIN;
for(i=0; i<x.col; i++)
{
if(x.mat[i][j]<min[j])
{
min[j]=x.mat[i][j];
}
if(x.mat[i][j]>max[j])
{
max[j]=x.mat[i][j];
}
}
}
/**
随机从样本中选择k个样本作为类中心
*/
int randIndex = 0;//随机取得数据
for(k=0; k<kNum; k++)
{
randIndex = rand() % x.col;
for(j=0; j<x.row; j++)
{
//改变初值的选取,得到的聚类中心会不一致,可见初值的选取的关键,//x.mat[randIndex][j];
initmeans.mat[k][j]=min[j]+(max[j]-min[j])*((rand()%11) / 10.0);
cout<<initmeans.mat[k][j]<<" ";
}
cout<<endl;
}
return initmeans;
}
CenAndDis kMeans(Matrix x, int kNum)
{
}
Matrix subMatrix(Matrix x,Matrix clusterAssment,int label)
{
int i=0,j=0,k=0;
Matrix submatrix;
submatrix.initMatrix(&submatrix,x.col,x.row);
for(i=0; i<x.col; i++)
{
if(clusterAssment.mat[i][0]==label)
{
for(j=0; j<x.row; j++)
{
submatrix.mat[k][j]=x.mat[i][j];
}
k++;
}
}
submatrix.col=k;
return submatrix;
}
/***
二分聚类的思想是每一次都采用一个典型的二类聚类,而在选择把那个子类进行二分的评价标准是SSE,
即分裂哪一类使得SSE最小就分裂哪一类,SSE是最小平方和误差,即使得聚类结果的距离最小平方和误差最小
就对哪一类进行二分,直到不再减少SSE,或者有一类为空类,或者到达预设的聚为K类
**/
int biKmeans(Matrix x, int kNum)
{
}
int main()
{
srand((unsigned)time(NULL));
dataToMatrix dtm;
char file[30]="G:/data/kmeans.txt";
dtm.loadData(&dtm,file);
Matrix x;
x.loadMatrix(&x,dtm);
//x.print(x);
kMeans(x,4);
//biKmeans(x,4);
}
第三步:运行过程
运行结果
用到的软件是vs2010以上的版本都可以,不用额外配置什么,没调包,会用这个软件进行c++开发,就会使用这个软件
此程序由于不调用任何外源库,所以读者可以看清楚每一个算法的原理,要想学好机器学习算法,必须打好基础,不要好高骛远,另外,程序都是有备注,应该很好理解的,实在不懂,可以来问店主
代码的下载路径(新窗口打开链接):机器学习算法k-均值聚类之c++实现(不调用外源库)
有问题可以私信或者留言,有问必答