¿Serán dos millones de puntos por segundo?
La distribución es simétrica: solo necesitamos calcular la distribución para un octavo del círculo completo y luego copiarla alrededor de los otros octantes. En coordenadas polares , la distribución acumulativa del ángulo Θ para la ubicación aleatoria ( X , Y ) en el valor θ viene dada por el área entre el triángulo ( 0 , 0 ) , ( 1 , 0 ) , ( 1 , tan θ ) y el arco del círculo que se extiende desde(r,θ)Θ(X,Y)θ(0,0),(1,0),(1,tanθ)(1,0)a . Por lo tanto, es proporcional a(cosθ,sinθ)
FΘ(θ)=Pr(Θ≤θ)∝12tan(θ)−θ2,
de donde es su densidad
fΘ(θ)=ddθFΘ(θ)∝tan2(θ).
Podemos tomar muestras de esta densidad usando, por ejemplo, un método de rechazo (que tiene una eficiencia de ).8/π−2≈54.6479%
La densidad condicional de la coordenada radial es proporcional a r d r entre r = 1 y r = sec θ . Eso se puede muestrear con una fácil inversión del CDF.Rrdrr=1r=secθ
Si generamos muestras independientes , la conversión de nuevo a coordenadas cartesianas ( x i , y i ) muestrea este octante. Debido a que las muestras son independientes, el intercambio aleatorio de las coordenadas produce una muestra aleatoria independiente del primer cuadrante, según se desee. (Los intercambios aleatorios requieren generar solo una variable binomial única para determinar cuántas de las realizaciones intercambiar).(ri,θi)(xi,yi)
Cada realización de requiere, en promedio, una variante uniforme (para R ) más 1 / ( 8 π - 2 ) veces dos variables uniformes (para Θ ) y una pequeña cantidad de cálculo (rápido). Eso es 4 / ( π - 4 ) ≈ 4.66 variantes por punto (que, por supuesto, tiene dos coordenadas). Los detalles completos se encuentran en el siguiente ejemplo de código. Esta cifra representa 10,000 de más de medio millón de puntos generados.(X,Y)R1/(8π−2)Θ4/(π−4)≈4.66
Aquí está el R
código que produjo esta simulación y la cronometró.
n.sim <- 1e6
x.time <- system.time({
# Generate trial angles `theta`
theta <- sqrt(runif(n.sim)) * pi/4
# Rejection step.
theta <- theta[runif(n.sim) * 4 * theta <= pi * tan(theta)^2]
# Generate radial coordinates `r`.
n <- length(theta)
r <- sqrt(1 + runif(n) * tan(theta)^2)
# Convert to Cartesian coordinates.
# (The products will generate a full circle)
x <- r * cos(theta) #* c(1,1,-1,-1)
y <- r * sin(theta) #* c(1,-1,1,-1)
# Swap approximately half the coordinates.
k <- rbinom(1, n, 1/2)
if (k > 0) {
z <- y[1:k]
y[1:k] <- x[1:k]
x[1:k] <- z
}
})
message(signif(x.time[3] * 1e6/n, 2), " seconds per million points.")
#
# Plot the result to confirm.
#
plot(c(0,1), c(0,1), type="n", bty="n", asp=1, xlab="x", ylab="y")
rect(-1, -1, 1, 1, col="White", border="#00000040")
m <- sample.int(n, min(n, 1e4))
points(x[m],y[m], pch=19, cex=1/2, col="#0000e010")