Simula una distribución uniforme en un disco

24

Intentaba simular la inyección de puntos aleatorios dentro de un círculo, de modo que cualquier parte del círculo tenga la misma probabilidad de tener un defecto. Esperaba que la cuenta por área de la distribución resultante siguiera una distribución de Poisson si rompo el círculo en rectángulos de igual área.

Como solo requiere colocar puntos dentro de un área circular, inyecté dos distribuciones aleatorias uniformes en coordenadas polares: (radio) y (ángulo polar).Rθ

Pero después de hacer esta inyección, claramente obtengo más puntos en el centro del círculo en comparación con el borde.

ingrese la descripción de la imagen aquí

¿Cuál sería la forma correcta de realizar esta inyección a través del círculo de modo que los puntos se distribuyan aleatoriamente a través del círculo?

Jonjilla
fuente
Esta pregunta tiene un análogo exacto en el foro de Geometría: math.stackexchange.com/questions/87230/…
Aksakal

Respuestas:

35

Desea que la proporción de puntos sea uniformemente proporcional al área en lugar de la distancia al origen. Como el área es proporcional a la distancia al cuadrado, genere radios aleatorios uniformes y tome sus raíces cuadradas. Combina eso con un ángulo polar uniforme.

Esto es rápido y simple de codificar, eficiente en la ejecución (especialmente en una plataforma paralela), y genera exactamente el número prescrito de puntos.

Ejemplo

Este es un Rcódigo de trabajo para ilustrar el algoritmo.

n <- 1e4
rho <- sqrt(runif(n))
theta <- runif(n, 0, 2*pi)
x <- rho * cos(theta)
y <- rho * sin(theta)
plot(x, y, pch=19, cex=0.6, col="#00000020")

ingrese la descripción de la imagen aquí

whuber
fuente
3

Se pueden usar muestras de rechazo . Esto significa que podemos tomar muestras de la distribución uniforme 2D y seleccionar muestras que satisfagan la condición del disco.

Aquí hay un ejemplo.

x=runif(1e4,-1,1)
y=runif(1e4,-1,1)

d=data.frame(x=x,y=y)
disc_sample=d[d$x^2+d$y^2<1,]
plot(disc_sample)

ingrese la descripción de la imagen aquí

Haitao Du
fuente
3
Esta es una buena alternativa al enfoque adoptado por el OP. Simple y eficiente. Sin embargo, en realidad no aborda la pregunta, que se refiere a cómo modificar el método de coordenadas polares para producir variaciones distribuidas uniformemente. ¿Por qué podría importarnos? Debido a las implicaciones: una vez que sepa cómo generar puntos distribuidos uniformemente en coordenadas polares, puede usar el muestreo de rechazo (y otros métodos familiares) en coordenadas polares para muestrear desde regiones que podrían ser prohibitivamente complicadas para muestrear en coordenadas cartesianas (piense en hipocicloides , por ejemplo).
whuber
1
Tenga en cuenta también que no ha generado 10,000 puntos en el disco: el número de puntos es un valor aleatorio cercano a veces 10,000. Hay formas eficientes de evitar esto, pero implementarlas complica el algoritmo. π/ /4 4
whuber
@whuber gracias por educarme comentando mi respuesta!
Haitao Du
3

Te daré una respuesta general n-dimensional que también funciona para casos bidimensionales, por supuesto. En tres dimensiones, un análogo de un disco es el volumen de una bola sólida (esfera).

Hay dos enfoques que voy a discutir. Uno de ellos lo llamaría "preciso" , y obtendrá una solución completa con él en R. El segundo lo llamo heurístico , y es solo la idea, no se proporciona una solución completa.

Solución "precisa"

Mi solución se basa en los trabajos de Marsaglia y Muller . Básicamente, sucede para que el vector gaussiano normalizado a su norma le dé los puntos distribuidos uniformemente en una hiperesfera d-dimensional:

ingrese la descripción de la imagen aquí

re1/ /re

n <- 1e4
rho <- sqrt(runif(n))
# d - # of dimensions of hyperdisk
d = 2
r = matrix(rnorm(n*d),nrow=n,ncol=d)
x = r/rep(sqrt(rowSums(r^2))/rho,1)
plot(x[,1], x[,2], pch=19, cex=0.6, col="#00000020")

ingrese la descripción de la imagen aquí

Aquí hay un fragmento de código para el caso 3D, es decir, una bola sólida:

library(scatterplot3d)
n <- 1e3
# d - # of dimensions of hyperdisk

d=3
rho <- (runif(n))^(1/d)
r = matrix(rnorm(n*d),nrow=n,ncol=d)
x = r/rep(sqrt(rowSums(r^2))/rho,1)

scatterplot3d(x[,1], x[,2], x[,3])

ingrese la descripción de la imagen aquí

Enfoque heurístico

Vnorte(R)=πnorte2Γ(norte2+1)Rnorte
Rnorte

yo=1reXyo2<R2

1re+2

Aksakal
fuente
@Silverfish, tienes razón, arreglé el idioma
Aksakal
@Silverfish, es lento debido al uso de variantes gaussianas, pero podría ser más rápido que el simple muestreo de rechazo en casos de alta dimensión, lo que no es obvio para muchos, aunque es un tema diferente
Aksakal
1/ /re,re
@whuber, estaba copiando y pegando, corrigió un error tipográfico en el poder del cubo. Si usamos Gaussian, entonces el muestreo de rechazo no es mejor, por lo que tendríamos que usar algo en forma de campana que sea más rápido que Gaussian, tienes razón
Aksakal
0

Aquí hay una solución alternativa en R:

n <- 1e4
## r <- seq(0, 1, by=1/1000)
r <- runif(n)
rho <- sample(r, size=n, replace=T, prob=r)
theta <- runif(n, 0, 2*pi)
x <- rho * cos(theta)
y <- rho * sin(theta)
plot(x, y, pch=19, cex=0.6, col="#00000020")

ingrese la descripción de la imagen aquí

Q_Li
fuente
44
¿Puedes explicar esta respuesta en inglés simple? Realmente no somos un sitio de ayuda de código, y las respuestas de solo código deben ser desaconsejadas.
gung - Restablece a Monica
55
0 01r <- seq(0, 1, by=1/10)
1
@whuber Gracias por señalar eso. En realidad es mi idea principal de la solución. Mi enfoque era generar muchos círculos uniformes con radios variables y, para cada círculo, el número de puntos es proporcional a la longitud de su radio. Por lo tanto, en una unidad de longitud de círculos con radios diferentes, el número de puntos es el mismo. Para evitar la naturaleza discreta, podríamos tomar muestras rde Uniform (0,1).
Q_Li