机器学习算法k-均值聚类之c++实现(不调用外源库)

 目前玩机器学习的小伙伴,上来就是使用现有的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++实现(不调用外源库)

有问题可以私信或者留言,有问必答

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值