用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. Android测试网络是否连接

    一.布局页面 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns ...

  2. .Net使用RabbitMQ详解

    序言 这里原来有一句话,触犯啦天条,被阉割!!!! 首先不去讨论我的日志组件怎么样.因为有些日志需要走网络,有的又不需要走网路,也是有性能与业务场景的多般变化在其中,就把他抛开,我们只谈消息Rabbi ...

  3. 【Win 10应用开发】手动调用WCF服务

    调用服务最简单的方法就是,直接在VS里面添加服务引用,输入服务的地址即可,无论是普通Web服务,还是WCF服务均可.VS会根据获取到的元数据,自动生成客户端代码. 如果服务的调用量很大,应用广泛,可以 ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统--任务调度系统解析

    1.任务主界面.任务可以被挂起,启动,和删除.来自著名Quartz扩展 2.任务可以是执行的SQL命令,存储过程,或者是一个后台方法 3.极其复杂的调度任务,循环次数,可以自行设置.并可以间隔执行,比 ...

  5. angular2系列教程(二)模板语法

    今天我们要讲的是angualr2的模板语法,官网写的很清楚,但我也用通俗易懂的讲法再罗列一下吧! 例子

  6. linux内核数据结构之kfifo

    1.前言 最近项目中用到一个环形缓冲区(ring buffer),代码是由linux内核的kfifo改过来的.缓冲区在文件系统中经常用到,通过缓冲区缓解cpu读写内存和读写磁盘的速度.例如一个进程A产 ...

  7. Spark 入门

    Spark 入门 目录 一. 1. 2. 3. 二. 三. 1. 2. 3. (1) (2) (3) 4. 5. 四. 1. 2. 3. 4. 5. 五.         Spark Shell使用 ...

  8. 用JWT来保护我们的ASP.NET Core Web API

    在上一篇博客中,自己动手写了一个Middleware来处理API的授权验证,现在就采用另外一种方式来处理这个授权验证的问题,毕竟现在也 有不少开源的东西可以用,今天用的是JWT. 什么是JWT呢?JW ...

  9. POI读取EXCEL(2007以上)

    import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; im ...

  10. 【视频处理】YUV与RGB格式转换

    YUV格式具有亮度信息和色彩信息分离的特点,但大多数图像处理操作都是基于RGB格式. 因此当要对图像进行后期处理显示时,需要把YUV格式转换成RGB格式. RGB与YUV的变换公式如下: YUV(25 ...