几种聚类算法的结合运用(K-MEANS、 K-medoids、 最大最小距离算法)
聚类算法通常会得到一种分类,将n个点聚合成k类,同一聚类(即插槽簇)中的对象相似度较高;而不同类中的对象相似度较小。
聚类算法的基本流程如下:
(1)从n个节点中选择 k 个节点作为初始聚类中心。(2)将剩余节点根据它们与这k个聚类中心的代价大小,分别将它们分配给与其代价最小的(聚类中心所代表的)聚类。(3)更新聚类的聚类中心。不断重复(2)(3)这一过程将剩下其它节点分配完毕。(4)排序,将各聚类按照聚类间节点代价和高低降序排列。
下面详细解释上述步骤。
(1)从n个节点中选择 k 个节点作为初始聚类中心
由于K-MEANS算法(一种典型的聚类算法,随机确定k个聚类中心)有缺点:产生类的大小相差不会很大,对于脏数据很敏感。所以采用最大最小距离算法确定这k个聚类中心。最大最小距离算法是识别领域中的一种试探性算法。思想是取尽可能离得远的对象作为聚类中心,以避免聚类中心过于邻近。
步骤如下:
1.计算各节点到其他节点的最大代价总和,取满足最大的点i(可理解为距其他节点最远)为聚类1的中心点。
2.计算其他节点到点的最大代价,取满足最大的i点为聚类2的中心点。
3. 计算其他节点到、点的最大代价,取满足最大的i点为聚类3的中心点。
4. 计算其他节点到、、点的最大代价,取满足最大的i点为聚类4的中心点。
以此类推直到找到k个聚类中心点。
(2)将剩余节点根据它们与这些聚类中心的代价大小,分别将它们分配给与其代价最小的(聚类中心所代表的)聚类
依次将不是聚类中心点的节点分配到k个聚类中去。若某类中已经有两个节点,则在分配进入该节点之后还要进行更新聚类中心点的操作(见后(3)详解)。
(3)更新聚类的聚类中心
当某个聚类中存在3个或3个以上节点时需要更新此聚类中心点。采用K-medoids算法中的更新聚类中心方式。在 K-medoids算法中,我们将从当前聚类中选取这样一个点——它到其他所有(当前聚类中)点的代价之和最小——作为中心点。
(4)排序,将各聚类按照聚类间代价高低降序排列。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <math.h>
#include "CLSlotClustering.h"
#include "CLZone.h"
#include "CLVMMinKCut.h"
using namespace std;
CLSlotClustering::CLSlotClustering()
{
}
CLSlotClustering::~CLSlotClustering()
{
}
int CLSlotClustering::Find(int i)
{
int j;
if (m_Parent[i]==i)
{
return i;
}
j=m_Parent[i];
Find(j);
return 0;
}
CLZone CLSlotClustering::SlotClustering(int C[][MAXNUMBER],int n,int k,int flag)
{
m_VexOfMaxCost=0; //初始化
m_Flag=0;
m_Number=(-1);
for (int i = 0; i < MAXNUMBER; i++)
{
m_Parent[i]=i;
m_VexOfCostSum[i]=0;
for (int j = 0; j < MAXNUMBER; j++)
{
m_C[i][j]=0;
}
}
m_k=k;
m_n=n;
//cout<<"m_C:"<<endl;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
m_C[i][j]=C[i][j]; //读入代价矩阵
//cout<<m_C[i][j]<<"\t";
}
//cout<<"\n";
}
//Sleep(3000);
FindCenter();
if (!flag)
{
Clusting();
}
Sort();
return **m_MyZone;
}
int CLSlotClustering::FindCenter() //找k个聚合类的中心点
{
for (int i = 0; i < m_n; i++)
{
for (int j = 0; j < m_n; j++)
{
m_VexOfCostSum[i]+=m_C[i][j];
}
if (m_VexOfCostSum[i]>m_Flag)
{
m_VexOfMaxCost=i;
m_Flag=m_VexOfCostSum[i];
}
}
m_MyZone[0]= new CLZone;
m_MyZone[0]->m_Center=m_VexOfMaxCost; //第一个中心点
m_MyZone[0]->m_Size=1;
m_MyZone[0]->m_Member[0]=m_MyZone[0]->m_Center;
m_Flag=0;
m_VexOfMaxCost=0;
for (int l = 1; l < m_k; l++) //找其余中心点
{
for (int k = 0; k < m_n; k++)
{
if (l>1)
{
if (l==2)
{
m_Cost[k]=m_C[m_MyZone[0]->m_Center][k];
}
m_Cost[k]=min(m_C[m_MyZone[l-1]->m_Center][k],m_Cost[k]); //min(Dl(l-1),Dl(l-2))
if (m_Flag<m_Cost[k]) //max(min(Dl(l-1),Dl(l-2)))
{
m_Flag=m_Cost[k];
m_VexOfMaxCost=k;
}
}
else //第二个节点,只需要maxDl1,不需要min(Dl1,Dl2)
{
if (m_Flag<m_C[m_MyZone[0]->m_Center][k])
{
m_Flag=m_C[m_MyZone[0]->m_Center][k];
m_VexOfMaxCost=k;
}
}
}
m_MyZone[l]=new CLZone;
m_MyZone[l]->m_Center=m_VexOfMaxCost; //各类中心点
m_MyZone[l]->m_Size=1;
m_MyZone[l]->m_Member[0]=m_MyZone[l]->m_Center;
m_Flag=0;
}
return 0;
}
int CLSlotClustering::Clusting()
{
m_VexOfCostSum[m_n-1]=10000; //临时变量
for (int i = 0; i < m_n; i++)
{
m_Flag=10000;
m_Flag_IsCenter=0;
for (int j = 0; j < m_k; j++)
{
if (i==m_MyZone[j]->m_Member[0]) //验证是否是首个中心点,如果是则不进行聚合操作
{
m_Parent[i]=i;
m_Flag_IsCenter=1;
break;
}
if (m_Flag>m_C[i][m_MyZone[j]->m_Center]&&m_C[i][m_MyZone[j]->m_Center]!=0) //记录i点离某个中心最近
{
m_Flag=m_C[i][m_MyZone[j]->m_Center];
m_Parent[i]=Find(m_MyZone[j]->m_Center);
m_Number=j;
}
}
if (m_Flag_IsCenter==0&&m_Number!=(-1)) //将i点聚合
{
m_MyZone[m_Number]->m_Member[m_MyZone[m_Number]->m_Size]=i;
(m_MyZone[m_Number]->m_Size)++;
if (m_MyZone[m_Number]->m_Size>2) //当某聚合类中数量大于2时需要检验是否要改变聚合类中心
{
for (int k = 0; k < m_MyZone[m_Number]->m_Size; k++)
{
m_VexOfCostSum[k]=0;
for (int l = 0; l < m_MyZone[m_Number]->m_Size; l++)
{
m_VexOfCostSum[k]+=m_C[m_MyZone[m_Number]->m_Member[k]][m_MyZone[m_Number]->m_Member[l]];
}
if (m_VexOfCostSum[k]<m_VexOfCostSum[m_n-1])
{
m_VexOfCostSum[m_n-1]=m_VexOfCostSum[k];
m_MyZone[m_Number]->m_Center=m_MyZone[m_Number]->m_Member[k];
}
}
//cout<<"changed--m_MyZone["<<m_Number<<"]->m_Center:"<<m_MyZone[m_Number]->m_Center<<endl;
}
}
m_Number=(-1);
}
return 0;
}
int CLSlotClustering::Sort()
{
m_Flag=0;
for (int i = 0; i < m_n; i++) //得到各点到其他聚合类的代价和
{
m_VexOfCostSum[i]=0;
for (int j = 0; j < m_n; j++)
{
if (m_Parent[i]==m_Parent[j]) //若i,j为同一个集合,则查看下一个点
{
continue;
}
else
{
m_VexOfCostSum[i]+=m_C[i][j];
}
}
}
m_MyZone[m_k]=new CLZone;
for (int k = 0; k < m_k; k++) //得到各类到其他类的代价和
{
m_MyZone[k]->m_SumOfCost=0;
for (int l = 0; l < m_MyZone[k]->m_Size; l++)
{
m_MyZone[k]->m_SumOfCost+=m_VexOfCostSum[m_MyZone[k]->m_Member[l]];
}
}
for (int i = 0; i < m_k; i++) //各聚合类降序排序
{
for (int j = i+1; j < m_k; j++)
{
if (m_MyZone[i]->m_SumOfCost<m_MyZone[j]->m_SumOfCost)
{
m_MyZone[m_k]=m_MyZone[i];
m_MyZone[i]=m_MyZone[j];
m_MyZone[j]=m_MyZone[m_k];
}
}
}
/*for (int i = 0; i < m_k; i++)
{
cout<<"m_MyZone["<<i<<"]->m_Center:"<<m_MyZone[i]->m_Center<<"\t"<<"m_MyZone["<<i<<"]->Size:"<<m_MyZone[i]->m_Size<<"\t"<<"m_MyZone["<<i<<"]->Member:\n";
for (int j = 0; j < m_MyZone[i]->m_Size; j++)
{
cout<<m_MyZone[i]->m_Member[j]<<"\t";
}
cout<<endl;
}*/
return 0;
}