模糊c-means算法的c++实现
首先输入点的个数,维度,分类数目
我的代码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++实现的更多相关文章
- Fuzzy C Means 算法及其 Python 实现——写得很清楚,见原文
Fuzzy C Means 算法及其 Python 实现 转自:http://note4code.com/2015/04/14/fuzzy-c-means-%E7%AE%97%E6%B3%95%E5% ...
- K-means算法
K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢? ...
- paper 104: 彩色图像高速模糊的懒惰算法
工程及源代码:快速模糊.rar 图像模糊算法有很多种,我们最常见的就是均值模糊,即取一定半径内的像素值之平均值作为当前点的新的像素值,在一般的工业 ...
- 模糊C均值算法
Fuzzy C-Means读书笔记 一.算法简介 很显然,图中的数据集可分为两个簇.借鉴K-Means算法的思想,利用单个特殊的点(质心)表示一个簇.因此,我们用\(C_1\)和\(C_2\)分别表示 ...
- KNN 与 K - Means 算法比较
KNN K-Means 1.分类算法 聚类算法 2.监督学习 非监督学习 3.数据类型:喂给它的数据集是带label的数据,已经是完全正确的数据 喂给它的数据集是无label的数据,是杂乱无章的,经过 ...
- FCM聚类算法介绍
FCM算法是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小.模糊C均值算法是普通C均值算法的改进,普通C均值算法对于数据的划分是硬性的,而FCM则 ...
- 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)
最新的效果见 :http://video.sina.com.cn/v/b/124538950-1254492273.html 可处理视频的示例:视频去雾效果 在图像去雾这个领域,几乎没有人不知道< ...
- FCM算法
FCM算法是一种基于划分的聚类算法,它的思想就是使得被划分到同一簇的对象之间相似度最大,而不同簇之间的相似度最小.模糊C均值算法是普通C均值算法的改进,普通C均值算法对于数据的划分是硬性的,而FCM则 ...
- paper 105: 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他
在图像去雾这个领域,几乎没有人不知道<Single Image Haze Removal Using Dark Channel Prior>这篇文章,该文是2009年CVPR最佳论文.作者 ...
- Matalab之模糊KMeans实现
这节继续上节的KMeans进行介绍,上节主要是对模糊KMeans方法的原理做了介绍,没有实践印象总是不深刻,前段时间有个师姐让我帮着写了个模糊KMeans的算法,今天就拿她给出的例子来对这个方法做个实 ...
随机推荐
- 三角函数在Three.js中的点的移动轨迹应用
在学习2D文字的时候,看到官网有这样一个示例: https://threejs.org/examples/#css2d_label : if a ...
- 【tensorflow2.0】数据管道dataset
如果需要训练的数据大小不大,例如不到1G,那么可以直接全部读入内存中进行训练,这样一般效率最高. 但如果需要训练的数据很大,例如超过10G,无法一次载入内存,那么通常需要在训练的过程中分批逐渐读入. ...
- python--爬虫(XPath与BeautifulSoup4)
获取页面内容除使用正则意外,还可以使用XPath,其原理是将html代码转换为xml格式,然后使用XPath查找html节点或元素. 选取节点 XPath使用路径表达式来选取XML文档中的节点或节点集 ...
- Hadoop(二)搭建Hadoop
0.部署计划 本文使用的版本是 red hat 6.8 -本来想用Centos7搭建的,但是工作需要还是换成这个了,不用红帽子用Centos 6系列的应该也可以 JDK 1.8 Hadoop 2.7. ...
- android开发对应高德地图定位服务进度一
进行android的高德地图开发首先需要进入高德地图的控制台进行注册登录.之后创建新的应用并且绑定软件得到相应的key. 这里面需要找到自己软件对应的多个SHA1.这里有发布版和调试版,以及对应的软件 ...
- websocket聊天室
目录 websocket方法总结 群聊功能 基于websocket聊天室(版本一) websocket方法总结 # 后端 3个 class ChatConsumer(WebsocketConsumer ...
- MAC中PHP7.3安装mysql扩展
1.下载mysql扩展http://git.php.net/?p=pecl/database/mysql.git;a=summary 2.解压tar xzvf mysql-d7643af.tar.gz ...
- spark本地开发环境搭建及打包配置
在idea中新建工程 删除新项目的src,创建moudle 在父pom中添加spark和scala依赖,我们项目中用scala开发模型,建议scala,开发体验会更好(java.python也可以) ...
- Powershell追踪路由
一般情况下,我们可以通过Cmdlet命令来实现路由追踪 我们是否能尝试通过Powershell完成此功能呢? 脚本具体如下,可以直接粘贴 function GetTraceRoute($hostnam ...