/// <summary> /// Инициализация начальных кластеров /// </summary> /// <param name="points">Исходные точки</param> /// <returns>Кластера с дополнительной информацией <seealso cref="CalculatedCluster"/></returns> private Dictionary <Guid, CalculatedCluster> InitClusters(IEnumerable <CurePoint> points) { var clusters = points.Select(x => new CureCluster(x)).ToList(); var dict = new Dictionary <Guid, CalculatedCluster>(); foreach (var cluster1 in clusters) { var minDistance = Double.MaxValue; CureCluster closest = null; foreach (var cluster2 in clusters) { if (cluster1 == cluster2) { continue; } var distance = Distance(cluster1, cluster2); if (distance < minDistance) { minDistance = distance; closest = cluster2; } } dict.Add(cluster1.Number, new CalculatedCluster { Closest = closest, Cluster = cluster1, Distance = minDistance }); } return(dict); }
/// <summary> /// Слияние кластеров /// </summary> /// <param name="cluster1">Кластер№1</param> /// <param name="cluster2">Кластер№2</param> /// <returns>Итоговый кластер</returns> private CureCluster MergeClusters(CureCluster cluster1, CureCluster cluster2) { var totalPoints = cluster1.Points.Union(cluster2.Points).ToList(); var meanPoint = new double[totalPoints.First().Vector.Length]; for (var i = 0; i < meanPoint.Length; ++i) { meanPoint[i] = totalPoints.Sum(x => x.Vector[i]) / totalPoints.Count * 1.0; } var ordered = totalPoints .Select(x => new { Point = x, Distance = _distanceCalculator.GetDistance(meanPoint, x.Vector) }) .OrderBy(x => x.Distance).ToList(); var rep = (_c > ordered.Count ? ordered : ordered.Take(_c)) .Select(x => x.Point.Vector.Select((v, i) => v + _a * (meanPoint[i] - v)).ToArray()) .ToList(); return(new CureCluster(totalPoints, rep)); }
/// <summary> /// Перерасчет метрки кластеров для определенного кластера с номером /// </summary> /// <param name="clusters">Кластеры</param> /// <param name="number">Номер кластера</param> private void RecalculateClosest(Dictionary <Guid, CalculatedCluster> clusters, Guid number) { var minDistance = Double.MaxValue; CureCluster closest = null; foreach (var pair in clusters) { if (pair.Key == number) { continue; } var distance = Distance(pair.Value.Cluster, clusters[number].Cluster); if (distance < minDistance) { minDistance = distance; closest = pair.Value.Cluster; } } clusters[number].Closest = closest; clusters[number].Distance = minDistance; }
/// <summary> /// Расчет растояния между двумя кластерами /// </summary> /// <param name="cluster1">Калстер№1</param> /// <param name="cluster2">Кластер№2</param> /// <returns>Расстояние</returns> public double Distance(CureCluster cluster1, CureCluster cluster2) { var repPoints = cluster2.RepPoints.ToList(); var min = _distanceCalculator.GetDistance(cluster1.RepPoints.First(), repPoints.First()); foreach (var repPoint1 in cluster1.RepPoints) { foreach (var repPoint2 in repPoints) { var distance = _distanceCalculator.GetDistance(repPoint1, repPoint2); if (distance < min) { min = distance; } } } var maxWeights = Math.Max(cluster1.Points.Sum(x => x.Weight), cluster2.Points.Sum(x => x.Weight)); return(maxWeights > _averageCount ? (min * maxWeights * _targetClustersCount / _averageCount) : min); }