internal static List <IMathPoint> InitCenters(IMathSet mathSet, ClusteringOptions options) { IMathPoint minPoint = DataMiningMath.GetLimitPoint(mathSet, (Double c, Double p) => c > p); IMathPoint maxPoint = DataMiningMath.GetLimitPoint(mathSet, (Double c, Double p) => c < p); if (options.Initialization == InitializationType.RANDOM) { return(GetRandomClusterCenters(minPoint, maxPoint, options)); } else { throw new ArgumentException("поддерживаемый метод инициализации центров кластеризации: random"); } }
public MainForm() { this.InitializeComponent(); this.DoubleBuffered = true; this.FormBorderStyle = FormBorderStyle.FixedDialog; // настройка лога: this.m_workInfo = new WorkInfo <TextBox>(this.tbx_log); this.m_workInfo.SettingOutputObject += (TextBox tbx, String s) => { tbx.Text = s; }; // настройка обработчика отрисовки: this.m_renderHandler = new DataSetRenderHandler(this.pbx_clustersBinding); // настройка кластеризации: this.m_clusteringHandler = new ClusteringHandler(); this.m_options = ClusteringOptions.Default; // количество кластеров: this.tbx_clustersCount.Text = this.m_options.ClusterCount.ToString(); // максимальное число итераций: this.tbx_maxIteration.Text = this.m_options.MaxIterations.ToString(); // способ инициализации: this.cbx_initType.Items.AddRange(Enum.GetNames(typeof(InitializationType))); this.cbx_initType.SelectedIndex = (int)this.m_options.Initialization; // метрика: this.cbx_distance.Items.AddRange(Enum.GetNames(typeof(DistanceMetricType))); this.cbx_distance.SelectedIndex = (int)this.m_options.Distance; // тип алгоритма (однопоточный, многопоточный): this.cbx_algorithmType.Items.AddRange(Enum.GetNames(typeof(ModeType))); this.cbx_algorithmType.SelectedIndex = (int)this.m_options.Mode; // алгоритм: this.cbx_algoritm.Items.AddRange(Enum.GetNames(typeof(AlgorithmType))); this.cbx_algoritm.SelectedIndex = (int)this.m_clusteringHandler.Algorithm; // настройка кнопок: this.btn_clustering.Click += this.Btn_clustering_Click; this.btn_create.Click += this.Btn_create_Click; this.btn_datasetInfo.Click += this.Btn_datasetInfo_Click; this.btn_load.Click += this.Btn_load_Click; this.btn_renderClasses.Click += this.Btn_renderClasses_Click; this.btn_renderClusters.Click += this.Btn_renderClusters_Click; // фоновый обработчик кластеризации: this.bgw_toCluster = new BackgroundWorker { WorkerReportsProgress = true, WorkerSupportsCancellation = true }; this.bgw_toCluster.DoWork += this.m_bgw_toCluster_DoWork; this.bgw_toCluster.ProgressChanged += this.m_bgw_toCluster_ProgressChanged; this.bgw_toCluster.RunWorkerCompleted += this.m_bgw_toCluster_RunWorkerCompleted; }
public void Run(IMathSet mathSet, ClusteringOptions options) { this.m_sw.Restart(); switch (this.Algorithm) { case AlgorithmType.KMEANS: this.Result = ClusteringFacade.Kmeans(mathSet, options); break; case AlgorithmType.KMEDOIDS: this.Result = ClusteringFacade.Kmedoids(mathSet, options); break; default: throw new ArgumentException("выбран не используемый (не реализованный) алгоритм"); } this.m_sw.Stop(); this.CalculationTime = this.m_sw.ElapsedMilliseconds; }
public static ClusteringResult Kmedoids(IMathSet mathSet, ClusteringOptions options) { if (mathSet != null) { if (options.ClusterCount <= mathSet.RowsCount) { switch (options.Mode) { case ModeType.SINGLETHREADED: return(K_medoids.Singlethreaded(mathSet, options)); case ModeType.MULTITHREADED: return(K_medoids.Multithreaded(mathSet, options)); default: throw new ArgumentException("был выбран неприемлемый параметр из enum AlgoritmType"); } } throw new ArgumentException("количество точек с данными в input Set должно быть больше или равно количества кластеров в options"); } throw new ArgumentNullException("входной набор данных inputSet равен null"); }
internal static ClusteringResult Multithreaded(IMathSet mathSet, ClusteringOptions options) { // выбор метрики для расчета: Func <IMathPoint, IMathPoint, Double> func = DataMiningMath.UsedMetrics(options.Distance); // построение всех medoids для входного набора данных: Double[][] allMedoids = new Double[mathSet.RowsCount][]; Parallel.For(0, mathSet.RowsCount, (Int32 row) => { allMedoids[row] = new Double[mathSet.RowsCount]; for (int col = 0; col < mathSet.RowsCount; col++) { if (row != col) { allMedoids[row][col] = func(mathSet[row], mathSet[col]); } } }); // выбор центров кластеризации (случайная инициализация): Random random = new Random(); Dictionary <String, Int32> cIndexes = new Dictionary <String, Int32>(options.ClusterCount); Dictionary <String, List <Int32> > cDistributions = new Dictionary <String, List <Int32> >(); for (Int32 i = 0; i < options.ClusterCount; i++) { String name = "Cluster " + (i + 1); cIndexes.Add(name, random.Next(mathSet.RowsCount)); cDistributions.Add(name, new List <Int32>()); } // первый этап: предварительное связывание точек с центрами: Double newCost = 0; Parallel.For(0, mathSet.RowsCount, (Int32 row) => { String name = ""; Double minDistance = Double.MaxValue; // обход центров кластеризации: foreach (KeyValuePair <String, Int32> cluster in cIndexes) { if (minDistance > allMedoids[row][cluster.Value]) { name = cluster.Key; minDistance = allMedoids[row][cluster.Value]; } } lock (cDistributions) { newCost += minDistance; // подсчет текущей стоймости cDistributions[name].Add(row); // добавить точку в распределение } }); // основной цикл обработки: Int32 iteration = 0; Double prevCost; while (iteration++ <= options.MaxIterations) { // выбрать новые центры из ранее полученного распределения: prevCost = newCost; newCost = 0; Dictionary <String, Int32> newIndexes = new Dictionary <string, int>(options.ClusterCount); Dictionary <String, List <Int32> > newDistribution = new Dictionary <String, List <Int32> >(); foreach (KeyValuePair <string, int> cIndex in cIndexes) { newIndexes.Add(cIndex.Key, cDistributions[cIndex.Key][random.Next(cDistributions[cIndex.Key].Count)]); newDistribution.Add(cIndex.Key, new List <Int32>()); } // повторное связывание: Parallel.For(0, mathSet.RowsCount, (Int32 row) => { String name = ""; Double minDistance = Double.MaxValue; // обход центров кластеризации: foreach (KeyValuePair <String, Int32> cluster in newIndexes) { if (minDistance > allMedoids[row][cluster.Value]) { name = cluster.Key; minDistance = allMedoids[row][cluster.Value]; } } lock (newDistribution) { newCost += minDistance; // подсчет текущей стоймости newDistribution[name].Add(row); // добавить точку в распределение } }); // проверка на выход из цикла: Double dCost = newCost - prevCost; if (dCost > 0) { break; } cDistributions = newDistribution; cIndexes = newIndexes; } // маркировка данных по кластера: Parallel.ForEach(cDistributions, (KeyValuePair <string, List <int> > distribution) => { foreach (Int32 index in distribution.Value) { mathSet[index].Cluster = distribution.Key; } }); // получение центро клстеризации: List <IMathPoint> centers = new List <IMathPoint>(); foreach (KeyValuePair <string, int> index in cIndexes) { centers.Add(mathSet[index.Value]); } return(new ClusteringResult(centers, mathSet, iteration)); }
internal static ClusteringResult Multithreaded(IMathSet mathSet, ClusteringOptions options) { // выбор метрики для расчета: Func <IMathPoint, IMathPoint, Double> func = DataMiningMath.UsedMetrics(options.Distance); // инициализация центров кластеров для текущего шага расчета: List <IMathPoint> currentCenters = InitCenters(mathSet, options); // инициализация центров кластеров для предыдущего шага расчета: List <IMathPoint> prevCenters = new List <IMathPoint>(options.ClusterCount); // основной цикл обработки: Int32 iteration = 0; while (iteration++ <= options.MaxIterations) { // вычисление самого удачного центра для кластеров на рассматриваемой иттерации: Parallel.For(0, mathSet.RowsCount, (Int32 r) => { // поиск ближайшего кластера к точке: Int32 closestIdx = -1; Double minDistance = Double.MaxValue; for (Int32 i = 0; i < currentCenters.Count; i++) { Double distance = func(mathSet[r], currentCenters[i]); if (minDistance > distance) { closestIdx = i; minDistance = distance; } } // обновляем центр выбраного кластера: lock (currentCenters) { currentCenters[closestIdx] = DataMiningMath.MeanPoint(mathSet[r], currentCenters[closestIdx]); } }); // кластеризация данных в соответствии с новыми центрами: Parallel.For(0, mathSet.RowsCount, (Int32 r) => { // поиск ближайшего кластера к точке: IMathPoint closestCluster = null; Double minDistance = Double.MaxValue; for (Int32 i = 0; i < currentCenters.Count; i++) { Double distance = func(mathSet[r], currentCenters[i]); if (minDistance > distance) { closestCluster = currentCenters[i]; minDistance = distance; } } // обновить кластер у точки: mathSet[r].Cluster = closestCluster.Cluster; }); // проверка на выход из цикла: if (prevCenters.Count != 0) { Boolean flag = true; // флаг прерывания расчета // обход центров кластеризации: for (Int32 i = 0; i < currentCenters.Count; i++) { // обход координат: for (Int32 c = 0; c < currentCenters[i].CoordinatesCount; c++) { if (currentCenters[i][c] != prevCenters[i][c]) { flag = false; break; } } } if (flag) { break; } } prevCenters = new List <IMathPoint>(currentCenters); } return(new ClusteringResult(currentCenters, mathSet, iteration)); }
internal static List <IMathPoint> GetRandomClusterCenters(IMathPoint minPoint, IMathPoint maxPoint, ClusteringOptions options) { Random rnd = new Random(); List <IMathPoint> startClusterPoints = new List <IMathPoint>(options.ClusterCount); // обход центров кластеризации: for (Int32 i = 0; i < options.ClusterCount; i++) { startClusterPoints.Add((IMathPoint)minPoint.Clone()); // обход координат центра кластеризации: for (Int32 c = 0; c < startClusterPoints[i].CoordinatesCount; c++) { startClusterPoints[i][c] = rnd.NextDouble() * (maxPoint[c] - minPoint[c]) + minPoint[c]; } startClusterPoints[i].Class = string.Format("class {0}", i + 1); startClusterPoints[i].Cluster = string.Format("cluster {0}", i + 1); } return(startClusterPoints); }