用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很赏心悦目~

  

  并行化思路:

  使用主从模式。由一个节点充当主节点负责数据的划分与分配,其他节点完成本地数据的计算,并将结果返回给主节点。大致过程如下:

  1、进程0为主节点,先从文件中读取数据集,然后将数据集划分并传给其他进程;

  2、进程0选择每个聚类的中心点,并发送给其他进程;

  3、其他进程计算数据块中每个点到中心点的距离,然后标出每个点所属的聚类,并计算每个聚类所有点到其中心点的距离之和,最后将这些结果返回给进程0;

  4、进程0计算出新的中心点并发送给其他进程,并计算其他进程传来的聚类所有点到其中心点的距离总和;

  5、重复3和4直到,直到步骤4中的所有聚类的距离之和不变(即收敛)。

  code:

 #include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "mpi.h" int main(int argc,char *argv[])
{
int i,j;
MPI_Status status;
float temp1,temp2;
int K,N,D; //聚类的数目,数据量,数据的维数
float **data; //存放数据
int *all_in_cluster; //进程0标记每个点属于哪个聚类
int *local_in_cluster; //其他进程标记每个点属于哪个聚类
int *in_cluster; //进程0标记每个点属于哪个聚类
int count=;
float *sum_diff;
float *global_sum_diff;
float **cluster_center; //存放每个聚类的中心点
int rank,size;
float **array(int m,int n);
float **loadData(int *k,int *d,int *n);
float getDistance(float avector[],float bvector[],int n);
void cluster(int n,int k,int d,float **data,float **cluster_center,int *local_in_cluster);
float getDifference(int k,int n,int d,int *in_cluster,float **data,float **cluster_center,float *sum);
void getCenter(int k,int d,int n,int *in_cluster,float **data,float **cluster_center); MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
if(!rank){
data=loadData(&K,&D,&N); //进程0读入数据
if(size==||size>N||N%(size-)) MPI_Abort(MPI_COMM_WORLD,); //若不满足条件则退出
}
MPI_Bcast(&K,,MPI_INT,,MPI_COMM_WORLD); //进程0广播
MPI_Bcast(&N,,MPI_INT,,MPI_COMM_WORLD);
MPI_Bcast(&D,,MPI_INT,,MPI_COMM_WORLD);
if(rank) data=array(N/(size-),D); //其他进程分配存储数据集的空间
all_in_cluster=(int *)malloc(N/(size-)*size*sizeof(int)); //用于进程0
local_in_cluster=(int *)malloc(N/(size-)*sizeof(int)); //用于每个进程
in_cluster=(int *)malloc(N*sizeof(int)); //用于进程0
sum_diff=(float *)malloc(K*sizeof(float)); //进程中每个聚类的数据点与其中心点的距离之和
global_sum_diff=(float *)malloc(K*sizeof(float));
for(i=;i<K;i++) sum_diff[i]=0.0; //初始化 if(!rank){ //进程0向其他进程分配数据集
for(i=;i<N;i+=(N/(size-)))
for(j=;j<(N/(size-));j++)
MPI_Send(data[i+j],D,MPI_FLOAT,(i+j)/(N/(size-))+,,MPI_COMM_WORLD);
printf("Data sets:\n");
for(i=;i<N;i++)
for(j=;j<D;j++){
printf("%-8.2f",data[i][j]);
if((j+)%D==) putchar('\n');
}
printf("-----------------------------\n");
}else{ //其他进程接收进程0数据
for(i=;i<(N/(size-));i++)
MPI_Recv(data[i],D,MPI_FLOAT,,,MPI_COMM_WORLD,&status);
}
MPI_Barrier(MPI_COMM_WORLD); //同步一下
cluster_center=array(K,D); //中心点
if(!rank){ //进程0产生随机中心点
srand((unsigned int)(time(NULL))); //随机初始化k个中心点
for(i=;i<K;i++)
for(j=;j<D;j++)
cluster_center[i][j]=data[(int)((double)N*rand()/(RAND_MAX+1.0))][j];
}
for(i=;i<K;i++) MPI_Bcast(cluster_center[i],D,MPI_FLOAT,,MPI_COMM_WORLD); //进程0向其他进程广播中心点
if(rank){
cluster(N/(size-),K,D,data,cluster_center,local_in_cluster); //其他进程进行聚类
getDifference(K,N/(size-),D,local_in_cluster,data,cluster_center,sum_diff);
for(i=;i<N/(size-);i++)
printf("data[%d] in cluster-%d\n",(rank-)*(N/(size-))+i,local_in_cluster[i]+);
}
MPI_Gather(local_in_cluster,N/(size-),MPI_INT,all_in_cluster,N/(size-),MPI_INT,,MPI_COMM_WORLD); //全收集于进程0
MPI_Reduce(sum_diff,global_sum_diff,K,MPI_FLOAT,MPI_SUM,,MPI_COMM_WORLD); //归约至进程0,进程中每个聚类的数据点与其中心点的距离之和
if(!rank){
for(i=N/(size-);i<N+N/(size-);i++)
in_cluster[i-N/(size-)]=all_in_cluster[i]; //处理收集的标记数组
temp1=0.0;
for(i=;i<K;i++) temp1+=global_sum_diff[i];
printf("The difference between data and center is: %.2f\n\n", temp1);
count++;
}
MPI_Bcast(&temp1,,MPI_FLOAT,,MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD); do{ //比较前后两次迭代,若不相等继续迭代
temp1=temp2;
if(!rank) getCenter(K,D,N,in_cluster,data,cluster_center); //更新中心点
for(i=;i<K;i++) MPI_Bcast(cluster_center[i],D,MPI_FLOAT,,MPI_COMM_WORLD); //广播中心点
if(rank){
cluster(N/(size-),K,D,data,cluster_center,local_in_cluster); //其他进程进行聚类
for(i=;i<K;i++) sum_diff[i]=0.0;
getDifference(K,N/(size-),D,local_in_cluster,data,cluster_center,sum_diff);
for(i=;i<N/(size-);i++)
printf("data[%d] in cluster-%d\n",(rank-)*(N/(size-))+i,local_in_cluster[i]+);
}
MPI_Gather(local_in_cluster,N/(size-),MPI_INT,all_in_cluster,N/(size-),MPI_INT,,MPI_COMM_WORLD);
if(!rank)
for(i=;i<K;i++) global_sum_diff[i]=0.0;
MPI_Reduce(sum_diff,global_sum_diff,K,MPI_FLOAT,MPI_SUM,,MPI_COMM_WORLD);
if(!rank){
for(i=N/(size-);i<N+N/(size-);i++)
in_cluster[i-N/(size-)]=all_in_cluster[i];
temp2=0.0;
for(i=;i<K;i++) temp2+=global_sum_diff[i];
printf("The difference between data and center is: %.2f\n\n", temp2);
count++;
}
MPI_Bcast(&temp2,,MPI_FLOAT,,MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
}while(fabs(temp2-temp1)!=0.0);
if(!rank) printf("The total number of cluster is: %d\n\n",count);
MPI_Finalize();
} //动态创建二维数组
float **array(int m,int n)
{
int i;
float **p;
p=(float **)malloc(m*sizeof(float *));
p[]=(float *)malloc(m*n*sizeof(float));
for(i=;i<m;i++) p[i]=p[i-]+n;
return p;
} //从data.txt导入数据,要求首行格式:K=聚类数目,D=数据维度,N=数据量
float **loadData(int *k,int *d,int *n)
{
float **array(int m,int n);
int i,j;
float **arraydata;
FILE *fp;
if((fp=fopen("data.txt","r"))==NULL) fprintf(stderr,"cannot open data.txt!\n");
if(fscanf(fp,"K=%d,D=%d,N=%d\n",k,d,n)!=) fprintf(stderr,"load error!\n");
arraydata=array(*n,*d); //生成数据数组
for(i=;i<*n;i++)
for(j=;j<*d;j++)
fscanf(fp,"%f",&arraydata[i][j]); //读取数据点
return arraydata;
} //计算欧几里得距离
float getDistance(float avector[],float bvector[],int n)
{
int i;
float sum=0.0;
for(i=;i<n;i++)
sum+=pow(avector[i]-bvector[i],);
return sqrt(sum);
} //把N个数据点聚类,标出每个点属于哪个聚类
void cluster(int n,int k,int d,float **data,float **cluster_center,int *local_in_cluster)
{
int i,j;
float min;
float **distance=array(n,k); //存放每个数据点到每个中心点的距离
for(i=;i<n;++i){
min=9999.0;
for(j=;j<k;++j){
distance[i][j] = getDistance(data[i],cluster_center[j],d);
if(distance[i][j]<min){
min=distance[i][j];
local_in_cluster[i]=j;
}
}
}
printf("-----------------------------\n");
free(distance);
} //计算所有聚类的中心点与其数据点的距离之和
float getDifference(int k,int n,int d,int *in_cluster,float **data,float **cluster_center,float *sum)
{
int i,j;
for(i=;i<k;++i)
for(j=;j<n;++j)
if(i==in_cluster[j])
sum[i]+=getDistance(data[j],cluster_center[i],d);
} //计算每个聚类的中心点
void getCenter(int k,int d,int n,int *in_cluster,float **data,float **cluster_center)
{
float **sum=array(k,d); //存放每个聚类中心
int i,j,q,count;
for(i=;i<k;i++)
for(j=;j<d;j++)
sum[i][j]=0.0;
for(i=;i<k;i++){
count=; //统计属于某个聚类内的所有数据点
for(j=;j<n;j++){
if(i==in_cluster[j]){
for(q=;q<d;q++)
sum[i][q]+=data[j][q]; //计算所属聚类的所有数据点的相应维数之和
count++;
}
}
for(q=;q<d;q++)
cluster_center[i][q]=sum[i][q]/count;
}
printf("The new center of cluster is:\n");
for(i = ; i < k; i++)
for(q=;q<d;q++){
printf("%-8.2f",cluster_center[i][q]);
if((q+)%d==) putchar('\n');
}
free(sum);
}

  

 //生成测试数据
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 1000 int main()
{
int i;
float a;
int k,d,n;
FILE *fp;
fprintf(stdout,"input(k d n):");
scanf("%d%d%d",&k,&d,&n);
if((fp=fopen("data.txt","w"))==NULL) exit();
fprintf(fp,"K=%d,D=%d,N=%d\n",k,d,n);
srand((unsigned int)(time(NULL)));
for(i=;i<=d*n;i++){
a=(int)(1.0+(double)N*rand()/(RAND_MAX+1.0));
fprintf(fp,"%.2f ",a);
if(i%d==) putc('\n',fp);
}
if(fclose(fp)) exit();
}

  实验:

  聚类数K=10,数据的维度D=2,单位(秒):

数据量N

10000

100000

500000

串行

1

21

109

并行(2个进程)

2

25

101

并行(3个进程)

3

26

101

  

  分析:电脑配置是奔腾双核,按照该并行程序,一个核心用作主节点以分配数据集,另一个核心作为承担了大多数计算任务的节点。当数据量较小时,并行程序花在进程间数据通信的时间占了总体时间的很大比重,所以并行程序耗时要多于串行程序。在本电脑CPU为两个核心的环境下,当数据量较大时,并行程序与串行程序耗时相当或者稍微偏小。在CPU核心数在3个以上时,该并行程序的优势才突显出来。

kmeans算法并行化的mpi程序的更多相关文章

  1. K-means算法的matlab程序

    K-means算法的matlab程序 在“K-means算法的matlab程序(初步)”这篇文章中已经用matlab程序对iris数据库进行简单的实现,下面的程序最终的目的是求准确度. 作者:凯鲁嘎吉 ...

  2. K-means算法的matlab程序(初步)

    K-means算法的matlab程序 在https://www.cnblogs.com/kailugaji/p/9648369.html 文章中已经介绍了K-means算法,现在用matlab程序实现 ...

  3. kmeans算法c语言实现,能对不同维度的数据进行聚类

    最近在苦于思考kmeans算法的MPI并行化,花了两天的时间把该算法看懂和实现了串行版. 聚类问题就是给定一个元素集合V,其中每个元素具有d个可观察属性,使用某种算法将V划分成k个子集,要求每个子集内 ...

  4. 【原创】数据挖掘案例——ReliefF和K-means算法的医学应用

    数据挖掘方法的提出,让人们有能力最终认识数据的真正价值,即蕴藏在数据中的信息和知识.数据挖掘 (DataMiriing),指的是从大型数据库或数据仓库中提取人们感兴趣的知识,这些知识是隐含的.事先未知 ...

  5. 利用Mahout实现在Hadoop上运行K-Means算法

    利用Mahout实现在Hadoop上运行K-Means算法 一.介绍Mahout Mahout是Apache下的开源机器学习软件包,目前实现的机器学习算法主要包含有协同过滤/推荐引擎,聚类和分类三个部 ...

  6. 数据挖掘十大经典算法[0]-K-Means算法

    K-Means算法的输入N,K和一个size为N的向量组vector.输出K个两两互不相交的向量组.其本质是将给定的向量组划分成K个类别,使得同类别的向量相似度比较大,而不同类别的向量之间的相似度较小 ...

  7. 转载: scikit-learn学习之K-means聚类算法与 Mini Batch K-Means算法

    版权声明:<—— 本文为作者呕心沥血打造,若要转载,请注明出处@http://blog.csdn.net/gamer_gyt <—— 目录(?)[+] ================== ...

  8. hadoop在实现kmeans算法——一个mapreduce实施

    写mapreduce程序实现kmeans算法.我们的想法可能是 1. 次迭代后的质心 2. map里.计算每一个质心与样本之间的距离,得到与样本距离最短的质心,以这个质心作为key,样本作为value ...

  9. 基于ReliefF和K-means算法的医学应用实例

    基于ReliefF和K-means算法的医学应用实例 数据挖掘方法的提出,让人们有能力最终认识数据的真正价值,即蕴藏在数据中的信息和知识.数据挖掘 (DataMiriing),指的是从大型数据库或数据 ...

随机推荐

  1. iOS 地图定位及大头针的基本使用

    地图 Part1 - 定位及大头针的基本使用 一.MapKit 作用 : 用于地图展示 如大头针,路线,覆盖层展示等(着重界面展示) 使用步骤 导入头文件 #import <MapKit/Map ...

  2. Atitit 图像处理类库大总结attilax qc20

    Atitit 图像处理类库大总结attilax qc20 1.1. 选择与组合不同的图像处理类库1 1.2. Halcon 貌似商业工具,功能强大.1 1.3. Openvc  Openvc功能也是比 ...

  3. Failure to find xxx in xxx was cached in the local repository, resolution will not be reattempted until the update interval of nexus has elapsed or updates are forced @ xxx

    问题: 在linux服务器上使用maven编译war时报错: 16:41:35 [FATAL] Non-resolvable parent POM for ***: Failure to find * ...

  4. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  5. 解析大型.NET ERP系统 查找与钻取

    查找 Lookup 窗体是一个容器,也可以把TextBox,Button也看成是一个容器,可以往容器里面添加按钮. 参考下面的实现代码,给TextBox增加查找按钮. var btn = new Bu ...

  6. Android中的复制粘贴

    Android中的复制粘贴 The Clipboard Framework 当使用clipboard framework时,把数据放在一个剪切对象(clip object)里,然后这个对象会放在系统的 ...

  7. mssql 字增自段怎样重置(重新自增)|清空表已有数据

    方法1 -- 清空已有数据,并且将自增自段恢复从1开始计数 truncate table 表名 方法2 -- 不清空已有数据,但将自增自段恢复从1开始计数 dbcc checkident(表名,RES ...

  8. 使用Beautiful Soup编写一个爬虫 系列随笔汇总

    这几篇博文只是为了记录学习Beautiful Soup的过程,不仅方便自己以后查看,也许能帮到同样在学习这个技术的朋友.通过学习Beautiful Soup基础知识 完成了一个简单的爬虫服务:从all ...

  9. Sqlserver调用api

    虽然使用sqlserver去调用服务接口的情况比较少,但也可以去了解下对应的使用情况 一.首先要开启组件的配置 sp_configure ; GO RECONFIGURE; GO sp_configu ...

  10. IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习保护API

    IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习之保护API. 使用IdentityServer4 来实现使用客户端凭据保护ASP.N ...