Як я можу зробити "випадковий" генератор, упереджений попередніми подіями?


37

Я хочу впровадити систему, засновану на шансах, яка упереджена попередньою подією

Передісторія: Деякі роки тому я пам’ятаю оновлення для World of Warcraft, яке оголосило, що вони впровадили новий калькулятор шансів, який би протидіяв колосальним ланцюжкам подій. (наприклад, критичні удари або ухилення від удару кілька разів поспіль). Ідея полягала в тому, що у випадку, коли ви ухилитесь від удару, шанс, що ви ухилитесь від наступного удару, зменшиться, але це буде працювати обома способами. Не ухилення від удару однаково збільшить шанс ухилення від наступного удару. Основна хитрість тут полягала в тому, що протягом декількох випробувань шанс ухилення все одно буде відповідати відсотку, який надається гравцеві в його або його статистичному аркуші.

Така система мене дуже сильно заінтригувала у той час, і зараз я знаходжусь у ситуації, коли мені потрібно таке рішення.

Ось мої неприємності:

  • Я здогадуюсь, що мені вдалося б знайти ресурси в Інтернеті щодо впровадження такої системи, але, можливо, мені не вистачає відповідних слів для її пошуку.
  • Також мені потрібен такий підхід, щоб відповідати системі, яка не є двочленною (тобто двома результатами), а натомість містить 4 взаємовиключні події.

Мій поточний підхід схожий на систему розіграшу квитків. Коли відбувається подія, я змінюю ваги на користь усіх інших подій. Це могло б спрацювати, якби чотири події мали бути однаково вірогідними, але, в моєму випадку, потребуватимуть набагато більшого поширення. Але оскільки найпоширеніша подія трапляється частіше, вона зміщує ваги іншого набагато вище, ніж було призначено, і я не можу знайти цифри для вагових зрушень, необхідних для утримання середнього рахунку квитків навколо початкових значень, що були у події дано.

Кілька покажчиків напрямку або чіткий приклад вирізання будуть дуже вдячні.


4
Якщо ви хочете отримати високотонкі або витончені відповіді, ви, можливо, матимете більше удачі, запитавши в Mathematics.SE. Математикам там зручно відповідати на складні запитання щодо ймовірності. math.stackexchange.com
Кевін -


6
Альтернативою сайту Математика, де ви, швидше за все, зрозумієте відповіді, є Programmers.SE . Дизайн алгоритму не є особливо тематичним з математики, і вам, мабуть, потрібно буде придумати початковий дизайн, щоб отримати корисний внесок.
Ліліенталь

1
Я погоджуюся з Кевіном та Ліліенталем, що ви можете отримати кращу відповідь там, але, прочитавши відповідь mklingen, я зрозумів, що тут описано, можна змоделювати як ланцюжок Маркова, і це може бути зручним інструментом для розробників ігор. Я спробую це написати докладніше пізніше.
nwellcome

1
По мірі того, як я наводив цифри на деякі відповіді тут, я знаходжу, що існує ряд різних обмежень, і рішення, яке вирішує всі вони, може бути мені складніше, ніж те, що вам потрібно. Деякі детальніші відомості щодо вашої справи можуть допомогти скоротити найкращі варіанти. Наприклад, чи досить схожі ймовірності ваших подій (наприклад, 5 різних результатів із 20% шансом на кожну), чи дуже різні (наприклад, 10% промахнеться, 80% потрапили в 10% критично)? Ви хочете звести до мінімуму пробіжки (наприклад, 3 промахи поспіль) або скупчення / очікування (наприклад, 3 промахи з 8 спроб або 20 спроб, перш ніж я отримаю критичне значення)?
DMGregory

Відповіді:


19

В основному те, що ви просите, це "напіввипадковий" генератор подій, який генерує події з такими властивостями:

  1. Середня швидкість, з якою відбувається кожна подія, зазначається заздалегідь.

  2. Одна і та ж подія рідше відбудеться двічі поспіль, ніж це було б навмання.

  3. Події не є повністю передбачуваними.

Один із способів зробити це спочатку реалізувати генератор випадкових подій, який задовольняє цілі 1 і 2, а потім додати деяку випадковість для задоволення мети 3.


Для генератора невипадкових подій ми можемо використовувати простий алгоритм відмирання . Зокрема, нехай p 1 , p 2 , ..., p n - відносна ймовірність подій 1 до n , а s = p 1 + p 2 + ... + p n - сума ваг. Потім ми можемо генерувати невипадкову максимально рівнорозподілену послідовність подій за допомогою наступного алгоритму:

  1. Спочатку нехай e 1 = e 2 = ... = e n = 0.

  2. Щоб генерувати подію, збільшуйте кожен е i на p i та виводите подію k, для якої e k найбільша (розрив зв'язків будь-яким способом).

  3. Зменшення e k на s і повторіть з кроку 2.

Наприклад, з урахуванням трьох подій A, B і C, с p A = 5, p B = 4 і p C = 1, цей алгоритм генерує щось на зразок наступної послідовності виходів:

A B A B C A B A B A A B A B C A B A B A A B A B C A B A B A

Зверніть увагу, як ця послідовність з 30 подій містить рівно 15 As, 12 Bs і 3 Cs. Це не зовсім оптимально розподіляє - є кілька випадків з двох Як підряд, яких можна було б уникнути - але воно наближається.


Тепер, щоб додати випадковість до цієї послідовності, у вас є кілька (не обов'язково взаємовиключних) варіантів:

  • Ви можете дотримуватися порад Філіпа і підтримувати "колоду" з N майбутніх подій для деякого числа N відповідного розміру . Кожен раз, коли вам потрібно генерувати подію, ви вибираєте випадкову подію з колоди, а потім замінюєте її на наступний висновок події алгоритмом дитингування вище.

    Застосовуючи це до наведеного вище прикладу, з N = 3, наприклад:

    A B A B C A B B A B A B C A A A A B B A B A C A B A B A B A

    тоді як N = 10 дає більш випадковий вигляд:

    A A B A C A A B B B A A A A A A C B A B A A B A C A C B B B

    Зверніть увагу, як загальні події A і B закінчуються набагато більше пробігів через перетасування, тоді як рідкісні події C все ще досить добре розподілені.

  • Ви можете ввести деяку випадковість безпосередньо в алгоритм відмирання. Наприклад, замість збільшення e i на p i на кроці 2, ви можете збільшити його на p i × випадковий (0, 2), де випадковий ( a , b ) - рівномірно розподілений випадкове число між a і b ; це дасть вихід таким чином:

    A B B C A B A A B A A B A B A A B A A A B C A B A B A C A B

    або ви могли б збільшити e i на p i + випадково (- c , c ), що призведе до отримання (для c = 0,1 × s ):

    B A A B C A B A B A B A B A C A B A B A B A A B C A B A B A

    або, для c = 0,5 × s :

    B A B A B A C A B A B A A C B C A A B C B A B B A B A B C A

    Зверніть увагу на те, як схема добавок має набагато сильніший рандомізуючий ефект для рідкісних подій С, ніж для загальних подій А і В, порівняно з мультиплікативною; це може бути або не бажано. Звичайно, ви також можете використовувати якусь комбінацію цих схем або будь-яке інше коригування приростів, якщо це зберігає властивість, середня приріст e i дорівнює p i .

  • Крім того, ви можете перешкодити виведенню алгоритму відмирання, іноді замінюючи вибрану подію k випадковою (обрану відповідно до необмеженої ваги p i ). Поки ви також використовуєте той же k на кроці 3, який ви виходите на етапі 2, процес дифірування все ще буде мати тенденцію до вирівнювання випадкових коливань.

    Наприклад, ось деякий приклад результату, з 10% шансом на те, що кожна подія буде обрана випадковим чином:

    B A C A B A B A C B A A B B A B A B A B C B A B A B C A B A

    і ось приклад з 50% шансом, що кожен вихід буде випадковим:

    C B A B A C A B B B A A B A A A A A B B A C C A B B A B B C

    Ви також можете розглянути можливість подачі суміші чисто випадкових і пошкоджених подій у колоду / пулу змішування, як описано вище, або, можливо, рандомізувати алгоритм відмирання, вибравши k випадковим чином, як зважили e i s (трактуючи негативні ваги як нуль).

Пс. Ось декілька абсолютно випадкових послідовностей подій, з однаковими середніми показниками для порівняння:

A C A A C A B B A A A A B B C B A B B A B A B A A A A A A A
B C B A B C B A A B C A B A B C B A B A A A A B B B B B B B
C A A B A A B B C B B B A B A B A A B A A B A B A C A A B A

Дотична: Оскільки в коментарях відбулася певна дискусія щодо того, чи потрібно, щоб рішення на основі палуби дозволяли колоді спорожнятися до її поповнення, я вирішив зробити графічне порівняння декількох стратегій заповнення колоди:

Plot
Сюжет декількох стратегій для генерування напів випадкових монетних перегородок (із співвідношенням головок до хвостів у середньому 50:50). Горизонтальна вісь - це кількість обертів, вертикальна вісь - це сукупна відстань від очікуваного відношення, вимірюється як (голови - хвости) / 2 = голови - відкидні / 2.

Червоні та зелені лінії на графіку показують два алгоритми, що не базуються на палубі, для порівняння:

  • Червона лінія, детерміновані відмирання : результати з парними нумераціями завжди є головами, результати з непарними номерами - це завжди хвости.
  • Зелена лінія, незалежні випадкові повороти : кожен результат вибирається самостійно, навмання, з 50% шансом на голову та 50% шансом на хвости.

Інші три рядки (синій, фіолетовий та блакитний) показують результати трьох стратегій на основі палуби, кожна реалізована за допомогою колоди з 40 карт, яка спочатку заповнюється 20 картками «голови» та 20 картками «хвости»:

  • Синя лінія, заповнення, коли порожня : Картки малюються випадковим чином, поки колода не буде порожньою, потім колоду поповнюють картками 20 «головок» та 20 картками «хвости».
  • Фіолетова лінія, заповнення, коли наполовину порожня : Картки витягуються випадковим чином, поки на колоді не залишиться 20 карт; потім настилають колоду з 10 картками «голова» та 10 картками «хвости».
  • Блакитна лінія, заповнення безперервно : Картки оформляються навмання; малюнки з парними нумераціями одразу замінюються карткою «голови», а непарні номери - карткою «хвости».

Звичайно, сюжет, наведений вище, - це лише одна реалізація випадкового процесу, але він є досить репрезентативним. Зокрема, ви бачите, що всі процеси, що базуються на палубі, мають обмежений ухил і залишаються досить близько до червоної (детермінованої) лінії, тоді як чисто випадкова зелена лінія зрештою відхиляється.

(Насправді відхилення синіх, фіолетових та блакитних ліній від нуля суворо обмежено розміром колоди: синя лінія ніколи не може відходити більше ніж на 10 кроків від нуля; фіолетова лінія може отримати лише 15 кроків від нуля і синя лінія може відхилятися не більше ніж за 20 кроків від нуля. Звичайно, на практиці будь-яка з ліній, що насправді досягають своєї межі, є вкрай малоймовірною, оскільки існує сильна тенденція повернутися ближче до нуля, якщо вони блукають занадто далеко вимкнено.)

На перший погляд, між різними стратегіями, що базуються на палубі, немає явної різниці (хоча, в середньому, синя лінія тримається дещо ближче до червоної лінії, а синя лінія тримається дещо далі), але більш уважний огляд синьої лінії виявляє чітку детерміновану схему: кожні 40 малюнків (позначені пунктирними сірими вертикальними лініями) синя лінія точно відповідає червоній лінії в нулі. Фіолетові та сині лінії не настільки суворо обмежені, і можуть триматися подалі від нуля в будь-якій точці.

Для всіх стратегій, що базуються на палубі, важливою особливістю, яка обмежує їх зміни, є той факт, що, хоча картки витягуються з колоди випадковим чином, колода поповнюється детерміновано. Якби картки, які використовувались для поповнення колоди, самі були обрані випадковим чином, усі стратегії, що базуються на палубі, стали б не відрізнятись від чистого випадкового вибору (зелена лінія).


Дуже чітка відповідь. Додавання випадкових факторів до алгоритму відмирання здається прямо вперед. :)
Sonaten

Вирішив піти з вашою відповіддю. :) Але я б рекомендував розмістити доповнення огляду методу вгорі. Що я збираюся зробити, виходячи з вашої відповіді, - це спробувати і рішення "Червоне" та "Фіолетове".
Sonaten

53

Не кидайте кістки, не торгуйте картками.

Візьміть усі можливі результати свого RNG, покладіть їх у список, перемішайте їх випадковим чином та поверніть результати у рандомізованому порядку. Коли ви будете в кінці списку, повторіть.

Результати все одно розподіляться рівномірно, але окремі результати не повторяться, якщо останній у списку також не стане першим із наступних.

Якщо це занадто передбачувано на ваш смак, ви можете використовувати список, який в nрази перевищує кількість можливих результатів, і nперед тим, як перемішувати, вводити кожен можливий результат у нього . Або ви можете змінити перелік, перш ніж його повністю повторити.


1
пошук "мішок перетасування" (навіть на цьому веб-сайті)
поштовх

3
Ось скільки ігор на тетріс уникають занадто довго залишати голодуючих за ключові п'єси. Важливо спорожнити мішок / настил, як пропонує Філіп, перед тим як вставляти нові картки, якщо ви хочете контролювати події протягом встановленого інтервалу. Повторно вставляючи картки під час руху (або переналагоджуючи ваги), ви можете спотворити розподіл ймовірностей способами, які важко обчислити та легко помилитися.
DMGregory

2
@DMGregory: Насправді цілком чудово змішувати нові картки до випорожнення колоди (і, власне, я б рекомендував робити це, щоб зробити результати більш природними та важче передбачити). Важливо - переконатися, що (середня) частка нових карт, переміщених у колоду, дорівнює бажаній частці, яку ви хочете витягнути з неї.
Ільмарі Каронен

4
Ілмарі Каронен: замінивши предмети, ви можете втратити переваги сумки перетасовки з точки зору обмеження пробігу однакових результатів або великого проміжку між окремими результатами. Якщо ваш коефіцієнт заміни дорівнює цільовому розподілу ймовірностей, ви, мабуть, перебуваєте в тому самому положенні, що і генерувати кожен результат незалежно, випадково. Якщо він не дорівнює цільовому розподілу ймовірностей, то ви можете викривити ефективні ймовірності способами, які важко передбачити і збалансувати відповідно - запитуючий описує, що бореться саме з цим питанням.
DMGregory

2
Погоджено з @DMGregory. Перетасовуючи нові картки, ви недійсні самій системі. Система карткових розсилок спеціально і ідеально підходить для бажаного результату. Наприклад, при видаленні ферзя (використовувати традиційні карти, наприклад) з колоди, ймовірність нанесення ферзя зменшується, а ймовірність нанесення карти інший , ніж королева збільшується. Це саморегулююча система, якщо ви хочете.
Volte

17

Ви можете спробувати випадковий графік Маркова . Розглянемо кожну подію, яка може статися вузлом у графі. З кожної події зробіть посилання на події, які можуть відбутися після неї. Кожне з цих посилань зважується через щось, що називається ймовірністю переходу . Потім ви виконуєте випадкову прогулянку графіка відповідно до моделі переходу.

Наприклад, у вас може бути графік, який відображає результат нападу (критичний удар, ухилення тощо). Ініціалізуйте стартовий вузол до одного, вибраного навмання, з урахуванням статистики гравця (просто «розкачайте кістки»). Потім, при наступній атаці, вирішіть, що буде далі з урахуванням перехідної моделі.

Необхідно уважно вирішити, як зважувати переходи. По-перше, всі переходи, що виходять з вузла, повинні додати до ймовірності 1. Одне просте, що ви могли зробити, - це зробити перехід від кожного вузла до кожного іншого вузла, з вагами, еквівалентними ймовірності того, що ці події відбудуться a priori , враховуючи, що поточна подія не може повторитися.

Наприклад, якщо у вас є три події:

  Critical, P = 0.1
  Hit,      P = 0.3
  Miss,     P = 0.6

Ви можете встановити перехідну модель таким чином, щоб критичний удар не повторився, просто розподіливши свою ймовірнісну масу на інші події рівномірно:

  Critical -> Critical,   P = 0.0
  Critical -> Hit,        P = 0.35
  Critical -> Miss,       P = 0.65

EDIT: Як говориться в коментарях нижче, ця модель не є достатньо складною, щоб отримати бажану поведінку. Натомість вам, можливо, доведеться додати кілька додаткових станів!


1
Запропонована вами схема повторного зважування не зберігає бажаних ймовірностей кожного стану. Здійснюючи емпіричний тест з цими числами, промахи трапляються приблизно 41% часу, а критичні - близько 25%, віддаляючи від вхідних значень. Перехід до решти штатів, пропорційний їх ймовірності (наприклад, у міс є 25% шансів перейти на Крит і 75% шансу потрапити в хіт), є дещо кращим, із 44% втратою та 17% критикою, але все одно не відображає бажаних ймовірностей на вході.
DMGregory

Я забув правило Байеса :( Перерахунок повторюватиметься пізніше. Можливо, не вдасться зберегти попередній розподіл ймовірностей, оскільки перехідна модель у міру її виходу залишає можливі послідовності, такі як CCHM або CHHM або дуже ймовірні MMMM тощо.
mklingen

Тут обмеження "не повторюється" може пов'язувати ваші руки, що стосується надзвичайно високих та низьких ваг. Якщо ви хочете, щоб 1 з 10 спроб виявився критичним, єдиний спосіб цього методу можна зустріти - це чергування 5 промаху та 5 звернень, що спотворює ймовірність потрапляння та пропуску на середню. Жодна послідовність без послідовних промахів не може задовольнити вимоги введених тут даних.
DMGregory

4
@mklingen, я згоден з DMGregory, "суворо не повторюється" тут небажано. Швидше вони хочуть, щоб ймовірність довгих ланцюгів одного і того ж результату була менш ймовірною, ніж це було б при рівномірній випадковій ймовірності. Ви можете зробити це з допомогою ланцюга Маркова (яка спрямована) , який виглядає як це . Це використовує кілька станів для подання повторних подій, коли ймовірність переходу з "Хіт 1" на "Хіт 2" і "Хіт 2" на "Хіт 3+" знижується, а ймовірність переходу назад до "Хіт 1" і "Крит" 1 "йти вгору.
nwellcome

@nwellcome, це чудова ідея.
mklingen

3

Ось реалізація, яку я створив у C #, яка:

  • Активуйте події на основі ймовірностей
  • Відрегулюйте ці ймовірності, щоб зменшити шанси на повторювані події
  • Не занадто далеко від початкових вірогідностей

Я додав кілька коментарів, щоб ви могли бачити, що я роблю.

    int percentageEvent1 = 15; //These are the starter values. So given a scenario, the
    int percentageEvent2 = 40; //player would have around a 15 percent chance of event
    int percentageEvent3 = 10; //one occuring, a 40 percent chance of event two occuring
    int percentageEvent4 = 35; //10 percent for event three, and 35 percent for event four.

    private void ResetValues()
    {
        percentageEvent1 = 15;
        percentageEvent2 = 40;
        percentageEvent3 = 10;
        percentageEvent4 = 35;
    }

    int resetCount = 0; //Reset the probabilities every so often so that they don't stray too far.

    int variability = 1; //This influences how much the chance of an event will increase or decrease
                           //based off of past events.

    Random RandomNumberGenerator = new Random();

    private void Activate() //When this is called, an "Event" will be activated based off of current probability.
    {
        int[] percent = new int[100];
        for (int i = 0; i < 100; i++) //Generate an array of 100 items, and select a random event from it.
        {
            if (i < percentageEvent1)
            {
                percent[i] = 1; //Event 1
            }
            else if (i < percentageEvent1 + percentageEvent2)
            {
                percent[i] = 2; //Event 2
            }
            else if (i < percentageEvent1 + percentageEvent2 + percentageEvent3)
            {
                percent[i] = 3; //Event 3
            }
            else
            {
                percent[i] = 4; //Event 4
            }
        }
        int SelectEvent = percent[RandomNumberGenerator.Next(0, 100)]; //Select a random event based on current probability.

        if (SelectEvent == 1)
        {
            if (!(percentageEvent1 - (3 * variability) < 1)) //Make sure that no matter what, probability for a certain event
            {                                                //does not go below one percent.
                percentageEvent1 -= 3 * variability;
                percentageEvent2 += variability;
                percentageEvent3 += variability;
                percentageEvent4 += variability;
            }
        }
        else if (SelectEvent == 2)
        {
            if (!(percentageEvent2 - (3 * variability) < 1))
            {
                percentageEvent2 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent3 += variability;
                percentageEvent4 += variability;
            }
        }
        else if (SelectEvent == 3)
        {
            if (!(percentageEvent3 - (3 * variability) < 1))
            {
                percentageEvent3 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent2 += variability;
                percentageEvent4 += variability;
            }
        }
        else
        {
            if (!(percentageEvent4 - (3 * variability) < 1))
            {
                percentageEvent4 -= 3 * variability;
                percentageEvent1 += variability;
                percentageEvent2 += variability;
                percentageEvent3 += variability;
            }
        }

        resetCount++;
        if (resetCount == 10)
        {
            resetCount = 0;
            ResetValues();
        }

        RunEvent(SelectEvent); //Run the event that was selected.
    }

Сподіваюсь, це допоможе, будь ласка, запропонуйте покращити цей код у коментарях, дякую!


1
Ця схема повторного зважування, як правило, призводить до того, що події є беззаперечними. Періодичне скидання ваг насправді є лише пов'язкою, яка обмежує, наскільки це погано, при цьому гарантуючи, що 1 з 10 рулонів взагалі не отримає користі від повторної ваги. Також одна примітка алгоритму: ви витрачаєте багато роботи, заповнюючи таблицю з 100 записів, щоб зробити свій випадковий вибір. Натомість ви можете генерувати випадковий відкат, а потім повторити свої 4 результати, підсумовуючи їх ймовірності в процесі роботи. Як тільки перелік менше суми, у вас є результат. Не потрібно заповнення таблиці.
DMGregory

3

Дозвольте трохи узагальнити відповідь mklingen . В основному, ви хочете реалізувати помилковість Азартного гравця , хоча тут я запропоную більш загальний метод:

Скажіть, nможливі події з вірогідністю p_1, p_2, ..., p_n. Коли випадок iтрапився, його ймовірність повинна змінюватися з коефіцієнтом 0≤a_i≤1/p_i(останній важливий, інакше у вас виявляється ймовірність, більша за одну, а інші події повинні мати негативні ймовірності , що в основному означає " анти " -події. Або щось), хоча як правило a_i<1. Ви можете, наприклад, вибрати a_i=p_i, що означає, що ймовірність того, що подія відбудеться вдруге, - це початкова ймовірність того, що подія відбудеться точно два рази поспіль, наприклад, друга кидання монети матиме ймовірність 1/4 замість 1/2. З іншого боку, у вас також можуть бути деякі a_i>1, що означало би спричинити "удару / нещастя".

Усі інші події залишаються однаково ймовірними відносно один одного, тобто всі вони повинні бути перераховані одним і тим же фактором b_i , щоб сума всіх ймовірностей дорівнювала одиниці, тобто

1 = a_i*p_i + b_i*(1-p_i)  # Σ_{j≠i) p_j  = 1 - p_i
 b_i = (1 - a_i*p_i) / (1 - p_i).   (1)

Поки так просто. Але тепер додамо ще одну вимогу: враховуючи всі можливі послідовності двох подій, вилучені з них ймовірності одного події мають бути вихідними ймовірностями.

Дозволяє

        / p_i * b_i * p_j  (ji)
p_ij = <
        \ a_i * (p_i     (j=i)

позначають ймовірність того, що подія jстанеться після події, iі зауважте, що p_ij≠p_jiякщо b_i=b_j (2)(що (1)означає a_j = 1 - a_i*p_i + (1-a_i)*p_i/p_j). Це також вимагає теорема Байєса, і це також має на увазі

Σ_j p_ij = p_i * b_i * (1 - p_i) + a_i * (p_i
         = b_i * p_i + (a_i - b_i) * (p_i
         = p_i  # using (1)

просто за бажанням. Просто зауважте, як це означаєa_i фіксує всі інші.


Тепер давайте подивимося, що відбувається, коли ми застосовуємо цю процедуру кілька разів, тобто для послідовностей з трьох і більше подій. В основному є два варіанти вибору сфальсифікованих ймовірностей третьої події:

а) Забудьте про першу подію та встановіть так, ніби тільки відбулася друга, тобто

         / p_ij * a_j * p_j  (j=k)
p_ijk = <
         \ p_ij * b_j * p_l  (jk)

Зауважте, що це зазвичай порушує Байєса, оскільки напр p_jik≠p_ikj у більшості випадків.

b) Використовуйте використання ймовірностей p_ij(для фіксованих i) як нових ймовірностей, pi_jз яких ви отримуєте нові ймовірності pi_jkдля kнаступної події . Незалежно від того, чи змінюєте ви, ai_jчи ні, не залежить від вас, але пам’ятайте, що нове bi_j, безумовно, відрізняється завдяки модифікованому pi_j. Знову ж таки, вибір ai_j, ймовірно, обмежений, вимагаючи всіх перестановок, ijkщо відбуваються з однаковою ймовірністю. Подивимось ...

         / p_ij * bi_j * pi_k  (jk)
p_ijk = <
         \ (p_ij * ai_j      (j=k)

         / b_i * bi_j * p_i * p_j * pi_k  (ijki)
         | b_i * ai_j * p_i * (p_j      (ij=k)
      = <  a_i * (p_i * bi_i * pi_k     (i=jk)
         | b_i * p_i * bi_j * p_k * pi_i  (i=kj)
         \ a_i * ai_i * (p_i * pi_i     (i=k=j)

та їх циклічні перестановки, які повинні бути рівними для відповідних випадків.

Боюся, що моєму продовженню на це доведеться почекати деякий час ...


Випробувавши це емпірично, це все ще призводить до спотворення подалі від вхідних ймовірностей протягом багатьох пробігів. Наприклад, якщо a_i / p_i = 0,5, (і використовуючи номери з відповіді mklingen), частота пропуску входу 60% стає спостережуваною швидкістю 50,1%, а критична швидкість входу 10% спостерігається як 13,8%. Ви можете перевірити це, взявши отриману матрицю переходу до великої потужності. Вибір співвідношення a_i: p_i ближче до 1 призводить до менших спотворень, але й меншої ефективності у скороченні пробігів.
DMGregory

@DMGregory хороший момент: ви не можете просто взяти повноваження перехідної матриці. Пізніше я розгорну свою відповідь
Тобіас Кіенцлер

@DMGregory Я почав описувати повний процес (варіант b)), але він стає досить стомлюючим, і мені зараз не вистачає часу: /
Тобіас Кіенцлер

1

Я думаю, що найкращим варіантом є вибір довільно зважених елементів. Там в реалізації для C # тут , але вони можуть бути легко знайдені або зроблені для інших мов.

Ідея полягала б у тому, щоб зменшити вагу опціону кожного разу, коли він вибирається, і збільшувати його щоразу, коли він не вибирається.

Наприклад, якщо зменшити вагу вибраноїNumOptions-1 опції на 1 і збільшити вагу кожного іншого варіанта на 1 (обережно виймайте елементи з вагою <0 та читайте їх, коли вони піднімаються вище 0) , кожен варіант буде обраний приблизно стільки ж разів протягом тривалого періоду, але нещодавно вибрані варіанти будуть набагато рідше вибрані.


Проблема використання випадкового впорядкування, як це пропонується багатьма іншими відповідями, полягає в тому, що після того, як кожен варіант, окрім одного, був обраний, ви можете зі прогнозом на 100% передбачити, який варіант буде обраний далі. Це не дуже випадково.


1

Моя відповідь невірна, мій тест був помилковим.

Я залишаю цю відповідь тут для обговорення та коментарів, які вказують на недоліки в цій конструкції, але власне тест був неправильним.

Те, що ви шукаєте, є зваженою вагою: ваги для ваших чотирьох можливих результатів потрібно додатково відкоригувати (зважити) за попередніми результатами, залишаючись при цьому правильними вагами.

Найпростіший спосіб досягти цього - це змінити всі ваги для кожного рулону, зменшуючи вагу для питомої величини, котившись, і збільшуючи інші ваги .

Як приклад, скажімо, що у вас є 4 ваги: ​​Fumble, Miss, Hit та Crit. Дозвольмо також сказати, що бажані загальні ваги для них: Fumble = 10%, Miss = 50%, Hit = 30% та Crit = 10%.

Якщо ви використовуєте генератор випадкових чисел (RNG) для отримання значень між 1 і 100, а потім порівняйте це значення з тим, де воно потрапляє в цей діапазон (1-10 Fumble, 11-60 промах, 61-90 хіт, 91-100 критерій ), ви генеруєте індивідуальний список.

Якщо ви зробите цей рулон, ви негайно відрегулюєте ці діапазони, виходячи з наведеного значення, ви будете зважувати майбутні рулони, але вам також потрібно зменшити вагу прокату на ту ж загальну суму, на яку ви збільшите інші ваги. Отже, у нашому прикладі вище, ви б зменшили вагу катання на 3, а інші ваги збільшили на 1 кожен.

Якщо ви зробите це для кожного рулону, у вас все одно будуть шанси на прожилки, але вони значно зменшаться, тому що для кожного рулону ви збільшуєте шанс, що майбутні рулони будуть чим-небудь іншим, ніж те, що є поточним. Ви можете збільшити цей ефект і тим самим ще більше знизити ймовірність ударів, збільшуючи / зменшуючи ваги більшим фактором (наприклад, зменшити струм на 6 та збільшити інші на 2).

Я запустив швидкий додаток, щоб підтвердити такий підхід, і після 32000 ітерацій з цими вагами він дає наступні графіки. Верхній графік показує 4 негайних значення для кожного валу, а нижній графік показує підрахунок підсумків кожного типу результатів, згорнутих до цієї точки.

Як бачимо, ваги дещо коливаються навколо бажаних значень, але загальна вага залишається в межах бажаних діапазонів, і після того, як початкова різноманітність вихідних чисел відстоюється, результати майже повністю ідеально відповідають бажаним відсоткам.

Зауважте, що цей приклад був створений з використанням класу .NET System.Random, який насправді не є одним з кращих RNG, тому ви, ймовірно, можете отримати більш точні результати, використовуючи кращу RNG. Також зауважте, що 32000 - це максимальний результат, який я міг графікувати за допомогою цього інструменту, але мій тестовий інструмент зміг генерувати понад 500 мільйонів результатів з однаковими загальними моделями.


Зауважте, що це працює лише в тому випадку, якщо ваші позначки +1 / -3 застосовуються відносно початкових ваг, а не до останніх використовуваних ваг. (Постійно змінюючи ваги рівномірно, як це змушує їх рухатися до вирівнювання). Хоча це підтримує ймовірність націлювання на ціль у довгостроковій перспективі, це робить дуже мало для зменшення пробігів. Зважаючи на те, що я пропустив один раз, шанс, що я пропущу ще два рази поспіль, становить 22% при цій схемі, проти 25% при незалежних нічиях. Збільшення зсуву ваги для більшого ефекту (скажімо до + 3 / -9) призводить до зміщення ймовірності в довгостроковій перспективі.
DMGregory

Насправді дані, представлені вище, застосовують + 1 / -3 до останньої ваги щоразу, коли рулон обробляється. Отже, якщо ви пропустите один раз на початковій вазі 50%, наступна вага пропуску складе 47%, а якщо ви пропустите ще раз, наступна вага - 44% тощо. Це зменшує прогони (окремим показником було відстеження пробігів, виявлене аж на 24% зменшення пробігів), але вони все ще неминучі, оскільки ця схема все ще має великі шанси залишити кожен з 4 ваг з ненульовою ймовірністю ( напр., чотири критичні підряди залишать критичну вагу з нульовим шансом виникнення).
Девід С Елліс

Якщо це було вашим наміром, то у вашій реалізації є помилка. Подивіться на графік - Вага джгута лише коли-небудь підскакує між 7 і 11, без значень поза цим. Я запустив моделювання, використовуючи безперервну модифікацію, яку ви описуєте, і графіки різко відрізняються, ймовірність кожного стану сходиться до 25% у кожному з перших сотень випробувань.
DMGregory

Dangit, насправді це було помило, як ви вказали. Ну, вражте цю відповідь.
David C Ellis

@DavidCEllis Ви говорите, що ваша реалізація була помилковою, або сама ідея є? Моя інтуїція задньої прокладки прийшла приблизно до описаної вами моделі (відрегулюйте ймовірність вниз, коли вона намальована, поступово відновлюйте всі ймовірності до їх початкових значень з часом), і для мене це все ще має сенс.
dimo414

0

Ви можете зробити те, що по суті є фільтром. Слідкуйте за минулими російськими подіями. Ймовірність - деякий фільтр, застосований до цих подій. 0-й фільтр є базовою ймовірністю, якщо 0 тоді ви ухилилися, якщо 1 не вдалося. Скажімо, база становила 25%, а фільтр зменшується вдвічі за кожну ітерацію. Тоді ваш фільтр буде:

[.25 .125 .0625 .03125] 

Сміливо продовжуйте, якщо хочете. Загальна ймовірність цієї схеми трохи вище, ніж базова ймовірність .25. Насправді ймовірність за цією ж схемою є (я називаю x реальною ймовірністю, р - вхідною ймовірністю):

x=p+(1-x)*(p/2+p/4+p/8)

Рішення по й, один знаходить відповідь p(1+1/2+1/4+1/8)/(1+p(1/2+1/4+1/8), або для нашого даного випадку x=0.38461538461. Але те, що ви насправді хочете, - це знайти p, заданий x. Це виявляється більш важкою проблемою. Якщо ви припустили нескінченний фільтр, проблема стає x+x*p=2*p, або p=x/(2-x). Таким чином, збільшуючи свій фільтр, ви зможете вирішити на число p, яке в середньому дасть вам однакові результати, але зі швидкістю, залежною від того, наскільки успіх нещодавно відбувся.

В основному ви використовуєте попередні значення, щоб визначити, яким є поріг прийняття цього раунду, і приймаєте випадкове значення. Потім виробляють наступне випадкове значення, задане фільтром.


-1

Так само, як ви самі запропонували, один із підходів до цього - реалізувати зважений випадковий випадок. Ідея полягає у створенні генератора випадкових чисел (або результатів), де ваги та результати можуть бути змінені.

Ось реалізація цього на Java.

import java.util.Map;
import java.util.Random;

/**
 * A psuedorandom weighted outcome generator
 * @param <E> object type to return
 */
public class WeightedRandom<E> {

    private Random random;
    private Map<E, Double> weights;

    public WeightedRandom(Map<E, Double> weights) {
        this.random = new Random();
        this.weights = weights;
    }

    /**
     * Returns a random outcome based on the weight of the outcomes
     * @return
     */
    public E nextOutcome() {
        double totalweight = 0;

        // determine the total weigth
        for (double w : weights.values()) totalweight += w;

        // determine a value between 0.0 and the total weight
        double remaining = random.nextDouble() * totalweight;

        for (E entry : weights.keySet()) {
            // subtract the weight of this entry
            remaining -= weights.get(entry);

            // if the remaining is smaller than 0, return this entry
            if (remaining <= 0) return entry;
        }

        return null;
    }

    /**
     * Returns the weight of an outcome
     * @param outcome the outcome to query
     * @return the weight of the outcome, if it exists
     */
    public double getWeight(E outcome) {
        return weights.get(outcome);
    }

    /**
     * Sets the weight of an outcome
     * @param outcome the outcome to change
     * @param weight the new weigth
     */
    public void setWeight(E outcome, double weight) {
        weights.put(outcome, weight);
    }
}

EDIT У випадку, коли ви хочете автоматично регулювати ваги, наприклад, підвищити ймовірність A, коли результат був B. Ви можете або

  1. Змініть поведінку nextOutcome() методу, щоб він міняв вагу відповідно до результату
  2. Використовуйте setWeight()для зміни ваги відповідно до результату.

Я думаю, що ви, можливо, неправильно прочитали питання: ОП - це не питання про те, як генерувати зважені випадкові результати, а як скорегувати ваги, щоб зменшити ймовірність того, що той самий результат відбудеться кілька разів поспіль.
Ільмарі Каронен

Я бачу, я змінив частину своєї відповіді, щоб пояснити, як це можливо за допомогою цієї системи.
erikgaal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.