完全照抄公式實現,沒什么好講的,有意的大家可以看: 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);
}