几种聚类算法的结合运用(K-MEANS K-medoids 最大最小距离算法)

几种聚类算法的结合运用(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;
}
点赞