模式識別 之 模糊C均值聚類算法


完全照抄公式實現,沒什么好講的,有意的大家可以看: http://wenku.baidu.com/view/ee968c00eff9aef8941e06a2.html

下面是代碼:

 

不知道為什么,在分類數,較多時候,容易出錯!  

據論文上講,算法的性能依賴於初始聚類中心。 所以下面這個算法,最好是,半交互,先指定聚類中心! 

 


void get_class_mohu_c_junzhi_julei(yangben_t*pYanBeng, int yangbengNum, yangben_t* pCentre,int classNum,double stopThreshold, double m)
{
assert(yangbengNum > classNum);
assert(classNum>=2);
assert(classNum<=20);
assert(stopThreshold>0.00000001);


//特征數量
int teZhengNum = pYanBeng[0].iTeZhengNum;


CString strLog;

//原始數據
// for (int n=0; n<yangbengNum; n++)
// {
// for (int i=0; i<teZhengNum; i++)
// {
// pYanBeng[n].pTeZheng[i];
// CString tmp;
// tmp.Format(" %7.3f ", pYanBeng[n].pTeZheng[i]);
// strLog += tmp;
// }
//
// strLog += "\n\r";
// }


////// 數據預處理 -- 歸一化

yangben_t minYanBeng;
yangben_t maxYanBeng;

{
// 1. 取出最大最小值
for (int i=0; i<teZhengNum; i++)
{
double minVal = pYanBeng[0].pTeZheng[i];
double maxVal = pYanBeng[0].pTeZheng[i];

for (int n=1; n<yangbengNum; n++)
{
if (pYanBeng[n].pTeZheng[i] < minVal)
{
minVal = pYanBeng[n].pTeZheng[i];
}
if (pYanBeng[n].pTeZheng[i] > maxVal)
{
maxVal = pYanBeng[n].pTeZheng[i];
}
}
minYanBeng.pTeZheng[i] = minVal;
maxYanBeng.pTeZheng[i] = maxVal;
}


// 2. 歸一化
for (int n=0; n<yangbengNum; n++)
{
for (int i=0; i<teZhengNum; i++)
{
pYanBeng[n].pTeZheng[i] = (pYanBeng[n].pTeZheng[i] - minYanBeng.pTeZheng[i])/(maxYanBeng.pTeZheng[i] - minYanBeng.pTeZheng[i]);
}
}


}

 

//歸一化的逆運算
// for (int n=0; n<yangbengNum; n++)
// {
// for (int t=0; t<teZhengNum; t++)
// {
// pYanBeng[n].pTeZheng[t] = pYanBeng[n].pTeZheng[t] * (maxYanBeng.pTeZheng[t] - minYanBeng.pTeZheng[t]) + minYanBeng.pTeZheng[t];
// }
// }


// 歸一化后的數據
strLog += "\n\r";
strLog += "歸一化數據\n\r";
for (int n=0; n<yangbengNum; n++)
{
for (int i=0; i<teZhengNum; i++)
{
pYanBeng[n].pTeZheng[i];
CString tmp;
tmp.Format(" %7.5f ", pYanBeng[n].pTeZheng[i]);
strLog += tmp;
}

strLog += "\n\r";
}

 


//聚類中心
yangben_t*pJuLeiCent = pCentre;

//指定任意,聚類初始中心
time_t t;
time(&t);
srand(t);

// 隨機聚類中心
for (int i = 0; i<classNum; i++)
{
int index = rand()%yangbengNum;

pJuLeiCent[i].iTeZhengNum = pYanBeng[index].iTeZhengNum;
for (int k=0; k<pYanBeng[index].iTeZhengNum; k++)
{
pJuLeiCent[i].pTeZheng[k] = pYanBeng[index].pTeZheng[k];
}

}

 

 

 

// 申請隸屬矩陣
double *pLiShu = new double[yangbengNum * classNum];
if (pLiShu == NULL) return;


// 樣本到各聚類中心的距離
double *pJuLi = new double[yangbengNum * classNum];
if (pJuLi == NULL) return;


double newSize = 10.0;
double oldSize = 0.0;

int loop = 0;
// 比較價值 -- 如果價值差異過大,則循環
while( abs(newSize - oldSize) > stopThreshold)
//while( loop < 50)
{
loop++;
//存上次計算價值
oldSize = newSize;

// 更新樣本到聚類中心的距離
{
for (int i=0; i<yangbengNum; i++)
{
for (int c = 0; c<classNum; c++)
{
pJuLi[i*classNum + c] = get_distance_ou(&pYanBeng[i], &pJuLeiCent[c]);

if (pJuLi[i*classNum + c]<0.000000001)
{
pJuLi[i*classNum + c] = 0.000000001;
}
}
}


strLog += "\n\r";
strLog += "\n\r";
strLog += "距離列表\n\r";

for (int i=0; i<yangbengNum; i++)
{
for (int c = 0; c<classNum; c++)
{
CString tmp;
tmp.Format(" %7.5f ", pJuLi[i*classNum + c]);
strLog += tmp;
}
strLog += "\n\r";
}


}

 

 


{
// 更新隸屬矩陣
for (int i=0; i<yangbengNum; i++)
{
for (int c = 0; c<classNum; c++)
{
double lishu = 0.0;


// 並不是完全隸屬某一類
for (int k = 0; k<classNum; k++)
{
double tmp = 0.0;

tmp = ( pJuLi[i*classNum + c] / pJuLi[i*classNum + k] );

lishu += pow(tmp,2/(m - 1));
}
pLiShu[i*classNum + c] = 1.0 / lishu;


}
}
// 隸屬矩陣不需要做歸一化處理

 

}


// 更新聚類中心
{

for (int c=0; c<classNum; c++)
{
double tmp = 0.0;
double sum0 = 0.0;
yangben_t cenTmp;
for (int i=0; i<yangbengNum; i++)
{
tmp = pLiShu[i*classNum + c];
tmp = pow(tmp,m);
sum0 += tmp;
for (int j=0; j<teZhengNum; j++)
{
cenTmp.pTeZheng[j] += tmp * pYanBeng[i].pTeZheng[j];
}


}

/////////////=-========-------------------
for (int j=0; j<teZhengNum; j++)
{
pJuLeiCent[c].pTeZheng[j] = cenTmp.pTeZheng[j]/sum0;
}


}

strLog = "\n\r";
strLog += "\n\r";
strLog += "隸屬矩陣\n\r";

for (int i=0; i<yangbengNum; i++)
{
CString tmp;
double sum = 0.0;
for (int c = 0; c<classNum; c++)
{
tmp.Format(" %14.8f ", pLiShu[i*classNum + c]);
strLog += tmp;

sum += pLiShu[i*classNum + c];
}
tmp.Format(" %14.8f \n\r", sum);
strLog += tmp;

}


strLog += "\n\r";
strLog += "\n\r";
strLog += "聚類中心\n\r";

for (int c=0; c<classNum; c++)
{
for (int i=0; i<teZhengNum; i++)
{
CString tmp;
tmp.Format(" %7.5f ", pJuLeiCent[c].pTeZheng[i]);
strLog += tmp;
}

strLog += "\n\r";
}
//AfxMessageBox(strLog);


}

// 更新價值
{
newSize = 0.0;
for (int c=0; c<classNum; c++)
{
for (int i=0; i<yangbengNum; i++)
{
double tmpLiShu = 0.0;
double tmpJuLi = 0.0;

tmpLiShu = pLiShu[i*classNum + c];
tmpJuLi = pJuLi[i*classNum + c];
newSize += pow(tmpLiShu,m) * tmpJuLi * tmpJuLi;
}
}
}

//break;
}


delete [] pJuLi;
delete [] pLiShu;

 


// 把聚類中心--做歸一化的逆運算
for (int c=0; c<classNum; c++)
{
for (int t = 0; t<teZhengNum; t++)
{
pCentre[c].pTeZheng[t] = pCentre[c].pTeZheng[t] * (maxYanBeng.pTeZheng[t] - minYanBeng.pTeZheng[t]) + minYanBeng.pTeZheng[t];
}
}


strLog = "\n\r";
strLog += "\n\r";
strLog += "聚類中心\n\r";

for (int c=0; c<classNum; c++)
{
for (int i=0; i<teZhengNum; i++)
{
CString tmp;
tmp.Format(" %7.5f ", pJuLeiCent[c].pTeZheng[i]);
strLog += tmp;
}

strLog += "\n\r";
}

//AfxMessageBox(strLog);

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM