¿Cómo puedo hacer un generador "aleatorio" que esté sesgado por eventos anteriores?


37

Estoy buscando implementar un sistema basado en el azar que esté sesgado por un evento anterior.

Antecedentes: Hace algunos años, recuerdo una actualización para World of Warcraft que anunciaba que implementaron una nueva calculadora de probabilidad que contrarrestaría las cadenas de eventos puntiagudos. (por ejemplo, realizar golpes críticos o esquivar varias veces seguidas). La idea era que en el caso de que esquivaras un golpe, la posibilidad de que esquivaras el siguiente golpe disminuiría, pero funcionaría en ambos sentidos. No esquivar un golpe aumentaría igualmente la posibilidad de esquivar el siguiente golpe. El truco principal aquí, fue que durante varias pruebas, la posibilidad de esquivar aún correspondería al porcentaje dado al jugador en su hoja de estadísticas.

Este tipo de sistema me intrigó mucho en ese momento, y ahora estoy en la situación de necesitar tal solución.

Aquí están mis problemas:

  • Supongo que podría encontrar recursos en línea para implementar dicho sistema, pero es posible que me falten las palabras de moda relevantes para encontrarlo.
  • También necesito este enfoque para ajustar un sistema que no sea binomial (es decir, dos resultados), sino que contenga 4 eventos mutuamente excluyentes.

Mi enfoque actual es similar al de un sistema de boletos de rifa. Cuando ocurre un evento, cambio los pesos a favor de todos los demás eventos. Esto podría funcionar si los cuatro eventos fueran igualmente probables, pero en mi caso, las necesidades deben ser mucho más frecuentes. Pero a medida que el evento frecuente ocurre con más frecuencia, cambia los pesos del otro mucho más de lo previsto y parece que no puedo encontrar los números para los cambios de peso que se necesitan para mantener el recuento promedio de boletos alrededor de los valores iniciales del evento. dado.

Unos pocos indicadores de dirección o un ejemplo claro serían muy apreciados.


44
Si desea una respuesta altamente matizada o sofisticada, es posible que tenga más suerte preguntando en Mathematics.SE. Los matemáticos se sienten cómodos respondiendo preguntas complicadas sobre la probabilidad. math.stackexchange.com
Kevin - Restablece a Monica


66
Una alternativa al sitio de Matemáticas donde es más probable que comprenda las respuestas es Programmers.SE . El diseño de algoritmos no es particularmente sobre el tema en matemáticas y es probable que necesite un diseño inicial para obtener información útil.
Lilienthal

1
Estoy de acuerdo con Kevin y Lilienthal en que podría obtener una mejor respuesta allí, pero al leer la respuesta de mklingen me di cuenta de que lo que se describe aquí puede modelarse como una cadena de Markov y que podría ser una herramienta útil para los desarrolladores de juegos. Trataré de escribir eso con más detalle más adelante.
bienvenido

1
Como he estado ejecutando los números en algunas de las respuestas aquí, descubro que hay varias restricciones diferentes, y que una solución que las resuelva todas podría ser más compleja de lo que necesita. Algunos detalles más específicos sobre su caso de uso podrían ayudar a reducir las mejores opciones. Por ejemplo, ¿son las probabilidades de sus eventos bastante similares (p. Ej. 5 resultados diferentes con un 20% de probabilidad cada uno), o muy diferentes (p. Ej., El 10% falla el 80% golpea al 10% crítico)? ¿Desea minimizar las corridas (p. Ej., 3 fallas seguidas) o agrupaciones / esperas (p. Ej., 3 fallas de 8 intentos o 20 intentos antes de obtener un crítico)?
DMGregory

Respuestas:


19

Básicamente, lo que está pidiendo es un generador de eventos "semi-aleatorio" que genere eventos con las siguientes propiedades:

  1. La tasa promedio a la que ocurre cada evento se especifica de antemano.

  2. Es menos probable que ocurra el mismo evento dos veces seguidas de lo que sería al azar.

  3. Los eventos no son completamente predecibles.

Una forma de hacerlo es implementar primero un generador de eventos no aleatorio que satisfaga los objetivos 1 y 2, y luego agregar algo de aleatoriedad para satisfacer el objetivo 3.


Para el generador de eventos no aleatorio, podemos usar un algoritmo de interpolación simple . Específicamente, sea p 1 , p 2 , ..., p n las probabilidades relativas de los eventos 1 a n , y sea s = p 1 + p 2 + ... + p n la suma de los pesos. Luego podemos generar una secuencia no aleatoria de eventos con la máxima equidistribución utilizando el siguiente algoritmo:

  1. Inicialmente, sea e 1 = e 2 = ... = e n = 0.

  2. Para generar un evento, incremente cada e i por p i , y genere el evento k para el cual e k es más grande (rompiendo los lazos de la forma que desee).

  3. Disminuya e k por s , y repita desde el paso 2.

Por ejemplo, dados tres eventos A, B y C, con p A = 5, p B = 4 y p C = 1, este algoritmo genera algo así como la siguiente secuencia de salidas:

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

Observe cómo esta secuencia de 30 eventos contiene exactamente 15 As, 12 Bs y 3 Cs. No es bastante óptima distribuye - hay algunas ocurrencias de dos como en una fila, que podría haber sido evitado - pero se acerca.


Ahora, para agregar aleatoriedad a esta secuencia, tiene varias opciones (no necesariamente mutuamente excluyentes):

  • Puede seguir los consejos de Philipp y mantener un "mazo" de N próximos eventos, para un número N de tamaño apropiado . Cada vez que necesita generar un evento, elige un evento aleatorio del mazo y luego lo reemplaza con el siguiente evento de salida por el algoritmo de difuminado anterior.

    Aplicando esto al ejemplo anterior, con N = 3, produce, por ejemplo:

    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

    mientras que N = 10 produce el aspecto más aleatorio:

    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

    Tenga en cuenta cómo los eventos comunes A y B terminan con muchas más carreras debido a la combinación, mientras que los eventos C raros todavía están bastante bien espaciados.

  • Puede inyectar algo de aleatoriedad directamente en el algoritmo de interpolación. Por ejemplo, en lugar de incrementar e i por p i en el paso 2, podría incrementarlo por p i × random (0, 2), donde random ( a , b ) es un número aleatorio distribuido uniformemente entre a y b ; esto produciría resultados como los siguientes:

    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

    o podría incrementar e i por p i + random (- c , c ), lo que produciría (para 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

    o, para 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

    Observe cómo el esquema aditivo tiene un efecto de aleatorización mucho más fuerte para los eventos raros C que para los eventos comunes A y B, en comparación con el multiplicativo; esto puede o no ser deseable. Por supuesto, también podría usar alguna combinación de estos esquemas, o cualquier otro ajuste a los incrementos, siempre que conserve la propiedad de que el incremento promedio de e i es igual a p i .

  • Alternativamente, podría perturbar la salida del algoritmo de interpolación reemplazando a veces el evento k elegido por uno aleatorio (elegido de acuerdo con los pesos brutos p i ). Siempre y cuando también use la misma k en el paso 3 que la salida en el paso 2, el proceso de interpolación aún tenderá a igualar las fluctuaciones aleatorias.

    Por ejemplo, aquí hay algunos resultados de ejemplo, con un 10% de posibilidades de que cada evento sea elegido al azar:

    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

    y aquí hay un ejemplo con un 50% de posibilidades de que cada salida sea aleatoria:

    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

    También podría considerar alimentar una mezcla de eventos puramente aleatorios y difusos en una plataforma / grupo de mezcla, como se describió anteriormente, o tal vez aleatorizar el algoritmo de interpolación eligiendo k aleatoriamente, según lo ponderado por los e i s (tratando los pesos negativos como cero).

PD. Aquí hay algunas secuencias de eventos completamente al azar, con las mismas tasas promedio, para comparar:

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

Tangente: Dado que en los comentarios se ha debatido si es necesario, para las soluciones basadas en plataformas, permitir que la plataforma se vacíe antes de que se vuelva a llenar, decidí hacer una comparación gráfica de varias estrategias de relleno de plataformas:

Trama
Trama de varias estrategias para generar lanzamientos de monedas semialeatorios (con una proporción de 50:50 de cara a cruz en promedio). El eje horizontal es el número de vueltas, el eje vertical es la distancia acumulativa de la relación esperada, medida como (caras - colas) / 2 = caras - vueltas / 2.

Las líneas rojas y verdes en la gráfica muestran dos algoritmos no basados ​​en mazos para comparación:

  • Línea roja, tramado determinista : los resultados pares son siempre cara, los resultados impares son siempre colas.
  • Línea verde, cambios aleatorios independientes : cada resultado se elige de forma independiente al azar, con un 50% de posibilidades de caras y un 50% de posibilidades de colas.

Las otras tres líneas (azul, morado y cian) muestran los resultados de tres estrategias basadas en mazos, cada una implementada usando un mazo de 40 cartas, que inicialmente se llena con 20 cartas "caras" y 20 cartas "colas":

  • Línea azul, rellenar cuando está vacío : las cartas se roban al azar hasta que el mazo esté vacío, luego el mazo se rellena con 20 cartas de "cabezas" y 20 cartas de "colas".
  • Línea púrpura, llene cuando esté medio vacío : las cartas se roban al azar hasta que el mazo tenga 20 cartas restantes; entonces el mazo se completa con 10 cartas de "cabezas" y 10 cartas de "colas".
  • Línea cian, rellena continuamente : las cartas se roban al azar; los sorteos pares se reemplazan inmediatamente con una carta de "cara" y los sorteos impares con una carta de "colas".

Por supuesto, la trama anterior es solo una realización única de un proceso aleatorio, pero es razonablemente representativa. En particular, puede ver que todos los procesos basados ​​en mazos tienen un sesgo limitado y se mantienen bastante cerca de la línea roja (determinista), mientras que la línea verde puramente aleatoria finalmente se desvía.

(De hecho, la desviación de las líneas azul, púrpura y cian lejos de cero está estrictamente limitada por el tamaño de la plataforma: la línea azul nunca puede alejarse más de 10 pasos de cero, la línea púrpura solo puede alejarse 15 pasos de cero , y la línea cian puede desplazarse como máximo 20 pasos desde cero. Por supuesto, en la práctica, cualquiera de las líneas que realmente alcancen su límite es extremadamente improbable, ya que existe una fuerte tendencia a que vuelvan más cerca de cero si se alejan demasiado. apagado.)

De un vistazo, no hay una diferencia obvia entre las diferentes estrategias basadas en mazos (aunque, en promedio, la línea azul se mantiene algo más cerca de la línea roja, y la línea cian se mantiene un poco más lejos), pero una inspección más cercana de la línea azul revela un patrón determinista distinto: cada 40 dibujos (marcados por las líneas verticales grises punteadas), la línea azul se encuentra exactamente con la línea roja en cero. Las líneas moradas y cian no están tan estrictamente restringidas y pueden mantenerse alejadas de cero en cualquier punto.

Para todas las estrategias basadas en mazos, la característica importante que mantiene limitada su variación es el hecho de que, mientras las cartas se sacan del mazo al azar, el mazo se rellena de manera determinista. Si las cartas utilizadas para rellenar el mazo fueran elegidas al azar, todas las estrategias basadas en el mazo serían indistinguibles de la elección aleatoria pura (línea verde).


Respuesta muy elaborada. Agregar factores aleatorios al algoritmo de interpolación parece sencillo. :)
Sonaten

Decidí ir con tu respuesta. :) Pero recomendaría que coloque las adiciones de la descripción general del método en la parte superior. Lo que voy a hacer, en función de su respuesta, es probar tanto la solución "Roja" como la "Púrpura".
Sonaten

53

No tires dados, reparte cartas.

Tome todos los resultados posibles de su RNG, colóquelos en una lista, revuélvalos aleatoriamente y devuelva los resultados en el orden aleatorio. Cuando esté al final de la lista, repita.

Los resultados aún se distribuirán de manera uniforme, pero los resultados individuales no se repetirán a menos que el último de la lista también sea el primero del siguiente.

Cuando esto sea demasiado predecible para su gusto, puede usar una lista que sea nel número de resultados posibles y poner cada resultado posible en ellos nantes de barajar. O podría reorganizar la lista antes de que se repita por completo.


1
buscar "shuffle bag" (incluso en este sitio)
jhocking

3
Así es como muchos juegos de Tetris evitan dejar al jugador hambriento de piezas clave durante demasiado tiempo. Es importante vaciar la bolsa / cubierta como sugiere Philipp antes de insertar nuevas cartas si desea controlar las ocurrencias durante un intervalo establecido. Al volver a insertar las tarjetas a medida que avanza (o reajustar los pesos), puede distorsionar la distribución de probabilidad de formas que son difíciles de calcular y fáciles de equivocar.
DMGregory

2
@DMGregory: En realidad, está perfectamente bien mezclar nuevas cartas antes de que se vacíe el mazo (y, de hecho, recomendaría hacer esto para que los resultados sean más naturales y difíciles de predecir). Lo importante es asegurarse de que la fracción (promedio) de las nuevas cartas barajadas en la cubierta es igual a la fracción deseada que desea dibujar fuera de ella.
Ilmari Karonen

44
Illmari Karonen: cuando reemplaza artículos, puede perder los beneficios de la bolsa de barajar en términos de limitar las corridas de resultados idénticos o brechas largas entre resultados particulares. Si su tasa de reemplazo es igual a la distribución de probabilidad objetivo, ahora es probable que esté en la misma posición que generar cada resultado de forma independiente al azar. Si no es igual a la distribución de probabilidad objetivo, puede deformar las probabilidades efectivas de manera que sean difíciles de predecir y equilibrar en consecuencia: el autor de la pregunta describe la lucha con exactamente este problema.
DMGregory

2
De acuerdo con @DMGregory. Al barajar nuevas tarjetas, invalidas el sistema mismo. El sistema de reparto de cartas es específico y perfectamente adecuado para el resultado deseado. Por ejemplo, cuando eliminas una reina (para usar cartas tradicionales, por ejemplo) del mazo, la probabilidad de robar una reina disminuye y la probabilidad de robar una carta que no sea ​​una reina aumenta. Es un sistema autoajustable, por así decirlo.
Volte

17

Puedes probar un gráfico aleatorio de Markov . Considere cada evento que puede ocurrir como un nodo en un gráfico. Desde cada evento, haga un enlace entre sí que posiblemente pueda venir después. Cada uno de estos enlaces está ponderado por algo llamado probabilidad de transición . Luego, realiza una caminata aleatoria del gráfico de acuerdo con el modelo de transición.

Por ejemplo, puede tener un gráfico que represente el resultado de un ataque (golpe crítico, esquivar, etc.). Inicialice el nodo inicial a uno elegido al azar, dadas las estadísticas del jugador (simplemente "tire los dados"). Luego, en el próximo ataque, decida qué sucede después dado el modelo de transición.

Se debe tener cuidado para decidir cómo ponderar las transiciones. Por un lado, todas las transiciones que salen de un nodo deben sumar una probabilidad de 1. Una cosa simple que podría hacer es hacer una transición de cada nodo a cualquier otro nodo, con pesos equivalentes a la probabilidad de que ocurran esos eventos. a priori , dado que el evento actual no puede volver a ocurrir.

Por ejemplo, si tiene tres eventos:

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

Puede configurar el modelo de transición de modo que un golpe crítico no vuelva a ocurrir simplemente redistribuyendo su masa de probabilidad a los otros eventos de manera uniforme:

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

EDITAR: como dicen los comentarios a continuación, este modelo no es lo suficientemente complicado como para obtener el comportamiento deseado. En su lugar, es posible que deba agregar varios estados adicionales.


1
El esquema de reponderación que propone no conserva las probabilidades deseadas de cada estado. Al hacer una prueba empírica con estos números, las fallas ocurren aproximadamente el 41% del tiempo y las críticas alrededor del 25%, muy por encima de los valores de entrada. La transición a los estados restantes proporcional a sus probabilidades (p. Ej., Miss tiene un 25% de posibilidades de ir a Crit y un 75% de posibilidades de ir a Hit) es un poco mejor, con una tasa de fallas del 44% y un 17% de críticos, pero aún así no refleja las probabilidades deseadas en la entrada.
DMGregory

Olvidé la regla de Bayes :( Volverá a calcular de nuevo más tarde. Puede que no sea posible mantener la distribución de probabilidad previa porque el modelo de transición tal como está, deja fuera posibles secuencias como CCHM o CHHM o el muy probable MMHM, etc.
mklingen

La restricción de "no repeticiones" podría unir sus manos aquí, con respecto a los pesos extremos altos y bajos. Si desea que 1 de cada 10 intentos sea Crítico, la única forma en que este método puede cumplir eso es alternando 5 Fallas y 5 golpes, lo que distorsiona las probabilidades de golpe y falla hacia su promedio. Ninguna secuencia sin errores consecutivos puede satisfacer los requisitos de la entrada aquí.
DMGregory

44
@mklingen, estoy de acuerdo con DMGregory, el "estrictamente sin repeticiones" no es deseable aquí. Más bien, quieren que la probabilidad de cadenas largas del mismo resultado sea menos probable de lo que sería con una probabilidad aleatoria uniforme. Usted puede hacer esto con una cadena de Markov (que se dirige) que se parece a esto . Esto usa múltiples estados para representar eventos repetidos donde las probabilidades de transición de "Hit 1" a "Hit 2" y "Hit 2" a "Hit 3+" disminuyen y las probabilidades de volver a la transición a "Hit 1" y "Crit 1 "subir.
bienvenido

@ Bienvenido, es una gran idea.
mklingen

3

Aquí hay una implementación que creé en C # que:

  • Activa eventos basados ​​en probabilidades
  • Ajuste esas probabilidades para disminuir las posibilidades de eventos recurrentes
  • No te alejes demasiado de las probabilidades originales

He agregado algunos comentarios para que pueda ver lo que estoy haciendo.

    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.
    }

Espero que esto ayude, sugiera mejoras a este código en los comentarios, ¡gracias!


1
Este esquema de reponderación tiende a hacer que los eventos sean equiprobables. Restablecer los pesos periódicamente es solo una curita que limita lo mal que se pone, al tiempo que garantiza que 1 de cada 10 rollos no obtenga ningún beneficio de la nueva ponderación. Además, una nota de algoritmo: está desperdiciando mucho trabajo al llenar una tabla de 100 entradas para hacer su selección aleatoria. En cambio, puede generar una tirada aleatoria y luego iterar sobre sus 4 resultados, sumando sus probabilidades a medida que avanza. Tan pronto como la tirada sea menor que la suma, tendrás tu resultado. No se requiere relleno de mesa.
DMGregory

3

Permítanme generalizar un poco la respuesta de mklingen . Básicamente, desea implementar la Falacia del jugador , aunque le proporcionaré un método más general aquí:

Digamos que hay nposibles eventos con probabilidades p_1, p_2, ..., p_n. Cuando isucedió el evento , su probabilidad se reescalará con un factor 0≤a_i≤1/p_i(este último es importante, de lo contrario terminará con una probabilidad mayor que uno y los otros eventos deben tener probabilidades negativas , que básicamente significan eventos " anti ". O algo así) normalmente a_i<1. Podría, por ejemplo a_i=p_i, elegir , lo que significa que la probabilidad de que un evento ocurra por segunda vez es la probabilidad original de que el evento ocurra exactamente dos veces seguidas, por ejemplo, un segundo lanzamiento de moneda tendría una probabilidad de 1/4 en lugar de 1/2. Por otro lado, también puede tener algunos a_i>1, lo que significaría desencadenar un "golpe de suerte / desgracia".

Todos los demás eventos serán igualmente probables entre sí, es decir, todos deben ser reescalados por el mismo factor de b_imanera que la suma de todas las probabilidades sea igual a uno, es decir

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)

Hasta ahora, muy simple. Pero ahora agreguemos otro requisito: considerando todas las secuencias posibles de dos eventos, las probabilidades de evento único extraídas de allí serán las probabilidades originales.

Dejar

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

denota la probabilidad de que jocurra un evento después del evento iy tenga en cuenta que a p_ij≠p_jimenos que b_i=b_j (2)(lo que (1)implica a_j = 1 - a_i*p_i + (1-a_i)*p_i/p_j). Esto es también lo que requiere el teorema de Bayes y esto también implica

Σ_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)

tal como lo desee Solo tenga en cuenta que esto significa que uno a_isoluciona todos los demás.


Ahora veamos qué sucede cuando aplicamos este procedimiento varias veces, es decir, para secuencias de tres y más eventos. Básicamente, hay dos opciones para elegir las probabilidades amañadas del tercer evento:

a) Olvídate del primer evento y la plataforma como si solo ocurriera el segundo, es decir

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

Tenga en cuenta que esto generalmente viola Bayes, ya que, por ejemplo, p_jik≠p_ikjen la mayoría de los casos.

b) Use las probabilidades p_ij(para fijas i) como nuevas probabilidades pi_jde las que obtiene las nuevas probabilidades pi_jkpara que el evento ksuceda a continuación. Depende de usted modificarlo ai_jo no, pero tenga en cuenta que los nuevos bi_json definitivamente diferentes debido a los modificados pi_j. Por otra parte, la elección de ai_jprobablemente esté restringida al requerir que todas las permutaciones ijkocurran con la misma probabilidad. Veamos...

         / 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)

y permutaciones cíclicas de los mismos, que deben ser iguales para los casos respectivos.

Me temo que mi continuación de esto tendrá que esperar un tiempo ...


Al probar esto empíricamente, esto todavía resulta en una distorsión lejos de las probabilidades de entrada en muchas ejecuciones. Si a_i / p_i = 0.5 por ejemplo, (y usando números de la respuesta de mklingen) una tasa de error de entrada del 60% se convierte en una tasa observada del 50.1%, y una tasa crítica de entrada del 10% se observa como 13.8%. Puede verificar esto llevando la matriz de transición resultante a una potencia alta. Elegir proporciones de a_i: p_i más cercano a 1 da como resultado menos distorsión, pero también menos efectividad en la reducción de corridas.
DMGregory

@DMGregory buen punto: no puede simplemente tomar poderes de la matriz de transición.
Ampliaré

@DMGregory Comencé a describir el proceso completo (variante b)), pero se vuelve bastante tedioso y actualmente tengo poco tiempo: /
Tobias Kienzler

1

Creo que la mejor opción es utilizar la selección de elementos ponderados al azar. Hay una aplicación para C # aquí , pero que se puede encontrar con facilidad o hecho para otros idiomas.

La idea sería reducir el peso de una opción cada vez que se selecciona, y aumentarla cada vez que no se elige.

Por ejemplo, si disminuye el peso de la opción seleccionada NumOptions-1y aumenta el peso de todas las demás opciones en 1 (teniendo cuidado de eliminar elementos con peso <0 y leerlos cuando se elevan por encima de 0) , cada opción se seleccionará aproximadamente la misma cantidad de veces durante un largo período, pero las opciones elegidas recientemente serán mucho menos propensas a ser elegidas.


El problema con el uso de un orden aleatorio, como lo sugieren muchas otras respuestas, es que después de cada opción, pero se ha elegido una, puede predecir con 100% de certeza qué opción se elegirá a continuación. Eso no es muy al azar.


1

Mi respuesta es incorrecta, mi prueba fue defectuosa.

Dejo esta respuesta aquí para la discusión y los comentarios que señalan las fallas en este diseño, pero la prueba real fue incorrecta.

Lo que está buscando es una ponderación ponderada: las ponderaciones para sus cuatro posibles resultados deben ajustarse (ponderarse) en función de los resultados anteriores, sin dejar de ser las ponderaciones adecuadas en general.

La forma más fácil de lograr esto es alterar todos los pesos para cada rollo disminuyendo el peso para el valor específico rodado y aumentando los otros pesos .

Como ejemplo, supongamos que tiene 4 pesos: Fumble, Miss, Hit y Crit. Digamos también que sus pesos totales deseados para ellos son Fumble = 10%, Miss = 50%, Hit = 30% y Crit = 10%.

Si usa un generador de números aleatorios (RNG) para producir valores entre 1 y 100, y luego compara ese valor con el que cae dentro de este rango (1-10 Fumble, 11-60 miss, 61-90 hit, 91-100 crit ), estás generando un rollo individual.

Si, cuando haces esa tirada, inmediatamente ajustas esos rangos en función del valor tirado, estarás ponderando futuras tiradas, pero también necesitas reducir el peso rodado en la misma cantidad total en la que aumentas las otras pesas. Entonces, en nuestro ejemplo anterior, reduciría el peso enrollado en 3 y aumentaría los otros pesos en 1 cada uno.

Si haces esto para cada tirada, aún tendrás la posibilidad de rayas, pero se reducirán en gran medida, porque para cada tirada estás aumentando la posibilidad de que las tiradas futuras sean algo más que lo que es la tirada actual. Puede aumentar este efecto y, por lo tanto, reducir aún más la posibilidad de rayas, aumentando / disminuyendo los pesos en un factor mayor (por ejemplo, reduzca la corriente en 6 y aumente los otros en 2).

Ejecuté una aplicación rápida para validar este enfoque, y después de 32000 iteraciones con esos pesos, produce los siguientes gráficos. El gráfico superior muestra los valores inmediatos de 4 pesos en cada rollo, y el gráfico inferior muestra el recuento de la suma de cada tipo de resultado acumulado hasta ese punto.

Como puede ver, los pesos fluctúan ligeramente alrededor de sus valores deseados, pero los pesos generales permanecen dentro de los rangos deseados, y después de que se establece la variedad inicial de los números iniciales, los resultados se ajustan a nuestros porcentajes deseados casi a la perfección.

Tenga en cuenta que este ejemplo se produjo utilizando la clase .NET System.Random, que en realidad no es uno de los mejores RNG que existen, por lo que probablemente pueda obtener resultados más precisos utilizando un mejor RNG. También tenga en cuenta que 32000 fueron los resultados máximos que pude graficar con esta herramienta, pero mi herramienta de prueba fue capaz de generar más de 500 millones de resultados con los mismos patrones generales.


Tenga en cuenta que esto solo funciona si sus + 1s / -3s se aplican en relación con los pesos originales, en lugar de los pesos utilizados más recientemente. (La modificación continua de los pesos de manera uniforme de esta manera los hace derivar hacia la posibilidad de ser equipables). Si bien esto mantiene la probabilidad en el objetivo a largo plazo, hace muy poco para reducir las carreras. Dado que he fallado una vez, la posibilidad de que pierda dos veces seguidas es del 22% con este esquema, frente al 25% con sorteos independientes. Aumentar el cambio de peso para un efecto mayor (digamos a + 3 / -9) da como resultado un sesgo de la probabilidad a largo plazo.
DMGregory

En realidad, los datos presentados anteriormente están aplicando el + 1 / -3 al peso más reciente cada vez que se procesa un rollo. Entonces, si pierde una vez con el peso inicial del 50%, el siguiente peso sería del 47%, y si vuelve a perder, el siguiente peso sería del 44%, y así sucesivamente. Reduce las corridas (la métrica separada era rastrear corridas, se encontró una reducción de hasta el 24% en las corridas), pero siguen siendo inevitables ya que este esquema aún tiene una gran posibilidad de dejar cada uno de los 4 pesos con una probabilidad distinta de cero ( Por ejemplo, cuatro críticas seguidas dejarían el peso crítico con cero posibilidades de ocurrir).
David C Ellis

Si esa fue su intención, entonces su implementación tiene un error. Mire el gráfico: el peso de fumble solo rebota entre 7 y 11, sin valores fuera de eso. Ejecuté una simulación usando la modificación continua que usted describe, y los gráficos son drásticamente diferentes, con las probabilidades de que cada estado converja hacia el 25% cada uno dentro de los primeros cien ensayos.
DMGregory

Dangit, de hecho fue molestado como lo indicaste. Bueno, busca esta respuesta.
David C Ellis

@DavidCEllis, ¿estás diciendo que tu implementación fue defectuosa o que la idea misma es? Mi intuición de la parte posterior de una servilleta llegó aproximadamente al modelo que describe (ajuste una probabilidad hacia abajo cuando se dibuja, restaura gradualmente todas las probabilidades a sus valores originales con el tiempo) y todavía tiene sentido para mí.
dimo414

0

Podrías hacer lo que es esencialmente un filtro. Mantenga un registro de los n eventos pasados. La probabilidad es algún filtro aplicado a esos eventos. El 0 ° filtro es la probabilidad base, si es 0, entonces lo esquivó, si 1 falló. Digamos que la base era del 25%, y el filtro disminuye a la mitad en cada iteración. Su filtro sería entonces:

[.25 .125 .0625 .03125] 

Siéntase libre de continuar si lo desea. La probabilidad general de este esquema es ligeramente mayor que la probabilidad base de .25. De hecho, la probabilidad, dado el mismo esquema, es (estoy llamando a x la probabilidad real, p es la entrada de probabilidad):

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

Resolviendo para x, se encuentra la respuesta es p(1+1/2+1/4+1/8)/(1+p(1/2+1/4+1/8), o para nuestro caso dado, x=0.38461538461. Pero lo que realmente quieres es encontrar p, dada x. Eso resulta ser un problema más difícil. Si asumió un filtro infinito, el problema se convierte en x+x*p=2*p, o p=x/(2-x). Entonces, al aumentar su filtro, podría resolver un número p que, en promedio, le dará los mismos resultados, pero a un ritmo que depende de cuánto éxito haya sucedido recientemente.

Básicamente, utiliza los valores anteriores para determinar cuál es el umbral de aceptación en esta ronda y toma un valor aleatorio. Luego produzca el siguiente valor aleatorio dado el filtro.


-1

Al igual que usted se propuso, uno de los enfoques para esto es implementar un azar ponderado. La idea es hacer un generador de números aleatorios (o resultados) donde se puedan modificar los pesos y los resultados.

Aquí hay una implementación de esto en 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);
    }
}

EDITAR En el caso en que desee ajustar los pesos automáticamente, por ejemplo, aumente la posibilidad de A cuando el resultado fue B. Puede

  1. Cambia el comportamiento del nextOutcome()método, por lo que modifica el peso de acuerdo con el resultado
  2. Use setWeight()para modificar el peso de acuerdo con el resultado.

Creo que puede haber leído mal la pregunta: el OP no pregunta cómo generar resultados aleatorios ponderados, sino cómo ajustar los pesos para reducir la probabilidad de que el mismo resultado ocurra varias veces seguidas.
Ilmari Karonen

Ya veo, he cambiado algunas de mis respuestas para explicar cómo sería posible usar este sistema.
erikgaal
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.