用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. 关于百度编辑器UEditor的一点说明

    大家在使用的时候要特别注意editor_config.js中的“URL”这个参数 我的理解:1.这个参数是editor整个结构的总路径          2.首先要把这个路径配置好了.才能正常的显示, ...

  2. JSP页面跳转的几种实现方法

    使用href超链接标记      客户端跳转 使用JavaScript               客户端跳转 提交表单                        客户端跳转 使用response ...

  3. for循环与for in,$('').each 与$.each的区别

    一:for循环与for in的区别 for...in 语句用于对数组或者对象的属性进行循环操作. 语法: for (变量 in 对象){    在此执行代码} for循环是对数组的元素进行循环,而不能 ...

  4. c 进程间的通信

    在上篇讲解了如何创建和调用进程 c 进程和系统调用 这篇文章就专门讲讲进程通信的问题 先来看一段下边的代码,这段代码的作用是根据关键字调用一个Python程序来检索RSS源,然后打开那个URL #in ...

  5. 连接SQLServer时,因启用连接池导致孤立事务的原因分析和解决办法

    本文出处:http://www.cnblogs.com/wy123/p/6110349.html 之前遇到过这么一种情况: 连接数据库的部分Session会出现不定时的阻塞,这种阻塞时长时短,有时候持 ...

  6. Restful Api 最佳实践

    Web APIs has become an very important topic in the last year. We at M-Way Solutions are working ever ...

  7. ASP.NET MVC5学习笔记01

    由于之前在项目中也使用MVC进行开发,但是具体是那个版本就不是很清楚了,但是我觉得大体的思想是相同的,只是版本高的在版本低的基础上增加了一些更加方便操作的东西.下面是我学习ASP.NET MVC5高级 ...

  8. 【转载】保哥 釐清 CLR、.NET、C#、Visual Studio、ASP.NET 各版本之間的關係

    我常常不仅仅逛 博客园,还会去找国外,特别是台湾的技术部落格,发现好的文章,我便会收录,今天我转载或者全文复制,在Google 博客园,一位叫保哥, 釐清 CLR..NET.C#.Visual Stu ...

  9. 周末惊魂:因struts2 016 017 019漏洞被入侵,修复。

    入侵(暴风雨前的宁静) 下午阳光甚好,想趁着安静的周末静下心来写写代码.刚过一个小时,3点左右,客服MM找我,告知客户都在说平台登录不了(我们有专门的客户qq群).看了下数据库连接数,正常.登录阿里云 ...

  10. Java设计模式——线程安全的单件模式

    单件模式,也称单例模式,用以创建独一无二的.只能有一个实例的对象. 单件模式的类图是所有模式的类图中最简单的--只有一个类.尽管从类设计的视角来看单件模式很简单,但是实现上还是会遇到一些问题,本文着重 ...