// Класстеризация объектов методом k-средних private List <int>[] kMeansClustering(int clustersCount, Dictionary <int, ObjectParameters> objParametrs) { if (objParametrs.Count < 1) { MessageBox.Show("Ошибка: не найдено ни одного объекта."); return(null); } List <ObjectParameters> objects = new List <ObjectParameters>(objParametrs.Values); // Выбор стартового набора центь центроидов кластеров методом k-средних++ List <ObjectParameters> centroids = kMeansPPSelectionStartingCentroids(clustersCount, objParametrs); // Список кластеров, содержащий набор объектов, принадлежищих каждому из них List <int>[] clusters = new List <int> [centroids.Count], oldClusters = new List <int> [centroids.Count]; for (int i = 0; i < clusters.Length; ++i) { clusters[i] = new List <int>(); } while (true) { for (int i = 0; i < clusters.Length; ++i) { oldClusters[i] = new List <int>(clusters[i]); clusters[i].Clear(); } // Формирование кластеров foreach (KeyValuePair <int, ObjectParameters> obj in objParametrs) { int selectedCentroid = 0; double minDistance = double.MaxValue; // Объект выбирает центроид кластера, которому он принадлежит double distance; for (int i = 0; i < centroids.Count; ++i) { distance = сalculateDistance(obj.Value, centroids[i]); if (distance < minDistance) { minDistance = distance; selectedCentroid = i; } } // После того, как кластер выбран, метка объекта добавляется в его список clusters[selectedCentroid].Add(obj.Key); } for (int i = 0; i < clusters.Length; ++i) { if (!clusters[i].SequenceEqual(oldClusters[i])) { break; } // Если все объекты идентичны else if (i == (clusters.Length - 1)) { // Выход из бесконечного цикла кластеризации return(clusters); } } // Для каждого полученного класстера перерассчитываются центроиды for (int i = 0; i < clusters.Length; ++i) { centroids[i] = new ObjectParameters(); foreach (int objMark in clusters[i]) { centroids[i].Perimeter += objParametrs[objMark].Perimeter; centroids[i].Square += objParametrs[objMark].Square; centroids[i].Compactness += objParametrs[objMark].Compactness; centroids[i].Elongation += objParametrs[objMark].Elongation; } if (clusters[i].Count != 0) { centroids[i].Perimeter /= clusters[i].Count; centroids[i].Square /= clusters[i].Count; centroids[i].Compactness /= clusters[i].Count; centroids[i].Elongation /= clusters[i].Count; } } } // Циклический перерассчёт до тех пор, пока результаты не усреднятся }