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

我的代码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. 12.1 flask基础之简单实用

    一.Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来) Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是 ...

  2. 发现钉钉打卡定位算法的一个bug

    最近公司取消了指纹打卡,改用钉钉打卡. 天天用这个打卡上班,经常忘记,困扰. 最烦的是好几次明明人在办公室,打卡地址显示在10分钟前的位置,定位失败,不得不重新打卡. 经历过几次定位失败后,我就琢磨起 ...

  3. RedHat 6.7 下安装 Cadence IC617

    操作系统:RedHat 6.7 搭建一个RedHat的本地源[1]: # mount -o /dev/cdrom1 /mnt # mkdir -p /opt/redhat/6.7 # cp -rv / ...

  4. python中装饰器的使用

    看个例子: # 定义装饰器函数 def log(func): """ 接受一个函数作为参数,并返回一个函数 :param func: :return: "&qu ...

  5. LinkedHashMap 与 HashMap 实现的区别

    阅读前最好对 HashMap 的内部实现方式有一定了解 LinkedHashMap 继承自 HashMap 主要重写了一个节点类 LinkedHashMap.Entry,并维护一个头结点和尾节点 以及 ...

  6. Linux学习66 运维安全-通信加密和解密技术入门

    一.Linux Service and Security 1.OpenSSL(ssl/tls)协议 2.OpenSSH(ssh)协议 3.bind(dns) 4.web(http):httpd(apa ...

  7. Spring(三):bean的自动装配

    Bean的自动装配 自动装配是Spring满足bean依赖的一种方式. Spring会在上下文中自动寻找,并自动给bean装配属性 Spring中三种装配方式 在xml中显式的配置. 在java中显式 ...

  8. 基于 mpvue 框架的小程序选择控件,支持单列,多列,联动

    最近在学着写mpvue小程序,在做选择控件时候遇到了点问题,按照微信小程序方法picker,很不方便! 在网上搜到一个很好用的组件下面给大家分享: 组件说明文档链接:https://go.ctolib ...

  9. (js描述的)数据结构[哈希表1.1](8)

    (js描述的)数据结构[哈希表1.1](8) 一.数组的缺点 1.数组进行插入操作时,效率比较低. 2.数组基于索引去查找的操作效率非常高,基于内容去查找效率很低. 3.数组进行删除操作,效率也不高. ...

  10. (js描述的)数据结构[双向链表](5)

    (js描述的)数据结构[双向链表](5) 一.单向链表的缺点 1.只能按顺序查找,即从上一个到下一个,不能反过来. 二.双向链表的优点 1.可以双向查找 三.双向链表的缺点 1.结构较单向链表复杂. ...