สร้างคะแนนอย่างมีประสิทธิภาพระหว่างหน่วยวงกลมและหน่วยสี่เหลี่ยม


17

ฉันต้องการสร้างตัวอย่างจากขอบเขตสีฟ้าที่กำหนดไว้ที่นี่:

ป้อนคำอธิบายรูปภาพที่นี่

โซลูชันไร้เดียงสาคือใช้การสุ่มตัวอย่างการปฏิเสธในหน่วยสี่เหลี่ยมจัตุรัส แต่ให้ประสิทธิภาพเพียง (~ 21.4%)1π/4

มีวิธีที่ฉันสามารถตัวอย่างมีประสิทธิภาพมากขึ้น?


6
คำแนะนำ : ใช้สมมาตรเพื่อเพิ่มประสิทธิภาพของคุณเป็นสองเท่า
พระคาร์ดินัล

3
โอ้ชอบ: ถ้าค่าเป็น (0,0) สิ่งนี้สามารถแมปกับ (1,1)? ฉันชอบความคิดนั้น
Cam.Davidson.Pilon

@cardinal ไม่ควรเพิ่มประสิทธิภาพขึ้นอีกหรือ? คุณสามารถสุ่มตัวอย่างใน[0,,1]×[0,,1]แล้วสะท้อนไปตามแกน x, แกน y และจุดกำเนิด
Martin Krämer

1
@ มาร์ติน: ในสี่ภูมิภาคที่สมมาตรคุณมีการทับซ้อนกันซึ่งคุณต้องจัดการอย่างระมัดระวังมากขึ้น
พระคาร์ดินัล

3
@ Martin: ถ้าฉันเข้าใจสิ่งที่คุณอธิบายที่ไม่ได้เพิ่มประสิทธิภาพในทุก (คุณพบจุดหนึ่งและตอนนี้รู้อีกสามคน --- ในพื้นที่สี่เท่าของขนาด --- ที่ทำหรือไม่อยู่ในดิสก์ยูนิตที่มีความน่าจะเป็นที่หนึ่งตาม(หรือไม่(x,y)อย่างไร ไม่ช่วยเหลือ?) จุดของการเพิ่มประสิทธิภาพคือการเพิ่มโอกาสในการได้รับการยอมรับสำหรับแต่ละ(x,y)ที่สร้างขึ้น บางทีฉันอาจเป็นคนหนาแน่น
พระคาร์ดินัล

คำตอบ:


10

จะมีคะแนนสองล้านคะแนนต่อวินาทีหรือไม่

การกระจายนั้นสมมาตร: เราแค่หาผลการกระจายสำหรับหนึ่งในแปดของวงกลมเต็มแล้วคัดลอกมันไปรอบ ๆ octants อื่น ในพิกัดเชิงขั้ว , การแจกแจงแบบสะสมของมุมΘสำหรับตำแหน่งสุ่ม( X , Y )ที่ค่าθนั้นได้รับจากพื้นที่ระหว่างสามเหลี่ยม( 0(r,θ)Θ(X,Y)θและส่วนโค้งของวงกลมที่ขยายจาก ((0,0),(1,0),(1,tanθ)เพื่อ ( cos θ , บาปθ ) ดังนั้นจึงเป็นสัดส่วนกับ(1,0)(cosθ,sinθ)

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

ความหนาแน่นของมันมาจากไหน

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

เราอาจสุ่มตัวอย่างจากความหนาแน่นนี้โดยใช้วิธีการปฏิเสธ (ซึ่งมีประสิทธิภาพ )8/π254.6479%

ความหนาแน่นของเงื่อนไขของการประสานงานในแนวรัศมีเป็นสัดส่วนกับR d Rระหว่างR = 1และR = วินาที θ ที่สามารถเก็บตัวอย่างได้ด้วยการกลับกันอย่างง่ายของ CDFRrdrr=1r=secθ

หากเราสร้างตัวอย่างอิสระให้แปลงกลับเป็นพิกัดคาร์ทีเซียน( x i , y i )ตัวอย่าง octant นี้ เนื่องจากตัวอย่างมีความเป็นอิสระการสลับพิกัดแบบสุ่มจะสร้างตัวอย่างแบบสุ่มที่เป็นอิสระจากจตุภาคแรกตามที่ต้องการ (การสลับแบบสุ่มต้องสร้างตัวแปร Binomial เพียงตัวเดียวเพื่อกำหนดจำนวนการรับรู้ที่จะแลกเปลี่ยน)(ri,θi)(xi,yi)

การตระหนักถึงแต่ละอย่างของต้องการค่าเฉลี่ย, ตัวแปรหนึ่งชุด (สำหรับR ) บวก1 / ( 8 π - 2 )คูณสองชุดเครื่องแบบ (สำหรับΘ ) และการคำนวณจำนวนเล็กน้อย (เร็ว) นั่นคือ4 / ( π - 4 ) 4.66ตัวแปรต่อจุด (ซึ่งแน่นอนว่ามีสองพิกัด) รายละเอียดทั้งหมดอยู่ในตัวอย่างโค้ดด้านล่าง ตัวเลขนี้คิดเป็น 10,000 จากคะแนนมากกว่าครึ่งล้านที่สร้างขึ้น(X,Y)R1/(8π2)Θ4/(π4)4.66

รูป

นี่คือRรหัสที่สร้างการจำลองนี้และหมดเวลา

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
ฉันไม่เข้าใจประโยคนี้: "เนื่องจากตัวอย่างมีความเป็นอิสระการสลับพิกัดอย่างเป็นระบบทุก ๆ วินาทีจะสร้างตัวอย่างสุ่มแบบอิสระจากจตุภาคแรกตามที่ต้องการ" สำหรับฉันแล้วดูเหมือนว่าการสลับพิกัดอย่างเป็นระบบทุก ๆ วินาทีตัวอย่างจะสร้างกลุ่มตัวอย่างที่มีความสัมพันธ์สูง ตัวอย่างเช่นฉันว่าการติดตั้งโค้ดของคุณสร้างตัวอย่างครึ่งล้านในแถวจาก octant เดียวกัน
A. Rex

7
การพูดอย่างเคร่งครัดวิธีการนี้ใช้งานไม่ได้ (สำหรับคะแนน iid) เนื่องจากมันสร้างตัวอย่างจำนวนเท่ากันในสอง octants: จุดตัวอย่างจึงขึ้นอยู่กับ ทีนี้ถ้าคุณพลิกเหรียญที่ไม่เอนเอียงเพื่อหาค่าออกเทนสำหรับแต่ละตัวอย่าง ...
พระคาร์ดินัล

1
@ สำคัญคุณถูกต้อง; ฉันจะแก้ไข - โดยไม่มี (asymptotically) เพิ่มจำนวนของตัวแปรสุ่มเพื่อสร้าง!
whuber

2
การพูดอย่างเคร่งครัด (และอีกครั้งเฉพาะในความหมายทางทฤษฎีที่บริสุทธิ์ที่สุด) ในกรณีตัวอย่างที่ จำกัด การดัดแปลงของคุณไม่จำเป็นต้องมีการแปรปรวนแบบสุ่มเพิ่มเติม เพื่อปัญญา: จากครั้งแรกมากตัวแปรสุ่มเครื่องแบบสร้างลำดับพลิกจากครั้งแรกบิต จากนั้นใช้ส่วนที่เหลือ (คูณ2 n ) ตามพิกัดที่สร้างขึ้นครั้งแรก n2n
พระคาร์ดินัล

2
@ ซีอานฉันไม่สามารถรับอินเวอร์สที่คำนวณได้สะดวก ฉันสามารถทำได้ดีกว่าเล็กน้อยโดยการปฏิเสธการสุ่มตัวอย่างจากการกระจายด้วยความหนาแน่นเป็นสัดส่วนกับ (ประสิทธิภาพคือ( 4 - π ) / ( π - 2 ) 75 % ) ที่ค่าใช้จ่ายในการคำนวณอาร์กซีน . 2sin(θ)2(4π)/(π2)75%
whuber

13

ฉันเสนอวิธีแก้ไขปัญหาต่อไปนี้ซึ่งควรจะง่ายกว่ามีประสิทธิภาพมากกว่าและ / หรือคำนวณได้ถูกกว่า soution อื่น ๆ โดย @cardinal, @whuber และ @ stephan-kolassa

มันเกี่ยวข้องกับขั้นตอนง่าย ๆ ดังต่อไปนี้:

1) วาดตัวอย่างมาตรฐานสองตัวอย่าง:

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

2a) ใช้การแปลงแรงเฉือนต่อไปนี้กับจุด (คะแนนในรูปสามเหลี่ยมมุมฉากขวาล่างจะสะท้อนกับสามเหลี่ยมซ้ายบนและจะเป็น "ไม่สะท้อน" ใน 2b): [ x y ] = [ 1 1 ] + [min{u1,u2},max{u1,u2}

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

2b) สลับและyถ้าคุณ1 > u 2xyu1>u2 2

3) ปฏิเสธตัวอย่างถ้าภายในวงกลมหน่วย (การยอมรับควรอยู่ที่ประมาณ 72%) เช่น:

x2+y2<1.

สัญชาตญาณที่อยู่เบื้องหลังอัลกอริทึมนี้จะแสดงในรูป enter image description here

ขั้นตอน 2a และ 2b สามารถรวมกันเป็นขั้นตอนเดียว:

2) ใช้การแปลงแรงเฉือนและสลับ

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

รหัสต่อไปนี้ใช้อัลกอริทึมด้านบน (และทดสอบโดยใช้รหัส @ Whuber)

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

การทดสอบอย่างรวดเร็วบางอย่างให้ผลลัพธ์ต่อไปนี้

อัลกอริทึม/stats//a/258349 ดีที่สุด 3: 0.33 วินาทีต่อล้านคะแนน

อัลกอริทึมนี้ ดีที่สุด 3: 0.18 วินาทีต่อล้านคะแนน


3
+1 ทำได้ดีมาก! ขอขอบคุณที่แบ่งปันโซลูชันที่ชาญฉลาดเฉลียวและเรียบง่าย
whuber

ความคิดที่ดี! ฉันกำลังคิดเกี่ยวกับการทำแผนที่จากหน่วยตารางไปยังส่วนนี้ แต่ไม่ได้คิดว่าไม่สมบูรณ์ทำแผนที่ที่และจากนั้นเป็นรูปแบบการปฏิเสธ ขอบคุณที่ขยายความคิดของฉัน!
Cam.Davidson.Pilon

7

ดีมีประสิทธิภาพมากขึ้นสามารถทำได้ แต่ผมหวังว่าคุณจะไม่ได้มองหาได้เร็วขึ้น

xx

f(x)=11x2.

Wolfram ช่วยให้คุณสามารถรวม :

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

F01f(y)dy )

xt01xเช่นนั้นF(x)=เสื้อ. นั่นคือเราต้องคว่ำ CDF ( การสุ่มตัวอย่างการแปลงผกผัน ) สิ่งนี้สามารถทำได้ แต่ไม่ใช่เรื่องง่าย ไม่เร็ว

ในที่สุดได้รับ xเลือกสุ่ม Y ที่กระจายอย่างสม่ำเสมอระหว่าง 1-x2 และ 1.

ด้านล่างคือรหัส R โปรดทราบว่าฉันกำลังประเมิน CDF ล่วงหน้าที่กริดของx ค่าและแม้กระทั่งนี้ใช้เวลาไม่กี่นาที

คุณสามารถเพิ่มความเร็วในการผกผันของ CDF ได้เล็กน้อยหากคุณลงทุน จากนั้นอีกครั้งคิดเจ็บ ผมเองจะไปสำหรับการสุ่มตัวอย่างการปฏิเสธซึ่งจะเร็วและไกลผิดพลาดได้ง่ายเว้นแต่ผมมีน้อยมากเหตุผลที่ดีที่จะไม่

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


ฉันสงสัยว่าการใช้ชื่อพหุนาม Chebyshev เพื่อประมาณ CDF จะช่วยเพิ่มความเร็วในการประเมินหรือไม่
Sycorax พูดว่า Reinstate Monica

@Sycorax ไม่ใช่โดยไม่มีการดัดแปลง; ดูเช่นการรักษา chebfunของเอกพจน์เกี่ยวกับพีชคณิตที่จุดสิ้นสุด
JM ไม่ใช่นักสถิติ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.