Porque hay incontables soluciones, encontremos una eficiente uno.
La idea detrás de ésta parte de una forma estándar de implementar una variable Bernoulli: comparar una variable aleatoria uniforme $U$ al parámetro $a/b$ . Cuando $U \lt a/b$ devolución $1$ ; en caso contrario, devuelve $0$ .
Podemos utilizar el $p$ -coin como generador uniforme de números aleatorios . Para generar un número $U$ uniformemente dentro de cualquier intervalo $[x, y)$ Lanza la moneda. Si sale cara, genera recursivamente un valor uniforme $X$ en la primera $p$ parte del intervalo; cuando es cruz, genera recursivamente $X$ del último $1-p$ parte del intervalo. En algún momento, el intervalo objetivo será tan pequeño que no importará cómo se elija un número de él: así es como se inicia la recursión. Es obvio que este procedimiento genera variantes uniformes (hasta cualquier precisión deseada), como se demuestra fácilmente por inducción.
Esta idea no es eficiente, pero conduce a un método eficiente. Dado que en cada etapa vas a extraer un número de un intervalo dado $[x,y)$ ¿Por qué no comprueba primero si necesita dibujarlo? Si su valor objetivo se encuentra fuera de este intervalo, ya conoce el resultado de la comparación entre el valor aleatorio y el objetivo. Por lo tanto, este algoritmo tiende a terminar rápidamente. (Esto podría interpretarse como la muestreo de rechazo procedimiento solicitado en la pregunta).
Podemos optimizar aún más este algoritmo. En cualquier etapa, en realidad tenemos dos monedas que podemos utilizar: reetiquetando nuestra moneda podemos convertirla en una que salga cara con el azar $1-p$ . Por lo tanto, como precomputación podemos elegir recursivamente cualquier reetiquetado que conduzca al menor número esperado de vueltas necesarias para la terminación. (Este cálculo puede ser un paso costoso).
Por ejemplo, es ineficiente utilizar una moneda con $p=0.9$ para emular un Bernoulli $(0.01)$ directamente: se necesitan casi diez vueltas de media. Pero si utilizamos una $p=1-0.0=0.1$ moneda, entonces en sólo dos tiradas seguro que habremos terminado y el número esperado de tiradas es de sólo $1.2$ .
He aquí los detalles.
Partición de cualquier intervalo semiabierto $I = [x, y)$ en los intervalos
$$[x,y) = [x, x + (y-x)p) \cup [x + (y-x)p, y) = s(I,H) \cup s(I,T).$$
Esto define las dos transformaciones $s(*,H)$ y $s(*,T)$ que funcionan a intervalos semiabiertos.
Como cuestión de terminología, si $I$ es cualquier conjunto de números reales dejemos que la expresión
$$t \lt I$$
significa que $t$ es un límite inferior para $I$ : $t \lt x$ para todos $x \in I$ . Del mismo modo, $t \gt I$ significa $t$ es un límite superior para $I$ .
Escriba a $a/b = t$ . (De hecho, no habrá diferencia si $t$ sea real en lugar de racional; sólo exigimos que $0 \le t \le 1$ .)
Este es el algoritmo para producir una variante $Z$ con el parámetro Bernoulli deseado:
-
Establecer $n=0$ y $I_n = I_0 = [0,1)$ .
-
En $(t\in I_{n})$ {Lanza la moneda para producir $X_{n+1}$ . Establecer $I_{n+1} = S(I_n, X_{n+1}).$ Incremento $n$ .}
-
Si $t \gt I_{n+1}$ a continuación, establezca $Z=1$ . En caso contrario, fije $Z=0$ .
Aplicación
Para ilustrarlo, he aquí un R
implementación del aloritmo como la función draw
. Sus argumentos son el valor objetivo $t$ y el intervalo $[x,y)$ inicialmente $[0,1)$ . Utiliza la función auxiliar s
aplicación de $s$ . Aunque no lo necesita, también hace un seguimiento del número de lanzamientos de la moneda. Devuelve la variable aleatoria, el recuento de lanzamientos y el último intervalo que inspeccionó.
s <- function(x, ab, p) {
d <- diff(ab) * p
if (x == 1) c(ab[1], ab[1] + d) else c(ab[1] + d, ab[2])
}
draw <- function(target, p) {
between <- function(z, ab) prod(z - ab) <= 0
ab <- c(0,1)
n <- 0
while(between(target, ab)) {
n <- n+1; ab <- s(runif(1) < p, ab, p)
}
return(c(target > ab[2], n, ab))
}
Como ejemplo de su uso y prueba de su precisión, tomemos el caso $t=1/100$ y $p=0.9$ . Dibujemos $10,000$ utilizando el algoritmo, informar sobre la media (y su error estándar) e indicar el número medio de volteos utilizados.
target <- 0.01
p <- 0.9
set.seed(17)
sim <- replicate(1e4, draw(target, p))
(m <- mean(sim[1, ])) # The mean
(m - target) / (sd(sim[1, ]) / sqrt(ncol(sim))) # A Z-score to compare to `target`
mean(sim[2, ]) # Average number of flips
En esta simulación $0.0095$ de las tiradas salieron cara. Aunque inferior al objetivo de $0.01$ la puntuación Z de $-0.5154$ no es significativa: esta desviación puede atribuirse al azar. El número medio de lanzamientos fue de $9.886$ --un poco menos de diez. Si hubiéramos utilizado el $1-p$ moneda, la media habría sido $0.0094$ -aún no significativamente diferente del objetivo, pero sólo $1.177$ por término medio.
2 votos
¿Es una pregunta original de un curso o libro de texto? En caso afirmativo, añada el
[self-study]
y leer su wiki . Tenga en cuenta que no es necesario que incluya un ruego de ayuda al final de su pregunta: ¡sabemos que todos los que escriben aquí esperan recibir ayuda!1 votos
Hay un excelente post de @Glen_b por aquí (aunque no recuerdo dónde) sobre por qué no existe la "moneda sesgada con probabilidad". $p$ ", ¡pero sé que esto es sólo una cuestión periférica a su pregunta!
0 votos
@Silverfish :Lo siento , pero esta no es una pregunta de manual, aunque por la forma en que la he planteado lo parezca. Se me ocurrió mientras intentaba tender un puente entre la probabilidad clásica y la no clásica (si se me permite el término).