php fuzzy,模糊C均值聚类算法(Fuzzy C-means)
模糊c均值聚類與k均值聚類區(qū)別
k均值聚類
k均值聚類的實現(xiàn)中,把每個樣本劃分到單一的類別中,亦即是每個樣本只能屬于一種類別,不能屬于多種類別。這樣的劃分,稱為硬劃分。
模糊c均值均類
為了解決硬劃分所帶來的問題,因此有了稱為軟劃分的聚類算法,這一類算法中,每個樣本不再只能屬于一種類別,而是對于每個樣本,都有對應(yīng)的隸屬度數(shù)組,數(shù)組里的每一個元素代表該樣本屬于某種類別的程度。而該樣本的隸屬度數(shù)組中的總值等于1。
其目標方程以及優(yōu)化的推導(dǎo)過程可以參照下述鏈接,個人認為推導(dǎo)過程十分詳細。
模糊c均值聚類推導(dǎo)
實現(xiàn)步驟:
根據(jù)相關(guān)的推導(dǎo)結(jié)果,具體實現(xiàn)步驟如下:
初始化數(shù)據(jù)集
初始化隸屬度數(shù)組
根據(jù)隸屬度數(shù)組更新聚類中心
根據(jù)聚類中心更新隸屬度數(shù)組
是否達到結(jié)束條件,沒有達到則重復(fù)2-4步驟。
實現(xiàn)
各個相關(guān)函數(shù)都有注釋。
#include
#include
#include
#include
typedef struct{
double x;
double y;
} Position;
//隨機生成二維數(shù)據(jù)點
//len:節(jié)點數(shù)量
//range:節(jié)點x、y值的范圍
Position *randomPosition(int len, int range){
srand((unsigned)time(NULL));
Position *allPos = (Position *)malloc(len * sizeof(Position));
short a = 1; //人為差異量
for (int i = 0; i < len; ++i)
{
if (a)
{
allPos[i].x = (double)rand() / 2147483647 * range;
allPos[i].y = (double)rand() / 2147483647 * range;
a = 0;
}
else if (!a)
{
allPos[i].x = (double)rand() / 2147483647 * range+50;
allPos[i].y = (double)rand() / 2147483647 * range+50;
a = 1;
}
}
return allPos;
}
//fcm初始化:隸屬度矩陣
//posNum:節(jié)點數(shù)量
//clusterNum:聚類中心數(shù)量
double **init(int posNum, int clusterNum){
double **u = (double **)malloc(sizeof(double *) * clusterNum);
for (int i = 0; i
{
u[i] = (double *)malloc(sizeof(double) * posNum);
}
srand((unsigned)time(NULL));
double sum;
//初始化u:sigmaU[i]=1
for (int i = 0; i < posNum; ++i)
{
sum=1;
for (int x = 0; x < clusterNum - 1; ++x)
{
u[x][i] = ((double)rand() / 2147483647) * sum;
sum -= u[x][i];
printf("u[%d][%d]:%f ",x,i,u[x][i]);
}
u[clusterNum-1][i]=sum;
printf("u[%d][%d]:%f\n",clusterNum-1,i,u[clusterNum-1][i]);
}
return u;
}
//輸出所有數(shù)據(jù)點
//allPos:節(jié)點數(shù)組
//len:節(jié)點數(shù)量
void outputPos(Position *allPos, int len){
for (int i = 0; i < len; ++i)
printf("position %d:(%f,%f)\n", i, allPos[i].x, allPos[i].y);
return;
}
//所有隸屬于聚類中心i的點的隸屬程度和
//u:隸屬度矩陣
//posNum:節(jié)點數(shù)量
//i:第i個聚類中心
//m:隸屬度因子
double sumUi(double** u,int posNum,int i,int m){
double res=0;
for(int x=0;x
res+=pow(u[i][x],m);
return res;
}
//所有隸屬于聚類中心i的點的x坐標的和
//u:隸屬度矩陣
//allPos:節(jié)點數(shù)組
//posNum:節(jié)點數(shù)量
//i:第i個聚類中心
//m:隸屬度因子
double sumXi(double** u,Position* allPos,int posNum,int i,int m){
double res=0;
for(int x=0;x
res+=allPos[x].x*pow(u[i][x],m);
return res;
}
//所有隸屬于聚類中心i的點的y坐標的和
//u:隸屬度矩陣
//posNum:節(jié)點數(shù)量
//i:第i個聚類中心
//m:隸屬度因子
double sumYi(double** u,Position* allPos,int posNum,int i,int m){
double res=0;
for(int x=0;x
res+=allPos[x].y*pow(u[i][x],m);
return res;
}
//第j個節(jié)點到所有聚類中心距離總和
//pos:第j個節(jié)點
//cluster:聚類中心數(shù)組
//clusterNum:聚類中心數(shù)量
//m:隸屬度因子
double sumDis(Position pos,Position* cluster,int clusterNum,int m){
double res=0;
for(int i=0;i
res+=(double)1/pow(pow(pos.x-cluster[i].x,2)+pow(pos.y-cluster[i].y,2),(double)1/(m-1));
return res;
}
//更新聚類中心
//allPos:節(jié)點數(shù)組
//cluster:聚類中心數(shù)組
//u:隸屬度矩陣
//posNum:節(jié)點數(shù)量
//clusterNum:聚類中心數(shù)量
//m:隸屬度因子
void updateCluster(Position* allPos,Position* cluster,double** u,int posNum,int clusterNum,int m){
for(int i=0;i
cluster[i].x=sumXi(u,allPos,posNum,i,m)/sumUi(u,posNum,i,m);
cluster[i].y=sumYi(u,allPos,posNum,i,m)/sumUi(u,posNum,i,m);
}
}
//更新隸屬度矩陣
//allPos:節(jié)點數(shù)組
//cluster:聚類中心數(shù)組
//u:隸屬度矩陣
//posNum:節(jié)點數(shù)量
//clusterNum:聚類中心數(shù)量
//m:隸屬度因子
void updateU(Position* allPos,Position* cluster,double** u,int posNum,int clusterNum,int m){
double disXI;
for(int i=0;i
for(int x=0;x
disXI=pow(pow(allPos[x].x-cluster[i].x,2)+pow(allPos[x].y-cluster[i].y,2),(double)1/(m-1));
u[i][x]=(double)1/(disXI*sumDis(allPos[x],cluster,clusterNum,m));
}
}
//輸出目標函數(shù)
//allPos:節(jié)點數(shù)組
//cluster:聚類中心數(shù)組
//u:隸屬度矩陣
//posNum:節(jié)點數(shù)量
//clusterNum:聚類中心數(shù)量
//m:隸屬度因子
void outpuCost_fun(Position* allPos,Position* cluster,double** u,int posNum,int clusterNum,int m){
double res=0;
for(int i=0;i
for(int x=0;x
res+=(pow(u[i][x],m)*(pow(allPos[x].x-cluster[i].x,2)+pow(allPos[x].y-cluster[i].y,2)));
printf("costFun:%f\n",res);
}
//..略,同上
void outputU(double** u,int posNum,int clusterNum){
for(int i=0;i
for(int x=0;x
printf("u[%d][%d]:%f ",x,i,u[x][i]);
printf("\n");
}
}
void fuzzy_Cmeans(int posNum,int clusterNum, int m, int iterTime,int range)
{
Position* allPos=randomPosition(posNum,range);
Position* cluster=(Position*)malloc(sizeof(Position)*clusterNum);
double** u=init(posNum,clusterNum);
for (int i = 0; i < iterTime; ++i)
{
updateCluster(allPos,cluster,u,posNum,clusterNum,m);
updateU(allPos,cluster,u,posNum,clusterNum,m);
outpuCost_fun(allPos,cluster,u,posNum,clusterNum,m);
//outputU(u,posNum,clusterNum);
}
}
int main(){
fuzzy_Cmeans(100,10,3,500,500);
return 0;
}
結(jié)果
可以看到,其目標函數(shù)的值是逐漸減少的,最后達到穩(wěn)定的狀態(tài)。
總結(jié)
以上是生活随笔為你收集整理的php fuzzy,模糊C均值聚类算法(Fuzzy C-means)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单片机8×8点阵显示简单汉字的程序_干货
- 下一篇: 解释型语言和编译型语言的区别_从泛型的使