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"); } }
private void Btn_load_Click(object sender, EventArgs e) { this.m_workInfo.AddInfornation("выбор подходящего набора данных"); using (OpenFileDialog fd = new OpenFileDialog() { InitialDirectory = @"c:\", Filter = "json files (*.json)|*.json|xml files (*.xml)|*.xml", FilterIndex = 1, RestoreDirectory = true }) { if (fd.ShowDialog() == DialogResult.OK) { try { FileInfo fi = new FileInfo(fd.FileName); if (fi.Extension.Equals(".xml")) { var set = DataSetSerializer.LoadFromXmlFile(fd.FileName); this.m_mathSet = DataSetSerializer.SetToIMathSet(set); } else { using (StreamReader sr = new StreamReader(fd.FileName, Encoding.Default)) { String jsonString = sr.ReadToEnd(); this.m_mathSet = DataSetSerializer.JsonToMathSet(jsonString); } } this.m_workInfo.AddInfornation("набор данных \'" + fi.Name + "\' загружен"); this.m_renderHandler.AddMathSet(this.m_mathSet); this.RenderClasses(); } catch (Exception ex) { this.m_workInfo.AddError(ex.Message); } } else { this.m_workInfo.AddInfornation("операция отменена"); } } }
internal static IMathPoint GetLimitPoint(IMathSet mathSet, Func <Double, Double, Boolean> comparisonFunc) { if (1 < mathSet.RowsCount) { IMathPoint limitPoint = mathSet[0].Clone() as IMathPoint; for (Int32 r = 0; r < mathSet.RowsCount; r++) { for (Int32 c = 0; c < mathSet[r].CoordinatesCount; c++) { if (comparisonFunc(limitPoint[c], mathSet[r][c])) { limitPoint[c] = mathSet[r][c]; } } } return(limitPoint); } throw new ArgumentException("входной набор IMathSet должен содержать минимум 2 точки с данными"); }
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 void AddMathSet(IMathSet set) { this.m_mathSet = set; this.m_cResult = null; }
public ClusteringResult(List <IMathPoint> centers, IMathSet mathSet, Int32 iteration) { this.Centers = centers; this.MathSet = mathSet; this.IterationCounter = 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)); }
public void AddMathSet(IMathSet set) { this.m_mathSet = set; this.m_cResult = null; }
public static String MathSetToJson(IMathSet mathSet) { return(DataSetSerializer.SetToJson(mathSet.SerializableSet)); }