Simula una distribuzione uniforme su un disco


24

Stavo tentando di simulare l'iniezione di punti casuali all'interno di un cerchio, in modo tale che qualsiasi parte del cerchio abbia la stessa probabilità di avere un difetto. Mi aspettavo che il conteggio per area della distribuzione risultante seguisse una distribuzione di Poisson se suddividessi il cerchio in rettangoli di uguale area.

Poiché richiede solo il posizionamento di punti all'interno di un'area circolare, ho iniettato due distribuzioni casuali uniformi in coordinate polari: (raggio) e (angolo polare).Rθ

Ma dopo aver fatto questa iniezione, ottengo chiaramente più punti al centro del cerchio rispetto al bordo.

inserisci qui la descrizione dell'immagine

Quale sarebbe il modo corretto di eseguire questa iniezione attraverso il cerchio in modo tale che i punti vengano distribuiti casualmente attraverso il cirlce?


Questa domanda ha un analogo esatto nel forum Geometry: math.stackexchange.com/questions/87230/…
Aksakal

Risposte:


35

Volete che la proporzione di punti sia uniformemente proporzionale all'area piuttosto che alla distanza dall'origine. Poiché l'area è proporzionale alla distanza quadrata, genera raggi casuali uniformi e acquisisce le loro radici quadrate. Combina questo con un angolo polare uniforme.

Questo è veloce e semplice da codificare, efficiente nell'esecuzione (specialmente su una piattaforma parallela) e genera esattamente il numero prescritto di punti.

Esempio

Questo è un Rcodice funzionante per illustrare l'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")

inserisci qui la descrizione dell'immagine


3

È possibile utilizzare il campionamento di rifiuto . Ciò significa che possiamo campionare dalla distribuzione uniforme 2D e selezionare campioni che soddisfano le condizioni del disco.

Ecco un esempio

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)

inserisci qui la descrizione dell'immagine


3
Questa è una buona alternativa all'approccio adottato dal PO. Semplice ed efficiente In realtà non affronta la questione, che riguarda come modificare il metodo delle coordinate polari per produrre variati distribuiti uniformemente. Perché ci potrebbe interessare? A causa delle implicazioni: una volta che sai come generare punti distribuiti uniformemente in coordinate polari, puoi usare il campionamento del rifiuto (e altri metodi familiari) in coordinate polari per campionare da regioni che potrebbero essere proibitivamente complicate da campionare in coordinate cartesiane (pensa agli ipocicloidi , per esempio).
whuber

1
π/4

@whuber grazie per avermi istruito commentando la mia risposta!
Haitao Du,

3

Ti darò una risposta n-dimensionale generale che funziona anche per il caso bidimensionale, ovviamente. In tre dimensioni un analogo di un disco è un volume di una palla solida (sfera).

Ci sono due approcci che ho intenzione di discutere. Uno di questi chiamerei "preciso" , e otterrai una soluzione completa con esso in R. Il secondo che io chiamo euristico , ed è solo l'idea, non viene fornita una soluzione completa.

Soluzione "precisa"

La mia soluzione si basa sulle opere di Marsaglia e Muller . Fondamentalmente, accade che il vettore gaussiano normalizzato alla sua norma ti dia i punti uniformemente distribuiti su un'ipersfera d-dimensionale:

inserisci qui la descrizione dell'immagine

d1/d

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

inserisci qui la descrizione dell'immagine

Ecco uno snippet di codice per case 3d, ovvero una palla solida:

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

inserisci qui la descrizione dell'immagine

Approccio euristico

Vn(R)=πn2Γ(n2+1)Rn
Rn

Σio=1dXio2<R2

1d+2


@Silverfish, hai ragione, ho corretto la lingua
Aksakal

@Silverfish, è lento a causa dell'uso dei variati gaussiani, ma potrebbe essere più veloce del semplice campionamento del rifiuto in caso di dimensioni elevate, il che non è ovvio per molti, anche se è un argomento diverso
Aksakal

1/d,d

@whuber, stavo copiando la copia, ho corretto un refuso sulla potenza del cubo. Se utilizziamo Gaussian, il campionamento del rifiuto non è migliore, quindi dovremmo usare qualcosa a forma di campana che è più veloce di Gaussian, hai ragione
Aksakal

0

Ecco una soluzione alternativa in 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")

inserisci qui la descrizione dell'immagine


4
Puoi spiegare questa risposta in un inglese semplice? In realtà non siamo un sito di aiuto per il codice e le risposte solo al codice dovrebbero essere scoraggiate.
gung - Ripristina Monica

5
01r <- seq(0, 1, by=1/10)

1
@whuber Grazie per averlo sottolineato. In realtà è la mia idea principale della soluzione. Il mio approccio era quello di generare molti cerchi uniformi con raggi variabili e, per ogni cerchio, il numero di punti è proporzionale alla lunghezza del suo raggio. Pertanto, su un'unità di lunghezza di cerchi con raggi diversi, il numero di punti è lo stesso. Per evitare la natura discreta, potremmo campionare rda Uniform (0,1).
Q_Li
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.