예제 #1
0
        /// <summary>
        ///     Алгоритм нечёткой кластеризации
        /// </summary>
        /// <param name="clusterCount">Число кластеров</param>
        /// <param name="values">Значения кластеров</param>
        /// <param name="m">Чёткость алгоритма</param>
        /// <param name="eps">Точность алгоритма</param>
        /// <param name="randSeed">Случайное исходное значение</param>
        public static IEnumerable <FuzzyValue> CMeans(int clusterCount, List <double> values, double m = 2,
                                                      double eps = 0.00001, int randSeed = 0)
        {
            if (randSeed != 0)
            {
                RandUtil.SetSeed(randSeed);
            }

            if (values.Count == 0)
            {
                return(new List <FuzzyValue>());
            }

            // Создаём матрицу принадлежности
            var u = Enumerable.Range(0, values.Count).Select(x =>
            {
                var c = new double[clusterCount];
                for (var i = 0; i < c.Length; i++)
                {
                    c[i] = RandUtil.RandDoubleRange(0, 1 - c.Sum());
                    if (i == c.Length - 1)
                    {
                        c[i] = 1 - c.Sum();
                    }
                }

                return(c);
            }).ToArray();

            double        _j = -1; // Текущее значение целевой функции
            List <double> centers; // Список центров кластеров

            while (true)
            {
                // Генерация новых центров кластеров
                centers = GetCenters(clusterCount, values, m, u);
                // Получение значения целевой функции
                var newJ = ObjectiveFunc(values, m, u, centers);
                if (_j != -1 && Math.Abs(newJ - _j) < eps)
                {
                    break;
                }
                _j = newJ;

                // Обновление матрицы принадлежности
                for (var i = 0; i < u.Length; i++)
                {
                    for (var j = 0; j < u[i].Length; j++)
                    {
                        var denominator = Enumerable.Range(0, clusterCount).Select(x =>
                                                                                   Math.Pow(
                                                                                       Math.Sqrt(Dist(values[i], centers[j])) / Math.Sqrt(Dist(values[i], centers[x])),
                                                                                       2 / (m - 1)
                                                                                       )
                                                                                   ).Sum();

                        u[i][j] = 1 / denominator;
                        if (double.IsNaN(u[i][j]))
                        {
                            u[i][j] = 1;
                        }
                    }
                }
            }

            var fuzzyValues = new List <FuzzyValue>();

            for (var j = 0; j < values.Count; j++)
            {
                var clusterDegree = new Dictionary <int, double>();
                for (var k = 0; k < u[j].Count(); k++)
                {
                    clusterDegree.Add(k, u[j][k]);
                }
                fuzzyValues.Add(new FuzzyValue(values[j], clusterDegree));
            }

            return(fuzzyValues);
        }