Отправляет email-рассылки с помощью сервиса Sendsay

RFpro.ru: Microsoft .NET

  Все выпуски  

RFpro.ru: Microsoft .NET


Хостинг портала RFpro.ru:
Московский хостер
Профессиональный ХОСТИНГ на базе Linux x64 и Windows x64

РАССЫЛКИ ПОРТАЛА RFPRO.RU

Лучшие эксперты по данной тематике

Асмик Гаряка
Статус: Академик
Рейтинг: 10416
∙ повысить рейтинг »
Micren
Статус: Профессор
Рейтинг: 1779
∙ повысить рейтинг »
Александр Чекменёв {vanger}
Статус: Профессор
Рейтинг: 996
∙ повысить рейтинг »

/ КОМПЬЮТЕРЫ И СОФТ / Программирование / Microsoft .NET : C#

Номер выпуска:232
Дата выхода:09.05.2012, 20:00
Администратор рассылки:Alexey G. Gladenyuk (Управляющий)
Подписчиков / экспертов:80 / 35
Вопросов / ответов:1 / 2

Консультация # 185939: Здравствуйте уважаемые эксперты! Нужно на C# запрограммировать алгоритм FOREL (Форель) и исследовать свойства этого алгоритма N=φ(r) где r это параметр алгоритма форель. Вот последовательность алгоритма: 1) Случайно выбираем текущий объект из выборки 2) Помечаем объекты выборки, находящиеся на расст...


Консультация # 185939:

Здравствуйте уважаемые эксперты! Нужно на C# запрограммировать алгоритм FOREL (Форель) и исследовать свойства этого алгоритма N=φ(r) где r это параметр алгоритма форель.

Вот последовательность алгоритма:

1) Случайно выбираем текущий объект из выборки
2) Помечаем объекты выборки, находящиеся на расстоянии менее, чем R от текущего
3) Вычисляем их центр тяжести, помечаем этот центр как новый текущий объект
4) Повторяем шаги 2-3, пока новый текущий объект не совпадет с прежним
5) Помечаем объекты внутри сферы радиуса R вокруг текущего объекта как кластеризованные, выкидываем их из выборки
6) Повторяем шаги 1-5, пока не будет кластеризована вся выборка

Дата отправки: 01.05.2012, 19:24
Вопрос задал: Константин (Посетитель)
Всего ответов: 2
Страница онлайн-консультации »


Консультирует Micren (Профессор):

Здравствуйте, Константин!

Код :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Application
{
	class MainClass
	{
		// Размер выборки
		const int SIZE = 10;
		// Радиус поиска
		const double R_MIN = 0;
		const double R_MAX = (MAX - MIN) / 2.0;
		const double R_STEP = 1;
		// Пределы для генерации массива случайных чисел
		const double MIN = -10;
		const double MAX = +10;

		public static void Main (string[] args)
		{
			try {
				new MainClass ().Run ();
			} catch (Exception ex) {
				Console.WriteLine ("Необработанное исключение:\n{0}", ex.Message);
			}
		}

		/// <summary>
		/// Запускает цикл тестирования
		/// </summary>
		void Run ()
		{
			double[] data = genArray ();
			
			print ("Коллекция данных для тестирования:", data);
			
			Dictionary<double, int> clusterCount = new Dictionary<double, int> ();
			
			for (double r = R_MIN; r <= R_MAX; r += R_STEP) {
				clusterCount.Add (r, testFOREL (data, r));
			}
			
			double maxClusters = clusterCount.Max (a => { return a.Value; });
			
			Console.WriteLine ("График зависимости к-ва кластеров от R");
			foreach (var item in clusterCount) {
				Console.Write ("{0,5:0.00}:", item.Key);
				string str = new string ('*', (int)(item.Value / maxClusters * (80 - 11)));
				Console.WriteLine ("{0}{1,-5}", str, item.Value);
			}
		}

		/// <summary>
		/// Тестирует алгоритм FOREL
		/// </summary>
		/// <param name="array">
		/// Коллекция данных
		/// </param>
		/// <param name="r">
		/// Радиус поиска
		/// </param>
		/// <returns>
		/// Количество кластеров
		/// </returns>
		int testFOREL (double[] array, double r)
		{
			double[][] clusters = Forel.Solve (array, r, (o1, o2) => { return o1 - o2; }, a =>
			{
				double s = 0.0;
				foreach (double v in a)
					s += v;
				return s / a.Length;
			});
			print (string.Format ("Для параметра R={0} получены кластеры:", r), clusters);
			Console.WriteLine ("Всего {0} кластеров", clusters.Length);
			return clusters.Length;
		}

		// Генератор случайных чисел
		static Random random = new Random ();

		/// <summary>
		///  Генерирует массив случайных чисел
		/// </summary>
		/// <returns>
		/// Сгенерированный массив
		/// </returns>
		double[] genArray ()
		{
			double[] result = new double[SIZE];
			
			for (int i = 0; i < SIZE; ++i) {
				result[i] = random.NextDouble () * (MAX - MIN) + MIN;
			}
			return result;
		}

		/// <summary>
		/// Выводит массив на консоль
		/// </summary>
		/// <param name="collection">
		/// Коллекция данных с интерфейсом IEnumerable
		/// </param>
		void print<T> (T collection) where T : IEnumerable
		{
			Console.Write ("(");
			foreach (var item in collection) {
				IEnumerable tmp = item as IEnumerable;
				if (tmp != null) {
					print (tmp);
				} else {
					Console.Write ("{0} ", item);
				}
			}
			Console.Write (")");
		}

		/// <summary>
		/// Выводит массив на консоль
		/// </summary>
		/// <param name="message">
		/// Сообщение перед выводом массива
		/// </param>
		/// <param name="collection">
		/// Коллекция данных с интерфейсом IEnumerable
		/// </param>
		void print<T> (string message, T collection) where T : IEnumerable
		{
			Console.WriteLine ("{0}", message);
			print (collection);
			Console.WriteLine ();
		}
		
	}

	/// <summary>
	/// Делегат для функции, определяющей расстояние между объектами
	/// </summary>
	public delegate double DistanceFunction<T> (T o1, T o2);
	/// <summary>
	/// Делегат для функции, определяющей центр масс объектов
	/// </summary>
	public delegate T CenterOfMassFunction<T> (T[] arr);

	/// <summary>
	/// Реализует алгоритм FOREL
	/// </summary>
	public static class Forel
	{
		private static Random random = new Random ();

		/// <summary>
		/// Решает задачу кластеризации
		/// </summary>
		/// <param name="array">
		/// Массив данных
		/// </param>
		/// <param name="r">
		/// Радиус
		/// </param>
		/// <param name="distance">
		/// Ф-я расчета дистанции между объектами
		/// </param>
		/// <param name="centerOfMass">
		/// Ф-я расчета центра масс
		/// </param>
		/// <returns>
		/// Массив кластеров
		/// </returns>
		public static T[][] Solve<T> (T[] array, double r, DistanceFunction<T> distance, CenterOfMassFunction<T> centerOfMass) where T : IEquatable<T>
		{
			r = Math.Abs (r);
			// Результат расчета
			List<T[]> result = new List<T[]> ();
			// Копируем данные в динамический список
			List<T> data = array.ToList ();
			// Пока есть не кластеризованные элементы
			while (data.Count > 0) {
				// Значение элемента выбранного в качестве центра
				T center;
				T centerNew = data[random.Next (data.Count)];
				// Получившийся кластер
				T[] cluster = null;
				do {
					center = centerNew;
					// Кластер собирается здесь					
					cluster = (from item in data
						where distance (item, center) <= r
						select item).ToArray ();
					// Считаем центр тяжести
					centerNew = centerOfMass (cluster);
				} while (!centerNew.Equals (center));
				result.Add (cluster);
				// Удаление кластеризованных элементов из выборки
				Array.ForEach (cluster, item => { data.Remove (item); });
			}
			return result.ToArray ();
		}
		
	}
}

Пример работы:
Код :
Коллекция данных для тестирования:
(-5,44374301817442 8,90650349618238 -2,73375119675591 -9,10588378045051 9,66046832486078 4,22250842406531 -6,14473116404597 -3,7516542401871 5,14795034897884 7,19218952450537 )
Для параметра R=0 получены кластеры:
((-9,10588378045051 )(-6,14473116404597 )(-5,44374301817442 )(-3,7516542401871 )(-2,73375119675591 )(4,22250842406531 )(5,14795034897884 )(7,19218952450537 )(8,90650349618238 )(9,66046832486078 ))
Всего 10 кластеров
Для параметра R=1 получены кластеры:
((-9,10588378045051 )(-5,44374301817442 -6,14473116404597 )(-2,73375119675591 -3,7516542401871 )(4,22250842406531 5,14795034897884 )(8,90650349618238 7,19218952450537 )(9,66046832486078 ))
Всего 6 кластеров
Для параметра R=2 получены кластеры:
((-5,44374301817442 -9,10588378045051 -6,14473116404597 )(-2,73375119675591 -3,7516542401871 )(4,22250842406531 5,14795034897884 7,19218952450537 )(8,90650349618238 9,66046832486078 ))
Всего 4 кластеров
Для параметра R=3 получены кластеры:
((-5,44374301817442 -2,73375119675591 -9,10588378045051 -6,14473116404597 -3,7516542401871 )(8,90650349618238 9,66046832486078 4,22250842406531 5,14795034897884 7,19218952450537 ))
Всего 2 кластеров
Для параметра R=4 получены кластеры:
((-5,44374301817442 -2,73375119675591 -9,10588378045051 -6,14473116404597 -3,7516542401871 )(8,90650349618238 9,66046832486078 4,22250842406531 5,14795034897884 7,19218952450537 ))
Всего 2 кластеров
Для параметра R=5 получены кластеры:
((-5,44374301817442 -2,73375119675591 -9,10588378045051 -6,14473116404597 -3,7516542401871 )(8,90650349618238 9,66046832486078 4,22250842406531 5,14795034897884 7,19218952450537 ))
Всего 2 кластеров
Для параметра R=6 получены кластеры:
((-5,44374301817442 -2,73375119675591 -9,10588378045051 -6,14473116404597 -3,7516542401871 )(8,90650349618238 9,66046832486078 4,22250842406531 5,14795034897884 7,19218952450537 ))
Всего 2 кластеров
Для параметра R=7 получены кластеры:
((-5,44374301817442 -2,73375119675591 -9,10588378045051 -6,14473116404597 -3,7516542401871 )(8,90650349618238 9,66046832486078 4,22250842406531 5,14795034897884 7,19218952450537 ))
Всего 2 кластеров
Для параметра R=8 получены кластеры:
((-5,44374301817442 -2,73375119675591 -9,10588378045051 4,22250842406531 -6,14473116404597 -3,7516542401871 5,14795034897884 )(8,90650349618238 9,66046832486078 7,19218952450537 ))
Всего 2 кластеров
Для параметра R=9 получены кластеры:
((-5,44374301817442 8,90650349618238 -2,73375119675591 -9,10588378045051 9,66046832486078 4,22250842406531 -6,14473116404597 -3,7516542401871 5,14795034897884 7,19218952450537 ))
Всего 1 кластеров
Для параметра R=10 получены кластеры:
((-5,44374301817442 8,90650349618238 -2,73375119675591 -9,10588378045051 9,66046832486078 4,22250842406531 -6,14473116404597 -3,7516542401871 5,14795034897884 7,19218952450537 ))
Всего 1 кластеров
График зависимости к-ва кластеров от R
 0,00:*********************************************************************10   
 1,00:*****************************************6    
 2,00:***************************4    
 3,00:*************2    
 4,00:*************2    
 5,00:*************2    
 6,00:*************2    
 7,00:*************2    
 8,00:*************2    
 9,00:******1
10,00:******1

Консультировал: Micren (Профессор)
Дата отправки: 08.05.2012, 08:47
Рейтинг ответа:

НЕ одобряю 0 одобряю!


Консультирует Evgenijm (10-й класс):

Здравствуйте, Константин!

Я прикрутил этот алгоритм к своему простенькому симулятору для изучения точек. Можно сохранить или загрузить точки из файла, а установив флажок - добавлять новые точки.

Сам алгоритм находится в файле FOREL.cs

Алгоритм очень прост. Ищет концентрированные сгустки точек на поле. Начинает от случайной точки и потихоньку ползет так, чтобы захватить как можно более плотное облако точек. Вырезав кластер, начинает все заново, пока точки не кончатся. Поиск локальный, так что глобальная оптимальность не гарантируется. Но в сгустках плотность точек выше и при случайном выборе точки мы получаем повышеную вероятность, что она уже будет в хорошей области.

Недостатки: фиксированный радиус для кластера и фиксированная форма границы кластера (окружность). При слишком большом радиусе в кластер попадут точки, которые к нему не должны относиться. При слишком маленьком или если поле почти равномерно заполнено - мы получаем не кластеры, а просто кучу кружочков и ошметков от кружочков, что лишает смысла кластеризацию. Кроме того, алгоритм не так легко распараллелить. Архив программы я выложил на сайте: скачать файл WpfFOREL.rar [10.7 кб]

Текст FOREL.cs дополнительно выставляю здесь:

Код :
using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfFOREL
{
    class FOREL
    {
        /// <summary>Разбивает список точек на несколько кластеров, которые тоже хранятся как списки.</summary>
        /// <param name="Points">Список точек</param>
        /// <param name="Radius">Радиус кластеров</param>
        /// <returns>Список кластеров (список списков точек)</returns>
        public static List<List<Point>> Recluster(List<Point> Points, double Radius)
        {
            List<List<Point>> Result = new List<List<Point>>();
            Random RND = new Random();
            double R2 = Radius * Radius;
            List<Point> Unclustered = new List<Point>(Points);

            while (Unclustered.Count > 0)
            {
                Point NewCenter = Unclustered[RND.Next(Unclustered.Count)];
                Point Center;
                do //Двигаем центр, пока он не устаканится
                {
                    Center = NewCenter;
                    double x = 0.0, y = 0.0;
                    int Cnt = 0;
                    foreach (Point P in Unclustered)//Считаем новый центр масс
                        if (Dist2(Center, P) < R2)
                        {
                            x += P.X;
                            y += P.Y;
                            Cnt++;
                        }
                    NewCenter = new Point(x / Cnt, y / Cnt);
                }
                while (Center != NewCenter);

                List<Point> Cluster = new List<Point>(); //Переносим точки в новый кластер
                for (int i = Unclustered.Count - 1; i >= 0; i--)
                    if (Dist2(Center, Unclustered[i]) < R2)
                    {
                        Cluster.Add(Unclustered[i]);
                        Unclustered.RemoveAt(i);
                    }
                Result.Add(Cluster);
            }

            return Result;
        }

        /// <summary>Квадрат расстояния между точками</summary>
        private static double Dist2(Point P1, Point P2)
        {
            double dx = P1.X - P2.X;
            double dy = P1.Y - P2.Y;
            return dx * dx + dy * dy;
        }
    }
}

Консультировал: Evgenijm (10-й класс)
Дата отправки: 09.05.2012, 02:11
Рейтинг ответа:

НЕ одобряю 0 одобряю!


Оценить выпуск | Задать вопрос экспертам

главная страница  |  стать участником  |  получить консультацию
техническая поддержка  |  восстановить логин/пароль

Дорогой читатель!
Команда портала RFPRO.RU благодарит Вас за то, что Вы пользуетесь нашими услугами. Вы только что прочли очередной выпуск рассылки. Мы старались. Пожалуйста, оцените его. Если совет помог Вам, если Вам понравился ответ, Вы можете поблагодарить автора - для этого в каждом ответе есть специальные ссылки. Вы можете оставить отзыв о работе портале. Нам очень важно знать Ваше мнение. Вы можете поближе познакомиться с жизнью портала, посетив наш форум, почитав журнал, который издают наши эксперты. Если у Вас есть желание помочь людям, поделиться своими знаниями, Вы можете зарегистрироваться экспертом. Заходите - у нас интересно!
МЫ РАБОТАЕМ ДЛЯ ВАС!



В избранное