วิธีตัวอย่าง X อย่างรวดเร็วถ้า exp (X) ~ Gamma


12

ฉันมีปัญหาในการสุ่มตัวอย่างอย่างง่ายโดยที่วงในของฉันดูเหมือน:

v = sample_gamma(k, a)

โดยที่sample_gammaตัวอย่างจากการแจกแจงแกมม่าเป็นตัวอย่าง Dirichlet

มันใช้งานได้ดี แต่สำหรับค่าบางส่วนของ k / a การคำนวณ downstream underflows บางส่วน

ฉันปรับมันเพื่อใช้ตัวแปรพื้นที่บันทึก:

v = log(sample_gamma(k, a))

หลังจากปรับโปรแกรมที่เหลือทั้งหมดมันทำงานได้อย่างถูกต้อง (อย่างน้อยมันก็ให้ผลลัพธ์ที่แน่นอนเหมือนกันในกรณีทดสอบ) อย่างไรก็ตามมันช้ากว่าเดิม

มีวิธีการโดยตรงตัวอย่างโดยไม่ใช้ฟังก์ชั่นช้าเช่นlog ( ) ? ฉันลอง googling สำหรับสิ่งนี้ แต่ฉันไม่รู้ด้วยซ้ำว่าการกระจายนี้มีชื่อสามัญ (log-gamma?)X,exp(X)Gammalog()


สิ่งที่คุณต้องทำคือการแบ่งแต่ละแกมม่าแปรตามผลรวมของพวกเขา underflow เกิดขึ้นได้อย่างไร และการลอการิทึมจะแก้ปัญหานี้ได้อย่างไร (คุณไม่สามารถคำนวณผลรวมได้โดยไม่ต้องยกกำลังกลับมาอีกครั้ง)
whuber

@whuber ในพื้นที่บันทึกคุณคำนวณผลรวมแล้วลบออกจากแต่ละองค์ประกอบ ดังนั้นสิ่งนี้จะหลีกเลี่ยงจุดแรกของความไม่พอ มีการประมวลผลเพิ่มเติมเล็กน้อยเมื่อ dirichlets เหล่านี้ทำหน้าที่เป็นส่วนประกอบผสมและได้รับการคูณด้วยตัวเลขขนาดเล็กอีกครั้ง
luispedro

การเพิ่มบันทึกนั้นไม่ถูกต้องทางคณิตศาสตร์: มันสอดคล้องกับการคูณ gammas แทนที่จะเพิ่มมัน ใช่คุณอาจได้รับผลการทำงาน แต่แน่นอนว่าพวกเขาจะไม่มีการแจกจ่าย Dirichlet! อีกครั้งธรรมชาติของอันเดอร์โฟลว์ดั้งเดิมคืออะไรและคุณคำนวณอะไรเมื่อมันเกิดขึ้น? คุณค่าที่แท้จริงของคุณคืออะไร
whuber

@ คนที่ฉันอาจจะง่ายขึ้นเล็กน้อยในคำอธิบายของฉัน ฉันทำทั้งหมดฉัน {t = gamma (a, b); รวม + = t; d [i] = log (t)}; logsum = log (ผลรวม); forall i {d [i] - = logsum; } ก่อนหน้านี้สิ่งนี้ underflowed ถ้า a มีขนาดเล็กมาก
luispedro

เตรียมพร้อม: สำหรับใกล้ 0 คุณจะมีปัญหาไม่ว่าจะเกิดอะไรขึ้น ปัญหาที่น่าสนใจ! α
whuber

คำตอบ:


9

พิจารณาพารามิเตอร์รูปร่างเล็กใกล้ 0 เช่นα = 1 / 100 ในช่วงระหว่าง 0 และα , E - αจะอยู่ที่ประมาณ1ดังนั้นแกมมาเป็น pdf ประมาณx α - 1 d x / Γ ( α ) สิ่งนี้สามารถรวมเข้ากับ CDF โดยประมาณ, F α ( x ) = x ααα=1/100αeα1xα1dx/Γ(α) ) เราจะเห็นพลัง1/α: เลขชี้กำลังจำนวนมาก สำหรับα=1/100นี้ทำให้โอกาสที่บางส่วนของอันเดอร์โฟล์ (ค่าความแม่นยำสองน้อยกว่า10-300มากกว่าหรือน้อยกว่า) นี่คือพล็อตของโอกาสในการรับอันเดอร์โฟลว์ในฐานะฟังก์ชันลอการิทึมฐานสิบของα:Fα(x)=xααΓ(α)1/αα=1/10010300α

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

ทางออกหนึ่งคือการใช้ประโยชน์จากการประมาณนี้สำหรับการสร้างรูปแบบการบันทึก (Gamma): ผลลองสร้างรูปแบบแกมมาและถ้ามันมีขนาดเล็กเกินไปสร้างลอการิทึมจากการกระจายพลังงานโดยประมาณนี้ (ดังแสดงด้านล่าง) (ทำสิ่งนี้ซ้ำ ๆ จนกว่าบันทึกจะอยู่ในช่วง underflow เพื่อให้มันเป็นสิ่งทดแทนที่ถูกต้องสำหรับตัวแปร underflowing ดั้งเดิม) สำหรับการคำนวณ Dirichlet ให้ลบค่าสูงสุดของค่าลอการิทึมทั้งหมดจากค่าบันทึกแต่ละค่าโดยปริยาย แกมมาแปรปรวนดังนั้นมันจะไม่ส่งผลกระทบต่อค่า Dirichlet ปฏิบัติกับบันทึกผลลัพธ์ที่มีขนาดเล็กเกินไป (พูดน้อยกว่า -100) ว่าเป็นบันทึกของศูนย์จริง ยกกำลังบันทึกอื่น ๆ ตอนนี้คุณสามารถดำเนินการต่อได้โดยไม่ต้อง underflow

สิ่งนี้จะใช้เวลานานกว่าเดิม แต่อย่างน้อยมันก็ใช้ได้!

αC=log(Γ(α))+log(α)αC

เนื่องจากพารามิเตอร์สเกลช่วยลดความแปรปรวนเพียงอย่างเดียวจึงไม่มีปัญหาในการรองรับในขั้นตอนเหล่านี้ คุณไม่จำเป็นต้องใช้มันหากพารามิเตอร์สเกลทั้งหมดเหมือนกัน

แก้ไข

1/αB(α)Γ(α+1)(αxα1)(yαeydy/Γ(α+1))z=xyyz/xxxz0y1

pdf(z)=αΓ(α+1)z(xα/x)ex(z/x)α1dxdz=1Γ(α)zα1ezdz,

Γ(α)

0<α<1Γ(α+1)1/αΓ(α)


1
Γ(α)Γ(α)+Γ(1)Beta(α,1)Γ(α)+Γ(1)Γ(α+1)α0yexpo(1)log(u)Γ(α+1)

7

raαbβ

  if (a < 1)
    {
      double u = gsl_rng_uniform_pos (r);
      return gsl_ran_gamma (r, 1.0 + a, b) * pow (u, 1.0 / a);
   }

gsl_ran_gammagsl_rng_uniform_pos(0,1)_pos

ดังนั้นฉันสามารถบันทึกการแสดงออกและการใช้งานล่าสุด

return log(gsl_ran_gamma(r, 1.0 + a, b)) + log(u)/a;

log()pow()1/a1/a


α

ฉันแก้ไขคำตอบเพื่อรวมรายละเอียดเพิ่มเติมตอนนี้
luispedro

ขอบคุณ: แต่ "r" คืออะไร? (โปรดทราบว่าการเรียกซ้ำถูก จำกัด ขอบเขต: การเรียกซ้ำแบบเรียกซ้ำมากที่สุดจะทำได้เนื่องจาก> 0 หมายถึง 1.0 + a> 1)
whuber

r คือตัวสร้างตัวเลขสุ่ม (ซึ่งคุณจะได้รับตัวเลขสุ่มจาก)
luispedro

Γ(α+1)B(α,1)Γ(α)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.