简单的K-means算法C语言实现代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<math.h>

#define DIMENSIOM 	2		//目前只是处理2维的数据
#define MAX_ROUND_TIME	100		//最大的聚类次数

typedef struct Item{
	int dimension_1;		//用于存放第一维的数据
	int dimension_2;		//用于存放第二维的数据
	int clusterID;			//用于存放该item的cluster center是谁
}Item;
Item* data;

typedef struct ClusterCenter{
	double dimension_1;
	double dimension_2;
	int clusterID;
}ClusterCenter;
ClusterCenter* cluster_center_new;

int isContinue;

int* cluster_center;		//记录center
double* distanceFromCenter;	//记录一个“点”到所有center的距离
int data_size;
char filename[200];
int cluster_count;

void initial();
void readDataFromFile();
void initial_cluster();
void calculateDistance_ToOneCenter(int itemID, int centerID, int count);
void calculateDistance_ToAllCenter(int itemID);
void partition_forOneItem(int itemID);
void partition_forAllItem_OneCluster(int round);
void calculate_clusterCenter(int round);
void K_means();
void writeClusterDataToFile(int round);
void writeClusterCenterToFile(int round);
void compareNew_OldClusterCenter(double* new_X_Y);
void test_1();

int main(int argc, char* argv[]){
	if( argc != 4 )
	{
		printf("This application need other parameter to run:"
				"\n\t\tthe first is the size of data set,"
				"\n\t\tthe second is the file name that contain data"
				"\n\t\tthe third indicate the cluster_count"
				"\n");
		exit(0);
	}
	srand((unsigned)time(NULL));
	data_size = atoi(argv[1]);
	strcat(filename, argv[2]);
	cluster_count = atoi(argv[3]);

	initial();
	readDataFromFile();
	initial_cluster();
	//test_1();
	//partition_forAllItem_OneCluster();
	//calculate_clusterCenter();
	K_means();
	return 0;
}

/*
 * 对涉及到的二维动态数组根据main函数中传入的参数分配空间
 * */
void initial(){
	data = (Item*)malloc(sizeof(struct Item) * (data_size + 1));
	if( !data )
	{
		printf("malloc error:data!");
		exit(0);
	}
	cluster_center = (int*)malloc(sizeof(int) * (cluster_count + 1));
	if( !cluster_center )
	{
		printf("malloc error:cluster_center!\n");
		exit(0);
	}
	distanceFromCenter = (double*)malloc(sizeof(double) * (cluster_count + 1));
	if( !distanceFromCenter )
	{
		printf("malloc error: distanceFromCenter!\n");
		exit(0);
	}
	cluster_center_new = (ClusterCenter*)malloc(sizeof(struct ClusterCenter) * (cluster_count + 1));
	if( !cluster_center_new )
	{
		printf("malloc cluster center new error!\n");
		exit(0);
	}
}

/*
 * 从文件中读入x和y数据
 * */
void readDataFromFile(){
	FILE* fread;
	if( NULL == (fread = fopen(filename, "r")))
	{
		printf("open file(%s) error!\n", filename);
		exit(0);
	}
	int row;
	for( row = 1; row <= data_size; row++ )
	{
		if( 2 != fscanf(fread, "%d %d ", &data[row].dimension_1, &data[row].dimension_2))
		{
			printf("fscanf error: %d\n", row);
		}
		data[row].clusterID = 0;
	}

	//test
	/*
	for( row = 1; row <= data_size; row++ )
	{
		printf("%d\t%d\t%d\n", data[row].dimension_1, data[row].dimension_2, data[row].clusterID);
	}
	*/
	//test END
}

/*
 * 根据从主函数中传入的@cluster_count(聚类的个数)来随机的选择@cluster_count个
 * 初始的聚类的起点
 * */

void initial_cluster(){
	//辅助产生不重复的数
	int* auxiliary;
	int i;
	auxiliary = (int*)malloc(sizeof(int) * (data_size + 1));
	if( !auxiliary )
	{
		printf("malloc error: auxiliary");
		exit(0);
	}
	for( i = 1; i <= data_size; i++ )
	{
		auxiliary[i] = i;
	}

	//产生初始化的cluster_count个聚类
	int length = data_size;
	int random;
	for( i = 1; i <= cluster_count; i++ )
	{
		random = rand()%length + 1;
		//printf("%d \n", auxiliary[random]);
		//data[auxiliary[random]].clusterID = auxiliary[random];
		cluster_center[i] = auxiliary[random];
		auxiliary[random] = auxiliary[length--];
	}

	//test
	/*
	int row, col;
	printf("\n the cluster center is :\n");
	for( i = 1; i <= cluster_count; i++ )
	{
		printf("%d ", cluster_center[i]);
	}
	printf("\n");
	*/
	//test END

	for( i = 1; i <= cluster_count; i++ )
	{
		cluster_center_new[i].dimension_1 = data[cluster_center[i]].dimension_1;
		cluster_center_new[i].dimension_2 = data[cluster_center[i]].dimension_2;
		cluster_center_new[i].clusterID = i;
		data[cluster_center[i]].clusterID = i;
	}
	/*
	for( row = 1; row <= data_size; row++ )
	{
		printf("%d\t%d\t%d\n", data[row].dimension_1, data[row].dimension_2, data[row].clusterID);
	}
	*/
}

/*
 * 计算一个点(还没有划分到cluster center的点)到一个cluster center的distance
 * 		@itemID:	不属于任何cluster中的点
 * 		@centerID:	center的ID
 * 		@count:		表明在计算的是itemID到第几个@center的distance,并且指明了结果放在distanceFromCenter的第几号元素
 * */
void calculateDistance_ToOneCenter(int itemID,int centerID){
	distanceFromCenter[centerID] = sqrt( (data[itemID].dimension_1-cluster_center_new[centerID].dimension_1)*(double)(data[itemID].dimension_1-cluster_center_new[centerID].dimension_1) + (double)(data[itemID].dimension_2-cluster_center_new[centerID].dimension_2) * (data[itemID].dimension_2-cluster_center_new[centerID].dimension_2) );
}

/*
 * 计算一个点(还没有划分到cluster center的点)到每个cluster center的distance
 * */
void calculateDistance_ToAllCenter(int itemID){
	int i;
	for( i = 1; i <= cluster_count; i++ )
	{
		calculateDistance_ToOneCenter(itemID, i);
	}
	//test
	/*
	printf("calculateDistance_ToAllCenter for item : %d\n", itemID);
	for( i = 1; i <= cluster_count; i++ )
	{
		printf("%f ", distanceFromCenter[i]);
	}
	printf("\n");
	*/
	//testEND
}

void test_1()
{
	calculateDistance_ToAllCenter(3);
	int i;
	for( i = 1; i <= cluster_count; i++ )
	{
		printf("%f ", distanceFromCenter[i]);
	}
}

/*
 * 在得到任一的点(不属于任一cluster的)到每一个cluster center的distance之后,决定它属于哪一个cluster center,即取距离最小的
 * 		函数功能:得到一个item所属的cluster center
 * */
void partition_forOneItem(int itemID){
	//操作对象是 distanceFromCenter和cluster_center
	int i;
	int min_index = 1;
	double min_value = distanceFromCenter[1];
	for( i = 2; i <= cluster_count; i++ )
	{
		if( distanceFromCenter[i] < min_value )
		{
			min_value = distanceFromCenter[i];
			min_index = i;
		}
	}

	data[itemID].clusterID = cluster_center_new[min_index].clusterID;
}

/*
 * 得到所有的item所属于的cluster center ,  在一轮的聚类中
 * */
void partition_forAllItem_OneCluster(int round){				//changed!!!!!!!!!!!!!!!!!!!!!!!!
	int i;
	for( i = 1; i <= data_size; i++ )
	{
		if( data[i].clusterID != 0 )
			continue;
		else
		{
			calculateDistance_ToAllCenter(i);	//计算i到所有center的distance
			partition_forOneItem(i);		//根据distance对i进行partition
		}
	}

	//把聚类得到的数据写入到文件中
	writeClusterDataToFile(round);

	//test
	/*
	int j;
	for( i = 1; i <= data_size; i++ )
	{
		printf("%d\t%d\t%d\n", data[i].dimension_1, data[i].dimension_2, data[i].clusterID);
	}
	*/
	//testEND
}

/*
 * 将聚类得到的数据写入到文件中,每一个类写入一个文件中
 * 		@round: 表明在进行第几轮的cluster,该参数的另一个作用是指定了文件名字中的第一个项.
 * */
void writeClusterDataToFile(int round){
	int i;
	char filename[200];
	FILE** file;
	file = (FILE**)malloc(sizeof(FILE*) * (cluster_count + 1));
	if( !file )
	{
		printf("malloc file error!\n");
		exit(0);
	}
	for( i = 1; i <= cluster_count; i++ )
	{
		sprintf(filename, ".//ClusterProcess//round%d_cluster%d.data", round, i);
		if( NULL == (file[i] = fopen(filename, "w")))
		{
			printf("file open(%s) error!", filename);
			exit(0);
		}
	}

	for( i = 1; i <= data_size; i++ )
	{
		//sprintf(filename, ".//ClusterProcess//round%d_cluster%d.data", round, data[i].clusterID);
		fprintf(file[data[i].clusterID], "%d\t%d\n", data[i].dimension_1, data[i].dimension_2);
	}
	for( i = 1; i <= cluster_count; i++ )
	{
		//sprintf(filename, ".//ClusterProcess//round%d_cluster%d.data", round, i);
		fclose(file[i]);
	}
}

/*
 * 重新计算新的cluster center
 * */
void calculate_clusterCenter(int round){					//changed!!!!!!!!!!!!!!!!!!!!!!
	int i;
	double* new_X_Y;	/*
				   用来计算和保存新的cluster center的值,同样的,0号元素不用。1,2号元素分别用来
				   存放第一个聚类的所有的项的x和y的累加和。3,4号元素分别用来存放第二个聚类的所有
				   的项的x和y的累加和......
				*/
	new_X_Y = (double*)malloc(sizeof(double) * (2 * cluster_count + 1));
	if( !new_X_Y )
	{
		printf("malloc error: new_X_Y!\n");
		exit(0);
	}
	//初始化为0
	for( i = 1; i <= 2*cluster_count; i++ )
		new_X_Y[i] = 0.0;

	//用来统计属于各个cluster的item的个数
	int* counter;
	counter = (int*)malloc(sizeof(int) * (cluster_count + 1));
	if( !counter )
	{
		printf("malloc error: counter\n");
		exit(0);
	}
	//初始化为0
	for( i = 1; i <= cluster_count; i++ )
		counter[i] = 0;

	for( i = 1; i <= data_size; i++ )
	{
		new_X_Y[data[i].clusterID * 2 - 1] += data[i].dimension_1;
		new_X_Y[data[i].clusterID * 2] += data[i].dimension_2;
		counter[data[i].clusterID]++;
	}
	//test
	/*
	for( i = 1; i <= 2 * cluster_count; i++ )
		printf("%f\t", new_X_Y[i]);
	printf("\n");
	for( i = 1; i <= cluster_count; i++ )
		printf("%d\t", counter[i]);
	printf("\n");
	*/
	//testEND

	for( i = 1; i <= cluster_count; i++ )
	{
		new_X_Y[2 * i - 1] = new_X_Y[2 * i - 1] / (double)(counter[i]);
		new_X_Y[2 * i] = new_X_Y[2 * i] / (double)(counter[i]);
	}

	//test
	/*
	printf("new cluster center:\n");
	for( i = 1; i <= 2 * cluster_count; i++ )
		printf("%f\t", new_X_Y[i]);
	printf("\n");
	*/
	//testEND

	//要将cluster center的值保存在文件中,后续作图
	writeClusterCenterToFile(round);

	/*
	 * 在这里比较一下新的和旧的cluster center值的差别。如果是相等的,则停止K-means算法。
	 * */
	compareNew_OldClusterCenter(new_X_Y);

	//将新的cluster center的值放入cluster_center_new
	for( i = 1; i <= cluster_count; i++ )
	{
		cluster_center_new[i].dimension_1 = new_X_Y[2 * i - 1];
		cluster_center_new[i].dimension_2 = new_X_Y[2 * i];
		cluster_center_new[i].clusterID = i;
	}
	free(new_X_Y);
	free(counter);

	//在重新计算了新的cluster center之后,意味着我们要重新来为每一个Item进行聚类,所以data中用于表示聚类ID的clusterID
	//要都重新置为0。
	for( i = 1; i <= data_size; i++ )
	{
		data[i].clusterID = 0;
	}
}

/*
 * 将得到的新的cluster_count个cluster center的值保存在文件中。以便于观察聚类的过程。
 * */
void writeClusterCenterToFile(int round){
	FILE* file;
	int i;
	char filename[200];
	sprintf(filename, ".//ClusterProcess//round%d_clusterCenter.data", round);
	if( NULL == (file = fopen(filename, "w")))
	{
		printf("open file(%s) error!\n", filename);
		exit(0);
	}

	for( i = 1; i <= cluster_count; i++ )
	{
		fprintf(file, "%f\t%f\n", cluster_center_new[i].dimension_1, cluster_center_new[i].dimension_2);
	}

	for( i = 1; i <= cluster_count; i++ )
	{
		fclose(file);
	}
}

/*
 * 比较新旧的cluster center的差异
 * */
void compareNew_OldClusterCenter(double* new_X_Y){
	int i;
	isContinue = 0;				//等于0表示的是不要继续
	for( i = 1; i <= cluster_count; i++ )
	{
		if( new_X_Y[2 * i - 1] != cluster_center_new[i].dimension_1 || new_X_Y[2 * i] != cluster_center_new[i].dimension_2)
		{
			isContinue = 1;		//要继续
			break;
		}
	}
}

/************************************************************************************************
 *					K-means算法						*
 ***********************************************************************************************/
void K_means(){
	int times_cluster;
	for( times_cluster = 1; times_cluster <= MAX_ROUND_TIME; times_cluster++ )
	{
		printf("\n                        times : %d                          \n", times_cluster);
		partition_forAllItem_OneCluster(times_cluster);
		calculate_clusterCenter(times_cluster);
		if( 0 == isContinue )
		{
			break;
			//printf("\n\nthe application can stop!\n\n");
		}
	}
}

时间: 2024-11-08 19:17:25

简单的K-means算法C语言实现代码的相关文章

【转】A* A星 算法 C语言 实现代码

http://blog.csdn.net/shanshanpt/article/details/8977512 关于A*算法,很早就想写点什么,可是貌似天天在忙活着什么,可事实又没有做什么,真是浮躁啊!所以今晚还是来写一下总结吧! A*算法是很经典的只能启发式搜索算法,关于只能搜索算法和一般的搜索算法(例如DFS,BFS之类),在语言描述上的区别,我觉得用<代码大全>中的一句话描述的非常好:“驾驶汽车达到某人家,写成算法是:沿167号高速往南行至Puyallup,从XX出口后往山上开4.5英里

K-means算法

K-means算法很简单,它属于无监督学习算法中的聚类算法中的一种方法吧,利用欧式距离进行聚合啦. 解决的问题如图所示哈:有一堆没有标签的训练样本,并且它们可以潜在地分为K类,我们怎么把它们划分呢?     那我们就用K-means算法进行划分吧. 算法很简单,这么做就可以啦: 第一步:随机初始化每种类别的中心点,u1,u2,u3,--,uk; 第二步:重复以下过程: 然后 ,就没有然后了,就这样子. 太简单, 不解释.

R语言学习笔记—K近邻算法

K近邻算法(KNN)是指一个样本如果在特征空间中的K个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性.即每个样本都可以用它最接近的k个邻居来代表.KNN算法适合分类,也适合回归.KNN算法广泛应用在推荐系统.语义搜索.异常检测. KNN算法分类原理图: 图中绿色的圆点是归属在红色三角还是蓝色方块一类?如果K=5(离绿色圆点最近的5个邻居,虚线圈内),则有3个蓝色方块是绿色圆点的"最近邻居",比例为3/5,因此绿色圆点应当划归到蓝色方块一类:如果

基于sklearn K临近算法 最简单预测 花的种类

因为注释已经很详细了,所以直接上代码: 1 from sklearn.datasets import load_iris 2 from sklearn.model_selection import train_test_split 3 #k临近算法 4 from sklearn.neighbors import KNeighborsClassifier 5 import numpy as np 6 import pandas as pd 7 def get数据(): 8 iris_dataset

从K近邻算法、距离度量谈到KD树、SIFT+BBF算法

从K近邻算法.距离度量谈到KD树.SIFT+BBF算法 从K近邻算法.距离度量谈到KD树.SIFT+BBF算法 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章待写:1.KD树:2.神经网络:3.编程艺术第28章.你看到,blog内的文章与你于别处所见的任何都不同.于是,等啊等,等一台电脑,只好等待..”.得益于田,借了我一台电脑(借他电脑的时候,我连表示感谢,他说“能找到工作全靠你的博客,这点儿小忙还说,不地道”,有的时候,稍许感受到受人信任也是一种压力,愿我不辜负大家对我的信任)

使用K近邻算法实现手写体识别系统

目录 1. 应用介绍 1.1实验环境介绍 1.2应用背景介绍 2. 数据来源及预处理 2.1数据来源及格式 2.2数据预处理 3. 算法设计与实现 3.1手写体识别系统算法实现过程 3.2 K近邻算法实现 3.3手写体识别系统实现 3.4算法改进与优化 4. 系统运行过程与结果展示 1.应用介绍 1.1实验环境介绍 本次实验主要使用Python语言开发完成,Python的版本为2.7,并且使用numpy函数库做一些数值计算和处理. 1.2应用背景介绍 本次实验实现的是简易的手写体识别系统,即根据

RSA算法C语言实现

RSA算法C语言实现 一.源文件三个rsa.h , rsa.c , main.c //rsa.h #include <stdio.h> #define MAX_NUM 63001 #define MAX_PRIME 251 //! 返回代码 #define OK 100 #define ERROR_NOEACHPRIME 101 #define ERROR_NOPUBLICKEY 102 #define ERROR_GENERROR 103 unsigned int MakePrivatedK

常见的简单的无监督学习算法总结

一.聚类(clustering) 1.k-均值聚类(k-means) 这是机器学习领域除了线性回归最简单的算法了.该算法用来对n维空间内的点根据欧式距离远近程度进行分类. INPUT: K(number of clusters) Training set{x1,x2,x3,....xn} (xi belongs to R^n) OUTPUT: K个聚类中心 算法工作原理摘要: 自己手写的python实现K—means: #簇数为k#数据空间维度为n#训练集元素数为mdef K_means_dem

DM里的K均值算法

1.Preface 因为一直在做的是聚类算法的研究,算是总结了一些心得,这里总结些知识性与思路性的东西,我想在其他地方也是很容易的找到类似的内容的.毕竟,世界就是那么小. 声明:本文比较不适合没有DM基础的人来阅读.我只是胡乱的涂鸦而已 2.聚类算法 在DM里的聚类算法里,有基于划分的算法,基于层次的算法,基于密度的算法,基于网格的算法,基于约束的算法. 其中每一种基于的算法都会衍生出一至几种算法,对应的每一种算法不管在学术界还是工业界都存在着许多的改进的算法 这里想介绍的是基于基于划分的算法里