Birim çember ve birim kare arasında verimli puanlar üretin


17

Burada tanımlanan mavi bölgeden örnekler oluşturmak istiyorum:

resim açıklamasını buraya girin

Saf çözüm, birim karede reddetme örneklemesi kullanmaktır, ancak bu sadece (~% 21.4) verimlilik sağlar.1π/4

Daha verimli örneklememin bir yolu var mı?


6
İpucu : Verimliliğinizi iki katına çıkarmak için simetri kullanın.
kardinal

3
Oh like: değer (0,0) ise, bu (1,1) ile eşlenebilir mi? Bu fikri seviyorum
Cam.Davidson.Pilon

@cardinal Verimliliği 4 kat artırmamalı mı? [ 0 , , 1 ] × [ 0 , , 1 ] içinde örnekleme yapabilirsiniz[0,,1]×[0,,1] ile ve ardından x ekseni, y ekseni ve orijini aynalayabilirsiniz.
Martin Krämer

1
@Martin: Dört simetrik bölgede, daha dikkatli bir şekilde uğraşmak zorunda olduğunuz örtüşmeye sahipsiniz.
kardinal

3
@Martin: Ben sizin tarif ettiğiniz anlayarak ediyorum, bu verimliliği artmaz hiç . (Bir nokta buldunuz ve şimdi nin yapılıp yapılmadığına göre birim disk içinde ya da yok olan üç tane - boyutun dört katı bir alanda - tanıyorsunuz . Verimliliğin artırılması noktası üretilen her ( x , y ) için kabul olasılığını arttırmaktır . Belki de yoğun olan benim. (x,y)(x,y)
kardinal

Yanıtlar:


10

Saniyede iki milyon puan kazanacak mı?

Dağıtım simetriktir: sadece tüm dairenin sekizde biri için dağıtımı yapmamız ve sonra diğer oktanların etrafına kopyalamamız gerekir. Kutupsal koordinatlarda , açı kümülatif dağılım İçeride ISTV melerin RWMAIWi'nin rastgele konum ( X , Y ) değeri ile θ üçgen arasındaki alan ile verilmiştir ((r,θ)Θ(X,Y)θ veuzanan dairenin yayı(0,0),(1,0),(1,tanθ) ila ( cos θ , sin θ ) . Böylece orantılıdır.(1,0)(cosθ,sinθ)

FΘ(θ)=Pr(Θθ)12tan(θ)θ2,

yoğunluğu

fΘ(θ)=ddθFΘ(θ)tan2(θ).

Bu yoğunluktan, örneğin, verimi 8 / π - 2 olan bir reddetme yöntemi kullanarak örnekleme yapabiliriz ).8/π254.6479%

Koordinat radyal koşullu yoğunluk ile orantılıdır r d r arasındaki r = 1 ve r =Rrdrr=1 . Bu, CDF'nin kolayca ters çevrilmesi ile örneklenebilir.r=secθ

Bağımsız numuneler üretersek , Kartezyen koordinatlara ( x i , y i ) dönüş bu oktanı örnekler. Numuneler bağımsız olduğu için, koordinatları rastgele değiştirmek, istendiği gibi birinci kadranda bağımsız bir rasgele numune üretir. (Rastgele değiş tokuşlar, gerçekleşecek kaç gerçekleşmenin değişeceğini belirlemek için yalnızca tek bir Binom değişkeni oluşturulmasını gerektirir.)(ri,θi)(xi,yi)

Her biri, gerçekleştirilmesi , ortalama, tek tip bir varyant ile (için, ihtiyaç R ) artı 1 / ( 8 π - 2 ) iki katı homojen için (dağılımı özellikleri İçeride ISTV melerin RWMAIWi'nin ) ve (hızlı) hesaplama küçük bir miktar. Bu 4 / ( π - 4 ) (X,Y)R1/(8π2)Θ nokta başına değişmektedir (ki bu elbette iki koordinatı vardır). Tüm ayrıntılar aşağıdaki kod örneğinde verilmiştir. Bu rakam, üretilen yarım milyondan fazla noktanın 10.000'ini çiziyor.4/(π4)4.66

Figure

İşte Rbu simülasyonu üreten ve zamanlayan kod.

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

1
Bu cümleyi anlamıyorum: "Numuneler bağımsız olduğu için, her ikinci numunenin sistematik olarak koordinatlarını değiştirmek, istendiği gibi birinci kadranda bağımsız bir rasgele numune üretir." Bana öyle geliyor ki, her ikinci örneğin sistematik olarak koordinatlarını değiştirmek son derece bağımlı örnekler üretiyor. Örneğin, bana göre, koddaki uygulamanız aynı oktandan üst üste yarım milyon örnek oluşturuyor mu?
A. Rex

7
Açıkçası, bu yaklaşım (iid noktaları için) pek işe yaramıyor çünkü iki oktanda aynı sayıda örnek üretiyor: Bu nedenle örnek noktaları bağımlıdır. Şimdi, her örnek için oktanı belirlemek için tarafsız paraları çevirirseniz ...
kardinal

1
@Cardinal haklısın; Bunu düzelteceğim - (asimptotik olarak) üretmek için rastgele değişkenlerin sayısını artırmadan!
whuber

2
Kesinlikle sonlu örnek durumunda, sizin modifikasyon gerektirir (yalnızca en saf teorik anlamda, tekrar ve) konuşan hiçbir ek üniforma rastgele değişebilirlerin. Wit için: İlk tekdüze rasgele değişkenden, ilk bitinden saygısız diziyi oluşturun . Ardından, geri kalanını (çarpı 2 n ) oluşturulan ilk koordinat olarak kullanın. n2n
kardinal

2
@ Xi'an Uygun şekilde hesaplanabilen bir ters elde edemedim. Bir sinüsü hesaplamak zorunda kalarak (oran ( 4 - π ) / ( π - 2 ) % 75) oranındaki yoğunlukta dağılımdan reddederek örnekleme yaparak biraz daha iyi yapabilirim. . 2sin(θ)2(4π)/(π2)75%
whuber

13

Şimdiye kadar @cardinal, @whuber ve @ stephan-kolassa'nın diğer çözümlerden daha basit, daha verimli ve / veya hesaplamalı olarak daha ucuz olması gereken aşağıdaki çözümü öneriyorum.

Aşağıdaki basit adımları içerir:

1) İki standart tek tip numune çizin:

u1Unif(0,1)u2Unif(0,1).

min{u1,u2},max{u1,u2}

[xy]=[11]+[2212210][min{u1,u2}max{u1,u2}].

2b) Swap x and y if u1>u2.

3) Reject the sample if inside the unit circle (acceptance should be around 72%), i.e.:

x2+y2<1.

The intuition behind this algorithm is shown in the figure. enter image description here

Steps 2a and 2b can be merged into a single step:

2) Apply shear transformation and swap

x=1+22min(u1,u2)u2y=1+22min(u1,u2)u1

The following code implements the algorithm above (and tests it using @whuber's code).

n.sim <- 1e6
x.time <- system.time({
    # Draw two standard uniform samples
    u_1 <- runif(n.sim)
    u_2 <- runif(n.sim)
    # Apply shear transformation and swap
    tmp <- 1 + sqrt(2)/2 * pmin(u_1, u_2)
    x <- tmp - u_2
    y <- tmp - u_1
    # Reject if inside circle
    accept <- x^2 + y^2 > 1
    x <- x[accept]
    y <- y[accept]
    n <- length(x)
})
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")

Some quick tests yield the following results.

Algorithm /stats//a/258349 . Best of 3: 0.33 seconds per million points.

This algorithm. Best of 3: 0.18 seconds per million points.


3
+1 Very well done! Thank you for sharing a thoughtful, clever, and simple solution.
whuber

Great idea! I was thinking about a mapping from the unit sq to this portion, but didn't think of an imperfect mapping and then a rejection scheme. Thanks for expanding my mind!
Cam.Davidson.Pilon

7

Well, more efficiently can be done, but I sure hope you are not looking for faster.

The idea would be to sample an x value first, with a density proportional to the length of the vertical blue slice above each x value:

f(x)=11x2.

Wolfram helps you to integrate that:

0xf(y)dy=12x1x2+x12arcsinx.

So the cumulative distribution function F would be this expression, scaled to integrate to 1 (i.e., divided by 01f(y)dy).

Now, to generate your x value, pick a random number t, uniformly distributed between 0 and 1. Then find x such that F(x)=t. That is, we need to invert the CDF (inverse transform sampling). This can be done, but it's not easy. Nor fast.

Finally, given x, pick a random y that is uniformly distributed between 1x2 and 1.

Below is R code. Note that I am pre-evaluating the CDF at a grid of x values, and even then this takes quite a few minutes.

You can probably speed the CDF inversion up quite a bit if you invest some thinking. Then again, thinking hurts. I personally would go for rejection sampling, which is faster and far less error-prone, unless I had very good reasons not to.

epsilon <- 1e-6
xx <- seq(0,1,by=epsilon)
x.cdf <- function(x) x-(x*sqrt(1-x^2)+asin(x))/2
xx.cdf <- x.cdf(xx)/x.cdf(1)

nn <- 1e4
rr <- matrix(nrow=nn,ncol=2)
set.seed(1)
pb <- winProgressBar(max=nn)
for ( ii in 1:nn ) {
    setWinProgressBar(pb,ii,paste(ii,"of",nn))
    x <- max(xx[xx.cdf<runif(1)])
    y <- runif(1,sqrt(1-x^2),1)
    rr[ii,] <- c(x,y)
}
close(pb)

plot(rr,pch=19,cex=.3,xlab="",ylab="")

randoms


I wonder if using Chebyshev polynomials to approximate the CDF would improve the evaluation speed.
Sycorax says Reinstate Monica

@Sycorax, not without modifications; see e.g. the chebfun treatment of algebraic singularities at the endpoints.
J. M. is not a statistician
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.