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");
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        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;
        }
Пример #4
0
        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");
        }
Пример #5
0
        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);
        }