1. 程式人生 > 實用技巧 >C均值聚類

C均值聚類

C均值聚類

演算法步驟

  1. 在樣本集合中選擇C個點作為初始類中心;
  2. 在剩下的樣本點中選擇一個,計算其到各個中心點的距離,選取距離最短者將其歸為那個類別;
  3. 選擇下一個樣本,重複2直到計算完所有樣本,若集合不發生變化或達到迭代上限則轉5否則轉4;
  4. 根據當前的類劃分情況重新計算中心點,重複步驟2;
  5. 結束演算法。

C實現

/*
	@Time : 2020/12/4 0:04
	@Author : Li Canghao
	@Name : C_means.py
	@Software : C-Free
*/
#include<stdio.h>
#include<math.h>
const long long maxn = 10005;
typedef struct twoD{
	double x,y; 
}twoD;
double Distance(twoD a,twoD b){					//計算距離 
	return fabs(sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)));
}
void InitCenters(twoD trains[],int c,twoD centers[]){				//初始化類中心 
	for(int i = 0; i < c; i++){
		centers[i].x = trains[i].x;
		centers[i].y = trains[i].y;
		//printf("%lf %lf\n",centers[i].x,centers[i].y) ;
	}
}
void SearchMinDistance(int index,twoD train,int c,twoD centers[],int belong[],int cnt[]){		//尋找距離最短 
	double mindistance = 1e6;
	int minindex = 0;
	for(int i= 0; i < c; i++){
		if(Distance(train,centers[i])<mindistance){
			mindistance = Distance(train,centers[i]);
			minindex = i;
		}
	}
	belong[index] = minindex;											//該模式屬於minindex類 
	cnt[minindex]++;													//該類模式數增加 
	//printf("belong[%d] = %d  cnt[%d] = %d\n",index,minindex,minindex,cnt[minindex]);
} 

void C_mean(int n,twoD trains[],int c){			//C均值主程式 
	twoD centers[maxn];							//存放類心 
	twoD avg[c];								//用於計算類心 
	int belong[n];								//儲存集合關係 
	int cnt[c];									//儲存一個類有多少模式 
	int counts = 0;								//判斷集合是否不再變化 
	InitCenters(trains,c,centers);
	while(counts < c){
		for(int i = 0; i < c; i++)cnt[i] = 0; 
		for(int i = 0; i < n; i++){				//每一模式與類心距離按照最小距離歸類 
			SearchMinDistance(i,trains[i],c,centers,belong,cnt);
		} 
		for(int i = 0; i < c; i++){				//為計算新的類心初始化 
			avg[i].x = 0;
			avg[i].y = 0;
		}
		for(int i = 0; i < n; i++){				//準備計算每一類的類心 
			avg[belong[i]].x += trains[i].x;
			avg[belong[i]].y += trains[i].y;
		}
		counts = 0;
		for(int i = 0;i < c; i++){
			avg[i].x /= cnt[i];					//計算類心 
			avg[i].y /= cnt[i];
			if(((centers[i].x-avg[i].x)<1e-6)&&((centers[i].y-avg[i].y)<1e-6)){	//如果新的類心與原類心差距十分小,就認為沒有更新 
				counts++;
			}
			//printf("count = %d\n",counts);
			centers[i].x = avg[i].x;			//更新類心 
			centers[i].y = avg[i].y;
		}
		
	}
	printf("\n-----處理完畢,展示結果-----\n");
	for(int i = 0; i < c; i++){
		printf("當前第%d類,聚類中心為:(%lf,%lf) 共有%d個模式,其中的集合為:\n",i+1,centers[i].x,centers[i].y,cnt[i]); 
		for(int j = 0; j < n; j++){
			if(belong[j] == i)printf("\t%d:(%lf,%lf)\n",j+1,trains[j].x,trains[j].y);
		}
	}
} 
int main(){										//測試 
	twoD trains[maxn];
	int n,c;
	printf("請輸入需要分成多少類:");
	scanf("%d",&c);
	printf("請輸入模式總個數:(n > c)");
	scanf("%d",&n);
	printf("請輸入各模式的特徵值(二維):\n");
	for(int i = 0; i < n; i++){
		scanf("%lf%lf",&trains[i].x,&trains[i].y);
	}
	printf("-----開始C均值聚類-----\n");
	C_mean(n,trains,c);
	printf("-----C均值聚類結束-----\n");
	return 0;
}



測試資料 少量樣本
1 2
4 5
7 3
100 20
90 50
-5 6
50 89
2000 414
2000 808
2020 124