imho.ws |
![]() |
![]() |
|
Сообщения:
Перейти к новому /
Последнее
|
Опции темы |
![]() |
# 1 |
Guest
Сообщения: n/a
|
Выбор элемента с пропорциональной ему вероятностью в C#
Вопрос может быть уже задавался не раз, но тем не менее я нигде не нашел ответа на него.
Требуется выбрать число из массива с вероятностью, пропорциональной его величине. Это значит приблизительно следующее: Есть массив, к примеру: int var[] = new int[8]; var = {1, 0, 0, 2, 5, 2, 4, 1}; Нужен алгоритм, который бы возвращал одно из этих чисел, но с пропорциональной этому числу вероятностью, т.е. шансы быть выбранным у элемента '5' самые большие, а у элементов '0' - самые маленькие, но все же они должны выпадать. Этот алгоритм надо будет запускать в многоитерационном цикле, а результирующее число записывать в переменную, которая будет использована дальше в программе. Прошу помощи, ибо сам исчерпал подходы к этой проблеме ![]() |
![]() |
# 2 |
Full Member
Регистрация: 20.01.2004
Адрес: Таллинн
Пол: Male
Сообщения: 623
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
первая мысль: делать много случайных чисел и записывать какое число сколько раз выпало.
Если выпал 0, записываем что он выпал один раз и генерируем снова. И так до того, пока у одного числа не наберётся максимальное количество выпаданий. 0 должен выпасть 6 раз 1 - 5 раза 2 - 4 раза 3 - 3 раза 4 - 2 раза 5 - 1 раз |
![]() |
![]() |
# 3 |
СуперМод
IMHO Консультант 2005-2009 Регистрация: 14.08.2002
Адрес: Московская ПЛ, ракетный отс
Пол: Male
Сообщения: 14 495
![]() |
Условия и взаимоисключающие.
Вероятность выпадения, пропорциональная нулю - нулю и равна. Вычисляется так: единица (вероятность того, что выпадет хоть что-то) делится на сумму чисел и умножается на соответствующее число (необходимое условие пропорциональности). При этом ноль не выпадет никогда. Следствия: если все элементы массива - нули, то задача решения не имеет. Ситуация "деление на ноль". Требуется встроить соответствующую проверку. Дальше так: вызываем функцию находжения случайного числа в диапазоне от нуля до единицы и начинаем вычитать из него вероятности выпадения чисел в порядке их возрастания до того момента, пока не получим результат равный нулю или меньше нуля. Как только данный результат достигнут - выводим число, которому соответствует последняя вычтенная вероятность. Пример: массив чисел {0, 1, 2 ,3 ,4 ,5} соответствующие вероятности {0, 1/15, 2/15, 3/15, 4/15, 5/15} пусть выпало случайное число=1/4 1/4-0=1/4, больше 0, продолжаем 1/4-1/15=11/60, больше 0, продолжаем 11/60-2/15=3/60, больше 0, продолжаем 3/60-3/15=-9/60, меньше 0, цикл завершён, выводим 3 Дальше снова берём случайное число и повторяем цикл. Количество повторений цикла - столько, сколько нужно. EvroStandart, Вашу мысль не понял. ![]()
__________________
Не засоряйте форум "спасибами"! Для выражения благодарности существуют ПС и репутация! Соблюдайте Правила! Распространенье наше по планете Особенно заметно вдалеке: В общественном парижском туалете Есть надписи на русском языке В. Высоцкий |
![]() |
![]() |
# 4 |
СуперМод
IMHO Консультант 2005-2009 Регистрация: 14.08.2002
Адрес: Московская ПЛ, ракетный отс
Пол: Male
Сообщения: 14 495
![]() |
В принципе - придумал, что сделать, чтобы ноль тоже выпадал (с исчезающе малой вероятностью).
Условие если результат равен нулю - выводить ноль, если меньше - число, которому соответствует последняя вычтенная вероятность. Если на 10000 циклов хоть раз получим ноль - это уже довольно большая удача...
__________________
Не засоряйте форум "спасибами"! Для выражения благодарности существуют ПС и репутация! Соблюдайте Правила! Распространенье наше по планете Особенно заметно вдалеке: В общественном парижском туалете Есть надписи на русском языке В. Высоцкий |
![]() |
![]() |
# 5 | |
Full Member
Регистрация: 20.01.2004
Адрес: Таллинн
Пол: Male
Сообщения: 623
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Я не думал о том, что у пятёрки вероятность равна 5%.
У меня просто выпадения с разной вероятностью. Чем больше цыфра, тем чаще будет выпадать. добавлено через 4 минуты Цитата:
надо проверять. ЗЫ. Проверил в экселе. Работает. Правда разбросы большие. Один раз из пятидесяти попыток 5 выпадает в шесть раз чаще, при другом запуске может быть только в два-три раза чаще. Последний раз редактировалось EvroStandart; 22.01.2010 в 13:01. Причина: проверил |
|
![]() |
![]() |
# 6 | |
СуперМод
IMHO Консультант 2005-2009 Регистрация: 14.08.2002
Адрес: Московская ПЛ, ракетный отс
Пол: Male
Сообщения: 14 495
![]() |
не самый лучший метод проверки, мягко говоря...
Цитата:
Алгоритм с вычитанием - фактически деление единичного отрезка на участки с длинами, соответствующими вероятностям выпадения чисел. Сортировка и вычитание - для упрощения алгоритма, не более того. Определяем, в какой из "участков вероятностей" попало наше случайное число. Со слов воспринять довольно трудно, но можно попробовать нарисовать... ![]() P.S. Случай на картинке соответствует попаданию случайного числа точно в границу двух участков.
__________________
Не засоряйте форум "спасибами"! Для выражения благодарности существуют ПС и репутация! Соблюдайте Правила! Распространенье наше по планете Особенно заметно вдалеке: В общественном парижском туалете Есть надписи на русском языке В. Высоцкий |
|
![]() |
![]() |
# 8 | |
СуперМод
IMHO Консультант 2005-2009 Регистрация: 14.08.2002
Адрес: Московская ПЛ, ракетный отс
Пол: Male
Сообщения: 14 495
![]() |
Цитата:
Погрешность вычислений - определяется типом данных и используемой математической библиотекой. Для типа данных c# "decimal", к примеру, составляет порядка 10^-27 (если я ничего не путаю). Хотя, повторюсь, если всё делать "по-честному", то при соблюдении пропорциональности ноль не выпадет никогда, ибо вероятность этого события равна (0*1/15) что согласно простейшей арифметике равно нулю. И хоть вы тресните - именно нулю, а не (6*10^-27), как получается при преднамеренном искажении логики программы...
__________________
Не засоряйте форум "спасибами"! Для выражения благодарности существуют ПС и репутация! Соблюдайте Правила! Распространенье наше по планете Особенно заметно вдалеке: В общественном парижском туалете Есть надписи на русском языке В. Высоцкий |
|
![]() |
![]() |
# 9 |
Guest
Сообщения: n/a
|
Спасибо за предложенные варианты... Но, боюсь, такие алгоритмы будут тяжеловаты (в плане времени выполнения и вообще выполнимости) для моей программы.
Проблема заключается в том, что изначально массив забит нулями. А в процессе работы (при проводении сотен или даже тысяч итераций) его значения должны меняться. Я придумал возможный выход из такого положения, но хотелось бы услышать мнение экспертов, так сказать ![]() Random ran = new Random(); int count = ran.Next(0, var.Sum()); int s = 0, giv = 0; for(int i = 0; i < var.lenght; i++) { if(сount <= s) {giv = var[i]; break;} s+= var[i]; } Таким образом у нас будет сумма чисел, разбитая на кусочки, в один из которых должен угодить рандом. Как только мы видим, что рандомное число меньше начала следующего кусочка, берем число с индексом предыдущего и получаем как раз то, что нам требовалось выбрать. Вроде бы, вероятности при этом не искажаются, но хочется быть уверенным. Последний раз редактировалось Ran; 22.01.2010 в 22:29. |
![]() |
# 10 | ||
СуперМод
IMHO Консультант 2005-2009 Регистрация: 14.08.2002
Адрес: Московская ПЛ, ракетный отс
Пол: Male
Сообщения: 14 495
![]() |
Цитата:
![]() Мой алгоритм полностью соответствует постановке задачи (как я её понял из первого поста топика). Он возвращает случайный элемент массива с пропорциональной значению элемента вероятностью (для элементов с нулевым значением - с пренебрежимо малой фиксированной вероятностью, если брать модифицированный алгоритм). Насчёт "тяжести" - да, есть такое дело. С ростом количества элементов массива чисел объём вычислений возрастает по экспоненте. "Прелести" вероятностных расчётов... Для количества элементов массива в пределах 1000 - вполне быстро вычисляемо для более-менее современного компьютера. А если, скажем, ещё и CUDA задействовать, так и вообще до 100000 элементов без особых проблем... Чего и как Цитата:
Код чуть ниже и его описание я тоже понять не могу... Простите, но говоря об алгоритме - приводите пример алгоритма, а не кусок кода с туманными пояснениями... Да и задачу чётче формулируйте, ибо "правильно сформулированный вопрос содержит половину ответа"...
__________________
Не засоряйте форум "спасибами"! Для выражения благодарности существуют ПС и репутация! Соблюдайте Правила! Распространенье наше по планете Особенно заметно вдалеке: В общественном парижском туалете Есть надписи на русском языке В. Высоцкий |
||
![]() |
![]() |
# 11 |
Guest
Сообщения: n/a
|
Понимаю, что вопрос прозвучит не в тему, но все же...
Random в C# видимо выдает случайное число, ориентируясь на время, поэтому он выдает несколько одинаковых чисел подряд. Это легко проверить, запустив рандом в цикле и записав результаты в массив. Вот и хотелось бы знать, существует ли в C# получать все-таки разные числа, пусть и таким способом. |
![]() |
# 12 |
мод
IMHO Кодер-200(6,7,8) Регистрация: 29.03.2003
Адрес: Saint-Petersburg, Russia
Пол: Male
Сообщения: 2 734
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
__________________
Я делаю Линукс! Присоединяйтесь к свободным людям! Связаться со мной всегда можно по джабберу: Hubbitus@jabber.ru Pahan-Hubbitus. |
![]() |
![]() |
# 13 |
Guest
Сообщения: n/a
|
Именно потому, что я его инициализирую временем у меня и получается несколько одинаковых чисел подряд
![]() ![]() |
![]() |
# 14 |
мод
IMHO Кодер-200(6,7,8) Регистрация: 29.03.2003
Адрес: Saint-Petersburg, Russia
Пол: Male
Сообщения: 2 734
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Так инициализировать надо один раз, перед циклом (в конструкторе, или вообще перед запуском программы, если глобальный объект), а дальше уже в цикле получать случайные числа.
__________________
Я делаю Линукс! Присоединяйтесь к свободным людям! Связаться со мной всегда можно по джабберу: Hubbitus@jabber.ru Pahan-Hubbitus. Последний раз редактировалось Hubbitus; 30.01.2010 в 19:06. Причина: очепятки |
![]() |