打印
[C语言]

聚类算法- K-means算法

[复制链接]
932|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
沙发
一路向北lm|  楼主 | 2020-8-11 18:25 | 只看该作者
聚类算法和分类算法的最大区别:
聚类算法是无监督的学习算法,而分类算法属于监督的学习算法。

使用特权

评论回复
板凳
一路向北lm|  楼主 | 2020-8-11 18:25 | 只看该作者
K-means算法:
01.        选择聚类的个数K,例如K = 3。
02.        生成K个聚类中心点。
03.        计算所有样本点到聚类中心的距离,根据远近聚类。
04.        更新质心,迭代聚类。
05.        重复第四步直到满足收敛要求。(通常是确定的中心点不再改变)

使用特权

评论回复
地板
一路向北lm|  楼主 | 2020-8-11 18:25 | 只看该作者
C++源码实现K-means 算法。
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <limits>
using namespace std;


使用特权

评论回复
5
一路向北lm|  楼主 | 2020-8-11 18:26 | 只看该作者
// 数据类型转换 string 转float
float StringToFloat(string str)
{
    stringstream  sstream;
        float score = 0;
        sstream<<str;
        sstream>>score;
        return score;
}


使用特权

评论回复
6
一路向北lm|  楼主 | 2020-8-11 18:26 | 只看该作者
//读取文件
vector<point_t> OpenFile(const char *dataset)
{
        fstream file;
        vector<point_t> data;
        file.open(dataset,ios::in);
        while(!file.eof())
        {
          string temp;
          file>>temp;
          int split =temp.find(',');
          point_t p;
          p.x = StringToFloat(temp.substr(0,split));
          p.y = StringToFloat(temp.substr(split+1,temp.length()-1));
          p.cluster = 0;
          data.push_back(p);
        }
        file.close();
   return data;
}


使用特权

评论回复
7
一路向北lm|  楼主 | 2020-8-11 18:26 | 只看该作者
//计算两点之间的距离
float SquareDistance(point_t a,point_t b)
{
        return ((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}


使用特权

评论回复
8
一路向北lm|  楼主 | 2020-8-11 18:27 | 只看该作者
//随机选择K个质点
vector<point_t> RandomSeceleK(vector<point_t>dataset,int k)
{
        unsigned int n = 1;
        unsigned int len = dataset.size();
        vector<point_t> centroid;
        srand((int)time(0));        //使用时间设定随机种子
        //随机选择质心,生成K个聚类中心点
        while(n<=k)
        {
                int cen = (float)rand()/(RAND_MAX+1)*len;
                point_t cp;
                cp.x = dataset[cen].x;
                cp.y = dataset[cen].y;
                cp.cluster = n;
                centroid.push_back(cp);
                n++;
        }
        return centroid;
}


使用特权

评论回复
9
一路向北lm|  楼主 | 2020-8-11 18:27 | 只看该作者
//计算所有样本点到聚类中心的距离,根据远近聚类
vector<point_t> DistanceCluster(vector<point_t>dataset,vector<point_t>centroid,int k)
{
        int len = dataset.size();
        int n = 1;
        for(int i=0;i<len;i++)
        {
                n=1;
                float shortest = INT_MAX;
                int cur = dataset[i].cluster;
                while(n<=k)
                {
                        float temp = SquareDistance(dataset[i],centroid[n-1]);                       
                        if(temp<shortest)
                        {
                                shortest = temp;
                                cur = n;
                        }
                        n++;
                }
                dataset[i].cluster = cur;
        }
        return dataset;
}


使用特权

评论回复
10
一路向北lm|  楼主 | 2020-8-11 18:27 | 只看该作者
//更新质心
vector<point_t> UpdateCentroid(vector<point_t>dataset,vector<point_t>centroid,int k)
{
    int len = dataset.size();
        int *cs = new int[k];
        for(int i=0;i<k;i++) cs[i] = 0;
        for(int i=0;i<k;i++)
        {
                centroid[i].x = 0;
                centroid[i].y = 0;
                centroid[i].cluster = i+1;
        }
        for(int i=0;i<len;i++)
        {
                centroid[dataset[i].cluster-1].x += dataset[i].x;
                centroid[dataset[i].cluster-1].y += dataset[i].y;
                cs[dataset[i].cluster-1]++;
        }
        for(int i=0;i<k;i++)
        {
                centroid[i].x /= cs[i];
                centroid[i].y /= cs[i];
        }
        return centroid;
}


使用特权

评论回复
11
一路向北lm|  楼主 | 2020-8-11 18:28 | 只看该作者
//k-means 算法
void k_means(vector<point_t>dataset,int k,int looptimes)
{
        vector<point_t> centroid;   //存放中心点
        int n =1;
        int len = dataset.size();
        //1.随机选择K个质点
        centroid = RandomSeceleK(dataset,k);
        //打印中心点(质点)
        for(int i=0;i<k;i++)
        {
          cout<<"x:"<<centroid[i].x<<"\ty:"<<centroid[i].y<<"\tc:"<<centroid[i].cluster<<endl;
        }
        //循环迭代
        for(int i = 0;i<looptimes;i++)
        {
           //2.计算所有样本点到聚类中心的距离,根据远近聚类
           dataset = DistanceCluster(dataset,centroid,k);          
           //3.更新质心,迭代聚类
           centroid = UpdateCentroid(dataset,centroid,k);   
        }
        //打印所有点聚类情况
         for(int i=0;i<dataset.size();i++)
           {
             cout<<dataset[i].cluster<<endl;
           }
        //打印最后更新质心
        for(int i=0;i<k;i++)
        {
                cout<<"x:"<<centroid[i].x<<"\ty:"<<centroid[i].y<<"\tc:"<<centroid[i].cluster<<endl;
        }
    //写入到文件保存
        fstream clustering;
        clustering.open("clustering.txt",ios::out);
        for(int i=0;i<len;i++)
        {
                clustering<<dataset[i].x<<","<<dataset[i].y<<","<<dataset[i].cluster<<"\n";
        }
        clustering.close();
}


使用特权

评论回复
12
一路向北lm|  楼主 | 2020-8-11 18:28 | 只看该作者
主函数测试代码,分为两类,迭代100
#include "k_means.h"

int main()
{
    vector<point_t> data;
        cout<<"k-means"<<endl;
        data = OpenFile("01.txt");
        k_means(data,2,100);
        while(1);
}


使用特权

评论回复
13
一路向北lm|  楼主 | 2020-8-11 18:28 | 只看该作者
测试结果如下:质心不再改变。

使用特权

评论回复
14
一路向北lm|  楼主 | 2020-8-11 18:29 | 只看该作者
测试文本内容和输出文本内容:

使用特权

评论回复
15
一路向北lm|  楼主 | 2020-8-11 18:29 | 只看该作者
总结:
K-means算法运行速度快,实现简便。但K-means算法对具有变化大小,变化密度,非圆形状等特点的数据具有局限性。解决方法是增加K的大小,增加cluster数量,使得数据的特征能够更加明显。对于数据初始中心点的选择,采用随机的方式可能无法产生理想的聚类,这时可以采用二分K-means方法,或层次聚类进行处理。

使用特权

评论回复
16
wsnsyy| | 2020-8-12 19:51 | 只看该作者
这是做什么用

使用特权

评论回复
17
一路向北lm|  楼主 | 2020-8-13 09:33 | 只看该作者

智能分类

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

277

主题

3805

帖子

76

粉丝