#region License Information /* HeuristicLab * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using HeuristicLab.Core; using System; using System.Collections.Generic; namespace HeuristicLab.Algorithms.EvolvmentModelsOfModels { public class KMeansClusterizationAlgorithm { public int K { get; private set; } public KMeansClusterizationAlgorithm() { } public KMeansClusterizationAlgorithm(int k) { K = k; } public KMeansClusterizationAlgorithm(KMeansClusterizationAlgorithm old) { this.K = old.K; } public int Apply(IRandom random, double[,] distances, List numberCluster) { K = ApplyClusteringAlgorithm(random, distances, numberCluster, K); return K; } public static int ApplyClusteringAlgorithm(IRandom random, double[,] distances, List numberCluster, int k) { int mapSize = distances.GetLength(0); List centroids = new List(); // capacity is equal K List averageClusterDistance = new List(); List> clusters = new List>(); // capacity is equal K CentroidsRandomSetUp(random, centroids, mapSize, k); if (numberCluster.Count == 0) { for (int i = 0; i < mapSize; i++) { numberCluster.Add(0); } } bool flag = true; int count = 0; while (flag&&(count<1000)) { clusters.Clear(); for (int i = 0; i < k; i++) { clusters.Add(new List()); } for (int i = 0; i < mapSize; i++) { numberCluster[i] = LookCloseCentroid(centroids, distances, i, k); clusters[numberCluster[i]].Add(i); } k = NullSizeClusterDelete(centroids, clusters, mapSize, numberCluster, k); flag = false; for (int i = 0; i < k; i++) { AverageClusterDistanceCalculation(averageClusterDistance, distances, numberCluster, mapSize, i); var newCentroid = clusters[i][HelpFunctions.ChooseMinElementIndex(averageClusterDistance)]; if (newCentroid != centroids[i]) { flag = true; centroids[i] = newCentroid; } averageClusterDistance.Clear(); } count++; } return k; } private static void CentroidsRandomSetUp(IRandom random, List centroids, int size, int k) { for (int i = 0; i < k; i++) { centroids.Add(random.Next(size)); } } private static int LookCloseCentroid(List centroids, double[,] distances, int currentNumber, int k) { double minDistanse = distances[currentNumber, centroids[0]]; int clusterNum = 0; for (int i = 1; i < k; i++) { if (minDistanse > distances[currentNumber, centroids[i]]) { minDistanse = distances[currentNumber, centroids[i]]; clusterNum = i; } } return clusterNum; } private static int NullSizeClusterDelete(List centroids, List> clusters, int mapSize, List numberCluster, int k) { int iter = 0; for (int i = 0; i < k; i++) { if (clusters[i - iter].Count == 0) { for (int j = 0; j < mapSize; j++) { if (numberCluster[j] > (i - iter)) numberCluster[j]--; } for (int j = 0; j < k - iter; j++) { if (j != i - iter) { for (int m = 0; m < clusters[j].Count; m++) if (clusters[j][m] > (i - iter)) (clusters[j][m])--; } } clusters.Remove(clusters[i - iter]); centroids.Remove(centroids[i - iter]); iter++; } } k -= iter; return k; } public static void AverageClusterDistanceCalculation(List averageClusterDistance, double[,] distances, List numberCluster, int MapSize, int currentClusterNumber) { int m = 0; for (int i = 0; i < MapSize; i++) { if (numberCluster[i] == currentClusterNumber) { averageClusterDistance.Add(0); for (int j = 0; j < MapSize; j++) { if (numberCluster[j] == currentClusterNumber) averageClusterDistance[m] += Math.Abs(distances[i, j]); } m++; } } } } }