关闭

多目标进化问题,根据PCI进行小区的聚类,Kmeans算法的改进:二次聚类

标签: 多目标Kmeans聚类c#算法
289人阅读 评论(0) 收藏 举报

其中将种群中的个体聚类的时候,使用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);
        }
    }
}

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:40404次
    • 积分:1137
    • 等级:
    • 排名:千里之外
    • 原创:77篇
    • 转载:2篇
    • 译文:0篇
    • 评论:6条
    最新评论