首先输入点的个数,维度,分类数目

我的代码FCM中主要过程如下:

1:(init_c函数)随机初始化聚类中心

2:(comp_dis函数)计算每个点到每个聚类距离 dis[i][j] 表示i点到j聚类中心的距离

3:(while(1))进入循环

4:(comp_u函数)计算隶属度矩阵u[i][j]表示i点对应j聚类中心的隶属度

5:(update_c函数)根据隶属度和每个点的位置更新聚类中心

6:(compdis函数)因为聚类中心更新了嘛,再重新计算下每个点到每个聚类中心的距离

7:(comp_obj_func函数)计算函数值差值如果小于设定值eps则进行第8步,否则进行第9步

8:(break)退出循环

9:根据每个点的隶属度情况,给每个点分类(距离哪个聚类中心近,就给谁)

注意事项:

1.如果点很少的话,可能在我的初始化聚类中心函数中会有相同的点,造成分类错误,但实际应用中,点数足够多的情况则这个概率可以忽略

2.在计算隶属度的函数中,如果一个点距离一个聚类中心足够的近,那么直接将它的隶属度设置成1,其他的为0

其他:

如果有错误和疑问欢迎探讨,望多多指教!

代码:

 #include<iostream>
#include<cstdio>
#include<vector>
#include<fstream>
#include<cmath>
#include<ctime>
#include<cstdlib>
using namespace std;
struct Mode
{
int x,y;
int di;
vector<double> datas;
};
typedef vector<vector<Mode> > ModeVec;
const int N=;
const double eps=1e-;
const double eps_dis=1e-; double getDistance(Mode &m1,Mode &m2);
void FCM(Mode *p,int n,int di,int clusternum,vector<vector<Mode> > &ans);
void init_c(Mode *p,int n,int clusternum,Mode *c);
void comp_dis(Mode *p,Mode *c,int n,int clusternum,double dis[][]);
void comp_u(double dis[][],int n,int clusternum,double u[][]);
void update_c(Mode *p,double u[][],int n,int clusternum,Mode *c);
double comp_obj_func(double u[][],double dis[][],int n,int clusternum,int di);
int main()
{
int n,dimension,clusternum;
Mode p[N];
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
ifstream fin("in.txt");
ofstream fout("out.txt");
fin>>n>>dimension>>clusternum; //输入点的个数,维度,聚类数目
for(int i=; i<n; i++)
{
p[i].di=dimension;
for(int j=; j<dimension; j++)
{
double temp;
fin>>temp;
p[i].datas.push_back(temp);
}
}
vector<vector<Mode> > ans;
FCM(p,n,dimension,clusternum,ans); //传入数组p,有n个点,维度为dimension,结果保存在ans
for(int i=;i<clusternum;i++)
{
printf("第%d类:\n",i+);
for(int j=;j<ans[i].size();j++)
{
printf("(");
for(int k=;k<dimension;k++)
{
if(k==) printf("%f",ans[i][j].datas[k]);
else printf(",%f",ans[i][j].datas[k]);
}
printf(") ");
}
printf("\n");
}
return ;
}
double getDistance(Mode &m1,Mode &m2)
{
int di=m1.di;
double ans=;
for(int i=; i<di; i++)
ans+=(m1.datas[i]-m2.datas[i])*(m1.datas[i]-m2.datas[i]);
return ans;
}
void init_c(Mode *p,int n,int clusternum,Mode *c) //初始化聚类中心
{
int di=p[].di;
srand(time(NULL));
for(int i=;i<clusternum;i++)
{
c[i].di=di;
c[i].datas.clear();
for(int j=;j<di;j++)
c[i].datas.push_back();
}
for(int i=;i<n;i++)
for(int j=;j<di;j++)
for(int k=;k<clusternum;k++)
c[k].datas[j]+=p[i].datas[j];
for(int i=;i<clusternum;i++)
{
for(int j=;j<di;j++)
{
int tp=rand()%n+;
c[i].datas[j]/=tp;
}
}
}
void comp_dis(Mode *p,Mode *c,int n,int clusternum,double dis[][]) //初始化每个点和每个簇的距离
{
for(int i=; i<n; i++)
for(int j=; j<clusternum; j++)
dis[i][j]=getDistance(p[i],c[j]);
}
void comp_u(double dis[][],int n,int clusternum,double u[][]) //计算隶属度矩阵
{
for(int i=; i<n; i++)
{
double tp=;
for(int j=;j<clusternum;j++)
{
if(dis[i][j]<eps_dis) //如果这个点很接近一个簇类中心,那么这个隶属度设为1,其他为0
{
for(int k=;k<clusternum;k++)
u[i][k]=;
u[i][j]=;
return;
}
tp+=/dis[i][j];
}
tp=/tp;
for(int j=; j<clusternum; j++)
u[i][j]=tp*(/dis[i][j]);
}
}
void update_c(Mode *p,double u[][],int n,int clusternum,Mode *c)
{
int di=p[].di;
for(int j=;j<clusternum;j++)
{
c[j].di=di;
c[j].datas.clear();
for(int i=;i<di;i++)
c[j].datas.push_back();
double tp=;
for(int i=;i<n;i++)
{
for(int k=;k<di;k++)
c[j].datas[k]+=u[i][j]*u[i][j]*p[i].datas[k];
tp+=u[i][j]*u[i][j];
}
for(int k=;k<di;k++)
c[j].datas[k]/=tp;
}
}
double comp_obj_func(double u[][],double dis[][],int n,int clusternum,int di)
{
double sum=;
for(int i=;i<n;i++)
for(int j=;j<clusternum;j++)
sum+=u[i][j]*u[i][j]*dis[i][j];
return sum;
}
void FCM(Mode *p,int n,int di,int clusternum,vector<vector<Mode> > &ans) //in: n,d,c time:O(c*n*d) 时间复杂度=聚类数*点数*维数
{
int index=;
double sum=,psum;
Mode c[]; //聚类中心
double dis[N][]; //距离
double u[N][]; //隶属度矩阵
init_c(p,n,clusternum,c); // 初始化聚类中心 time: O(c)
comp_dis(p,c,n,clusternum,dis); //更新距离矩阵dis
while()
{
index++;
printf("第%d次循环----------------------------------------\n",index);
comp_u(dis,n,clusternum,u); //计算隶属度矩阵u time:O(n*c);
for(int i=;i<n;i++)
{
printf("第%d个点的隶属值\n",i+);
for(int j=;j<clusternum;j++)
{
printf("%f ",u[i][j]);
}
printf("\n");
}
update_c(p,u,n,clusternum,c); //更新聚类中心 time:O(c*(2*d+(n*d))) = O(c*n*d)
comp_dis(p,c,n,clusternum,dis); //重新计算距离矩阵
psum=sum;
sum=comp_obj_func(u,dis,n,clusternum,di);
printf("函数值=%f\n",sum);
if(fabs(psum-sum)<eps)
break;
}
for(int i=;i<clusternum;i++)
{
vector<Mode> m;
ans.push_back(m);
}
for(int i=;i<n;i++)
{
double tp=-;
int index=;
for(int j=;j<clusternum;j++)
{
if(u[i][j]>tp)
{
tp=u[i][j];
index=j;
}
}
ans[index].push_back(p[i]);
}
}

模糊c-means算法的c++实现的更多相关文章

  1. Fuzzy C Means 算法及其 Python 实现——写得很清楚,见原文

    Fuzzy C Means 算法及其 Python 实现 转自:http://note4code.com/2015/04/14/fuzzy-c-means-%E7%AE%97%E6%B3%95%E5% ...

  2. K-means算法

    K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢?  ...

  3. paper 104: 彩色图像高速模糊的懒惰算法

    工程及源代码:快速模糊.rar                            图像模糊算法有很多种,我们最常见的就是均值模糊,即取一定半径内的像素值之平均值作为当前点的新的像素值,在一般的工业 ...

  4. 模糊C均值算法

    Fuzzy C-Means读书笔记 一.算法简介 很显然,图中的数据集可分为两个簇.借鉴K-Means算法的思想,利用单个特殊的点(质心)表示一个簇.因此,我们用\(C_1\)和\(C_2\)分别表示 ...

  5. KNN 与 K - Means 算法比较

    KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...

  6. FCM聚类算法介绍

    FCM算法是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小.模糊C均值算法是普通C均值算法的改进,普通C均值算法对于数据的划分是硬性的,而FCM则 ...

  7. 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)

    最新的效果见 :http://video.sina.com.cn/v/b/124538950-1254492273.html 可处理视频的示例:视频去雾效果 在图像去雾这个领域,几乎没有人不知道< ...

  8. FCM算法

    FCM算法是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小.模糊C均值算法是普通C均值算法的改进,普通C均值算法对于数据的划分是硬性的,而FCM则 ...

  9. paper 105: 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他

    在图像去雾这个领域,几乎没有人不知道<Single Image Haze Removal Using Dark Channel Prior>这篇文章,该文是2009年CVPR最佳论文.作者 ...

  10. Matalab之模糊KMeans实现

    这节继续上节的KMeans进行介绍,上节主要是对模糊KMeans方法的原理做了介绍,没有实践印象总是不深刻,前段时间有个师姐让我帮着写了个模糊KMeans的算法,今天就拿她给出的例子来对这个方法做个实 ...

随机推荐

  1. NKOJ3777 卡牌操作

    问题描述 有n张卡片在桌上一字排开,每张卡片上有两个数,第i张卡片上,正面的数为a[i],反面的数为b[i].现在,有m个熊孩子来破坏你的卡片了!第i个熊孩子会交换c[i]和d[i]两个位置上的卡片. ...

  2. java中eclipse的安装和JDK的环境变量的配置以及记事本的使用

    2020-04-09 23:26:15 学习java的第一步当然就是环境配置了,java中的配置作为小白刚刚开始肯定会有点一点晕头转向的,开没等开始入门呢!就要准备放弃了.哈哈哈哈,没关系的,都是这么 ...

  3. 1-1. OSS/ALSA 声卡的驱动与配置和 Madplay 嵌入式播放器的移植

    报警子系统 一. OSS/ALSA 声卡的驱动与配置 声卡驱动中传统的OSS构架在02年被收购后即不开源,并且OSS的混音效果不好->因此ALSA构架孕育而生. ALSA(高级音频构架,目前应用 ...

  4. Win32程序:与"LPCWSTR"类型的形参不兼容

    出现该问题的原因是通常手动输入的字符串都是LPCSTR类型的, 解决办法如下: 在工程处右键,属性-常规-字符集,将Unicode字符集改为为多字节字符集,应用并确认即可.   字符串常量报错: 在常 ...

  5. jQuery实现回车键抬起触发事件

    $(function(){ //回车键按下触发 $(document).keydown(function(event){ if(event.keyCode==13){ alert("niha ...

  6. Golang笔记集

    学习Golang了, 下面分享我的, 还有我收集的Golang的学习资料 我的基础笔记地址: https://github.com/zhuchangwu/go-study-notes 其他参考: Go ...

  7. GitHub 热点速览 Vol.15:Background-Matting 让你秒变专业抠图师

    作者:HelloGitHub-小鱼干 摘要:如果要选一个词来概述上周的热点,春风拂过,应该是一个不错的词.新项目像春天冒出的枝芽,朝气蓬勃,虽然获得的 star 不如之前三维 Vim 抢眼,但胜在多姿 ...

  8. Android | 教你如何开发扫二维码功能

    前言   最近要做一个停车场扫码收费的app,在网上搜了一圈,首先接触到了ZXing,上手试了下,集成过程不复杂,但是感觉效果欠佳,比如距离稍微远点儿就扫不出来了,另外角度对的不好,反光或者光线比较暗 ...

  9. 【php】LAMP中开启错误提示

    vi /usr/local/php/etc/php.ini 查找display_errors 开启On即可

  10. 【php】文件的上传与下载

    一. 生活中常见的地方: a) 例如邮箱.空间.文库.百度云.微爱等地方,都可以看到文件的上传和下载的应用,因此,上传和下载的功能非常重要!二. PHP当中的文件上传和下载 a) 我们需要进行一些设置 ...