其中将种群中的个体聚类的时候,使用Kmeans聚类,但是初始点的选择会影响最终的结果,我们考虑了初始点的选择(极致化和均匀)另外采取二次Kmeans聚类。
C# 源代码如下:相似度是余弦相似度。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MOEA_PCI
{
public class Kmeans
{
public int K=40;//簇的个数
public int N=200;//数据的个数
List<int>centerindex=new List<int>();//保存质心数组元素下标,质心下标索引集合
public List<List<int>> center = new List<List<int>>();//保存质心数组元素
List<List<int>> centercopy = new List<List<int>>();//保存质心数组元素副本
List<int> top;//保存每个簇中个体下标的个数
public List<List<int>> classter; //保存每个簇中个体下标
public Individual[] population; //种群
public int gsmnum = 0;
//开始聚类
public void ClusterMain(int k ,int n)
{
K = k;
N = n;
#region (1)初始化簇的个数和个体下标数据
top = new List<int>(K);
classter = new List<List<int>>(K);
#endregion
#region (2)初始化簇二维数组
for (int i = 0; i < K; i++)
{
List<int> l = new List<int>();
List<int> l2 = new List<int>();
for (int j = 0; j < N; j++)
{
l.Add(0);
}
classter.Add(l);
for (int j = 0; j < gsmnum; j++)
{
l2.Add(0);
}
center.Add(l2);
}
#endregion
#region (3)初始化质心数组K个元素的下标,
#region 方法1(随机选取质心)
Random num = new Random();
for (int i = 0; i < K; i++)
{
int j = 0;
int temp = num.Next(N);//产生0到N的随机数!
for (j = 0; j < i; j++)
{
if (centerindex[j] == temp)//生成重复数据
{
break;
}
}
if (j >= i)
{
centerindex.Add(temp);
}
else
{
--i; //生成重复,继续重新生成
}
}
#endregion
#endregion
#region (4)初始化质心数组K个元素
//List<int> tempcenter = new List<int>();
for (int i = 0; i < K; ++i)
{
//tempcenter.Clear();
for (int j = 0; j < gsmnum; j++)
{
center[i][j]=population[centerindex[i]].gene[j];
}
}
Copycenter();//拷贝到质心数组副本中去
#endregion
#region (5)进行聚类
bool flag=true;
while (flag)
{
top.Clear();//一定要要清空,不然top的大小会变得比K大
for (int i = 0; i < K; i++)
{
top.Add(0);
}
UpdateClasster();
UpdateCenter();
if (IsEqule(centercopy, center))
{
flag = false;
}
else
{
Copycenter();
}
}
#endregion
#region (6)检测结果
// Console.WriteLine("**********************************聚类开始*******************************");
//for (int i = 0; i < classter.Count; i++)
//{
// Console.WriteLine("********************************第{0}类************************", i + 1);
// for (int j = 0; j < top[i]; j++)
// {
// Console.Write(classter[i][j].ToString() + " ");
// }
// Console.WriteLine();
//}
//按照质心排序,从小到大进行排序
//for (int i = 0; i < K; i++)
//{
// int sum = 0, avg = 0;
// for (int j = 0; j < gsmnum; j++)
// {
// sum += center[i][j];
// }
// avg = sum / gsmnum;
// centersortavg.Add(avg);
//}
//for (int i = 0; i < K; i++)
//{
// int tempindex = i;
// for (int j = i+1; j < K; j++)
// {
// if (centersortavg[i] > centersortavg[j])
// {
// int temp = centersortavg[i];
// centersortavg[i] = centersortavg[j];
// centersortavg[j] = temp;
// tempindex = j;
// }
// }
// centersortindex.Add(tempindex);
//}
#endregion
}
private int disoftwoindividual(int[] a,int[] b)//计算两个个体之间的距离
{
int sum = 0;
for (int k = 0; k < gsmnum; k++)
{
int a1 = a[k];
int b1 = b[k];
sum += Math.Abs(a1- b1) * Math.Abs(a1 - b1);
}
return sum;
}
private void Copycenter()// 复制质心数组
{
int i;
centercopy.Clear();
for (i = 0; i < K; ++i)
{
centercopy.Add(center[i]);
}
}
private void UpdateClasster()// 更新聚类信息,将数据分类
{
int i, index;
for (i = 0; i < N; i++)
{
//index = GetIndexEuclidean(i, center);//得到距离最小的质心下标
index = GetIndex(i, center);//得到距离最小的质心下标
AddClasster(index, i);//添加到相应的聚类中
}
}
private int GetIndex(int value, List<List<int>> center)//得到数据与质心距离最小的那个类的质心的下标
{
#region 按照余弦相似度计算距离
int index;
double cosmax;
index = 0;
double cos = 0;
cos = CosOfIndividuals(center[0].ToArray(), population[value].gene);
cosmax = cos;
index = 0;
for (int i = 1; i < K; i++)
{
double tempmax = CosOfIndividuals(center[i].ToArray(), population[value].gene);
if (tempmax > cosmax)
{
cosmax = tempmax;
index = i;
}
}
#endregion
#region 按照欧式距离计算距离
//int min;
//index = 0;
//int sum = 0;
//for (int i = 0; i < gsmnum; i++)
//{
// int a = center[0][i];
// int b=population[value].gene[i];
// sum += Math.Abs(a - b) * Math.Abs(a - b);
//}
//min = Convert.ToInt32((Math.Sqrt((Double)sum)));
//index = 0;
//for (int i = 1; i < K; i++)
//{
// sum = 0;
// for (int j = 0; j < gsmnum; j++)
// {
// int a = center[i][j];
// int b = population[value].gene[j];
// sum += Math.Abs(a - b) * Math.Abs(a - b);
// }
// int tempmin = Convert.ToInt32((Math.Sqrt((Double)sum)));
// if (tempmin < min)
// {
// min = tempmin;
// index = i;
// }
//}
#endregion
return index;
}
private int GetIndexEuclidean(int value, List<List<int>> center)//得到数据与质心距离最小的那个类的质心的下标
{
int index;
int min;
index = 0;
int sum = 0;
for (int i = 0; i < gsmnum; i++)
{
int a = center[0][i];
int b = population[value].gene[i];
sum += Math.Abs(a - b) * Math.Abs(a - b);
}
min = Convert.ToInt32((Math.Sqrt((Double)sum)));
index = 0;
for (int i = 1; i < K; i++)
{
sum = 0;
for (int j = 0; j < gsmnum; j++)
{
int a = center[i][j];
int b = population[value].gene[j];
sum += Math.Abs(a - b) * Math.Abs(a - b);
}
int tempmin = Convert.ToInt32((Math.Sqrt((Double)sum)));
if (tempmin < min)
{
min = tempmin;
index = i;
}
}
return index;
}
private void AddClasster(int index, int value)//将数据添加到相应的类中
{
classter[index][top[index]++]=value;
}
private void UpdateCenter()//更新质心数组,每次选择均值作为质心
{
List<int> tempcenter2 = new List<int>();
int i, j;
for (i = 0; i < K; i++)
{
tempcenter2.Clear();
if (top[i] > 0)//如果类里面没有数据
{
for (int jj = 0; jj < gsmnum; jj++)
{
int sum = 0;
for (j = 0; j < top[i]; j++)
{
sum += population[classter[i][j]].gene[jj];
}
tempcenter2.Add(sum / top[i]);
}
for (int ii = 0; ii < gsmnum; ii++)
{
center[i][ii] = tempcenter2[ii];
}
}
}
}
private bool IsEqule(List<List<int>> copycenter, List<List<int>> center)//判断质心数组是不是不再变化,即相等
{
int i;
for (i = 0; i < K; ++i)
{
if (copycenter[i] != center[i])
{
return false;
}
}
return true;
}
private void InitCenterPoint()//选择尽量相互之间最远的一些点作为起始点
{
int centerpointcount=0;
#region 第一个点的选取 小区PCI 0-503 0-150-300-503
int firstindex = 0;
int num = 0;
int maxnum = 0;
for (int i = 0; i < population.Length; i++)
{
num = 0;
maxnum = 0;
if (i == 0)
{
for (int j = 0; j < population[i].gene.Length; j++)
{
if (population[i].gene[j] < 150)
{
num++;
}
}
maxnum = num;
firstindex = i;
}
else
{
for (int j = 0; j < population[i].gene.Length; j++)
{
if (population[i].gene[j] < 150)
{
num++;
}
}
if (num > maxnum)
{
maxnum = num;
firstindex = i;
}
}
}//第一个点的index选取
centerindex.Add(firstindex);
centerpointcount++;
#endregion
#region 第二个点的选取,距离第一个点最远的一个点
int secondmaxdis = 0;
int secondmaxindex = 0;
for (int i = 0; i < population.Length; i++)
{
secondmaxdis = 0;
if (i == 0)
{
secondmaxdis = disoftwoindividual(population[i].gene,population[firstindex].gene);
secondmaxindex = i;
}
else
{
int tempdis=disoftwoindividual(population[i].gene, population[firstindex].gene);
if (tempdis > secondmaxdis)
{
secondmaxdis = tempdis;
secondmaxindex = i;
}
}
}//第二个点的index选取
centerindex.Add(secondmaxindex);
centerpointcount++;
#endregion
#region 后续K-2个点的选择,选择距离和最大的5个中偏差最小的一个
//for (int i = 0; i < K-2; i++)
//{
// for(int j=0;j<K-)
//}
#endregion
}
private double CosOfIndividuals(int[] a, int[] b)//计算两个个体之间的向量余弦
{
double temp1 = 0.0;
double temp2 = 0.0;
double temp3 = 0.0;
for (int i = 0; i < gsmnum; i++)
{
temp1 += a[i] * b[i];
temp2 += a[i] * a[i];
temp3 += b[i] * b[i];
}
temp2 = Math.Sqrt(temp2);
temp3 = Math.Sqrt(temp3);
return Math.Round(temp1 / (temp2 * temp3), 6);
}
}
}