public IEnumerable<ICluster> CreateClusters(IEnumerable<IClusterable> elements, uint clusterCount) { if (int.MaxValue < clusterCount) { throw new ArgumentOutOfRangeException(nameof(clusterCount)); } if (clusterCount < 1) { return Enumerable.Empty<ICluster>(); } if (clusterCount == 1) { var cluster = new SimpleCluster(); cluster.AddAll(elements); return new List<ICluster> { cluster }; } var elementsAsList = elements as IList<IClusterable>; if (null == elementsAsList) { elementsAsList = elements.ToList(); } int clusterCountAsInt = (int)clusterCount; if (elementsAsList.Count < clusterCountAsInt) { return Enumerable.Empty<ICluster>(); } var clusters = CreateRandomClusters(elementsAsList, clusterCountAsInt); AssignElementsToClusters(elementsAsList, clusters); var maxIterationCount = 1E3; for (var iteration = 0; iteration < maxIterationCount; iteration++) { if (UpdateClustersCenter(clusters)) { break; } foreach (var cluster in clusters) { cluster.RemoveAll(); } AssignElementsToClusters(elementsAsList, clusters); } return clusters; }
/// <summary> /// Creates random clusters. /// Each cluster contains no elements and uses one element as the center of the cluster. /// </summary> /// <param name="elements">The elements of all clusters.</param> /// <param name="clusterCount">The number of clusters.</param> /// <returns>Newly created random clusters having only a center.</returns> private IEnumerable<SimpleCluster> CreateRandomClusters(IList<IClusterable> elements, int clusterCount) { var clusters = new List<SimpleCluster>(clusterCount); var centerIndices = new HashSet<int>(); var maxElementIndex = elements.Count - 1; var maxIterationCount = 1E3; for (var clusterIndex = 0; clusterIndex < clusterCount; clusterIndex++) { var newCenterFound = false; for (var iteration = 0; !newCenterFound && iteration < maxIterationCount; iteration++) { var nextElementIndex = _random.Next(0, maxElementIndex); if (!centerIndices.Contains(nextElementIndex)) { var nextElement = elements[nextElementIndex]; var cluster = new SimpleCluster(); cluster.Center = nextElement; clusters.Add(cluster); centerIndices.Add(nextElementIndex); newCenterFound = true; break; } } if (!newCenterFound) { throw new ArgumentException(nameof(elements)); } } return clusters; }