วิธีสร้างตัวเลขตามการแจกแจงแบบไม่ต่อเนื่องโดยอำเภอใจ?


28

ฉันจะสร้างตัวเลขตามการแจกแจงแบบไม่ต่อเนื่องตามอำเภอใจได้อย่างไร?

ตัวอย่างเช่นฉันมีชุดตัวเลขที่ฉันต้องการสร้าง สมมติว่าพวกเขามีป้ายกำกับตั้งแต่ 1-3 ดังนี้

1: 4%, 2: 50%, 3: 46%

โดยทั่วไปร้อยละเป็นความน่าจะเป็นที่พวกเขาจะปรากฏในผลลัพธ์จากการสร้างตัวเลขสุ่ม ฉันมีตัวสร้างตัวเลขแบบสุ่มที่จะสร้างการกระจายแบบสม่ำเสมอในช่วงเวลา [0, 1] มีวิธีการทำเช่นนี้หรือไม่?

ไม่มีขอบเขตเกี่ยวกับองค์ประกอบที่ฉันมีได้ แต่% จะรวมกันได้มากถึง 100%


2
ฉันอาจแนะนำให้ระบุ "... การแจกแจงแบบไม่ต่อเนื่องโดยพลการ" ในชื่อหากนั่นคือคำถามของคุณ กรณีต่อเนื่องจะแตกต่างกัน
David M Kaplan

3
วิธีทั่วไปเพื่อทำการค้นหา binary ภายในรายการของความน่าจะเป็นที่สะสมซึ่งในตัวอย่างนี้จะเป็น(0,0.04,0.54,1.0)โดยเฉลี่ยแล้วจะใช้เวลาโพรบต่อการสร้างเหตุการณ์ หากไม่มีความน่าจะเป็นน้อยมากคุณสามารถรับประสิทธิภาพโดยสร้างเวกเตอร์ที่มีระยะห่างเท่ากันในและ (ในขั้นตอนการคำนวณล่วงหน้า) เพื่อกำหนดผลลัพธ์ให้กับแต่ละค่า เช่นในตัวอย่างนี้คุณอาจสร้างเวกเตอร์ (มี 2 และ 3) สร้างเครื่องแบบคูณด้วย 100 และทำดัชนีลงในเวกเตอร์นี้: เสร็จแล้ว (0,0.04,0.54,1.0)log(n)/2O(1)[0,1](1,1,1,1,2,,2,3,,3)5046
whuber


ลิงก์ "ที่นี่" นั้นเชื่อมโยงกับคำถามนี้จริง ๆ @Glen_b ... ข้อผิดพลาดของการคัดลอก -n-paste?
buruzaemon

@buruzaemon ขอบคุณใช่นั่นเป็นข้อผิดพลาด; ฉันได้แก้ไขแล้ว
Glen_b -Reinstate Monica

คำตอบ:


26

หนึ่งในขั้นตอนวิธีการที่ดีที่สุดสำหรับการสุ่มตัวอย่างจากการกระจายต่อเนื่องเป็นวิธีนามแฝง

เมธอด alias (อย่างมีประสิทธิภาพ) จะคำนวณโครงสร้างข้อมูลสองมิติล่วงหน้าเพื่อแบ่งพาร์ติชันสี่เหลี่ยมออกเป็นส่วน ๆ ตามสัดส่วนของความน่าจะเป็น

รูป

ในแผนผังนี้จากไซต์ที่อ้างอิงสี่เหลี่ยมผืนผ้าของความสูงของหน่วยได้รับการแบ่งออกเป็นสี่ประเภทของภูมิภาค - ตามความแตกต่างของสี - ในสัดส่วน , ,และใน เพื่อสุ่มตัวอย่างจากการกระจายแบบไม่ต่อเนื่องกับความน่าจะเป็นเหล่านี้ แถบแนวตั้งมีความกว้างคงที่ (หน่วย) แต่ละแบ่งออกเป็นเพียงหนึ่งหรือสองชิ้น ตัวตนของชิ้นส่วนและสถานที่ตั้งของหน่วยงานแนวตั้งจะถูกเก็บไว้ในตารางที่สามารถเข้าถึงได้ผ่านดัชนีคอลัมน์1/21/31/121/12

ตารางสามารถถูกสุ่มตัวอย่างในสองขั้นตอนง่าย ๆ (หนึ่งสำหรับแต่ละพิกัด) ต้องการสร้างค่าเครื่องแบบอิสระเพียงสองค่าและการคำนวณสิ่งนี้ปรับปรุงในการคำนวณจำเป็นในการคว่ำ CDF แบบแยกดังที่อธิบายไว้ในคำตอบอื่น ๆ ที่นี่O ( บันทึก( n ) )O(1)O(เข้าสู่ระบบ(n))


2
อัลกอริทึมนี้จะดีที่สุดก็ต่อเมื่อความน่าจะเป็นที่จะถูกคำนวณ ตัวอย่างเช่นถ้ามีขนาดใหญ่มันอาจดีกว่าที่จะไม่สร้างทั้งต้น n
ความน่าจะเป็นทางการ

3
+1 จนถึงตอนนี้เป็นคำตอบเดียวที่แนะนำและอธิบายอัลกอริทึมที่มีประสิทธิภาพ
whuber

19

คุณสามารถทำได้อย่างง่ายดายใน R เพียงระบุขนาดที่คุณต้องการ:

sample(x=c(1,2,3), size=1000, replace=TRUE, prob=c(.04,.50,.46))

3
โดยส่วนตัวแล้วฉันต้องการอัลกอริทึม (หรือที่อื่นเพื่อเรียนรู้ความรู้ที่จำเป็น) เนื่องจากฉันพยายามรวมสิ่งนี้ลงในแอพที่ฉันกำลังสร้าง :) ขอบคุณมากสำหรับคำตอบของคุณแม้ว่า :)
FurtiveFelon

อืม ... การรู้เพิ่มเติมเกี่ยวกับสิ่งที่คุณต้องการจะช่วยเราแนะนำคุณ คุณสามารถบอกเราเพิ่มเติมเกี่ยวกับมันได้หรือไม่ (วัตถุประสงค์บริบท ฯลฯ )
Dominic Comtois

มันมีไว้สำหรับการลงคะแนน ตัวอย่างเช่นฉันมีรูปภาพจำนวนมากและฉันสามารถแสดง 6 ครั้งต่อผู้ใช้เท่านั้นฉันต้องการรวม "ดีที่สุด" ให้กับผู้ใช้ในแต่ละครั้งและผู้ใช้สามารถลงคะแนนขึ้นหรือลงในแต่ละภาพ . ทางออกที่ง่ายที่สุดที่สามารถใช้งานได้ในขณะนี้คือโครงร่าง i ที่ระบุไว้ (แต่ละหมายเลขแทนรูปถ่ายการลงคะแนนเสียงทุกครั้งจะลดความน่าจะเป็นในภาพนั้นและเพิ่มทุกอย่างอื่น ๆ )
FurtiveFelon

1
@furtivefelon คุณสามารถพอร์ตโค้ดจาก R ได้ตลอดเวลาหรือหาอัลกอริทึมจากโค้ดและนำไปใช้ใหม่
mpiktas

ฉันคิดว่าคุณอาจได้รับคำแนะนำที่ดี (ดีกว่า) เกี่ยวกับ Stack Overflow เนื่องจากอาจมีคำตอบที่รู้จักกันดีสำหรับวัตถุประสงค์เฉพาะนี้ ฉันขอแนะนำให้รวมข้อมูลจากความคิดเห็นล่าสุดของคุณลงในคำถามของคุณโดยตรง
Dominic Comtois

19

ในตัวอย่างของคุณสมมติว่าคุณวาดค่า pseudorandom Uniform ของคุณ [0,1] และเรียกมันว่า U. จากนั้น output:

1 ถ้า U <0.04

2 ถ้า U> = 0.04 และ U <0.54

3 ถ้า U> = 0.54

หาก% ที่ระบุคือ a, b, ... ให้แสดงผลลัพธ์

ค่า 1 ถ้าคุณ

ค่า 2 ถ้า U> = a และ U <(a + b)

เป็นต้น

โดยพื้นฐานแล้วเรากำลังทำแผนที่% ลงในส่วนย่อยของ [0,1] และเรารู้ว่าความน่าจะเป็นที่ค่าการสุ่มที่สม่ำเสมอตกอยู่ในช่วงใด ๆ นั้นก็แค่ความยาวของช่วงนั้น การวางช่วงตามลำดับนั้นเป็นวิธีที่ง่ายที่สุดถ้าไม่ใช่เฉพาะวิธีที่จะทำ นี่คือการสมมติว่าคุณกำลังถามเกี่ยวกับการแจกแจงแบบแยกเท่านั้น อย่างต่อเนื่องสามารถทำบางสิ่งเช่น "การสุ่มตัวอย่างการปฏิเสธ" ( รายการ Wikipedia )


8
อัลกอริทึมเร็วขึ้นหากคุณเรียงลำดับหมวดหมู่ตามลำดับความน่าจะเป็นที่ลดลง ด้วยวิธีนี้คุณจะทำการทดสอบน้อยลง (โดยเฉลี่ย) ต่อจำนวนสุ่มที่สร้างขึ้น
jbowman

1
เพียงเพิ่มบันทึกย่อแบบย่อเกี่ยวกับการเรียงลำดับ - สิ่งนี้จะมีผลก็ต่อเมื่อคุณทำมันครั้งเดียวตอนเริ่มต้นของการสุ่มตัวอย่าง - ดังนั้นมันจะไม่ดีสำหรับกรณีที่ความน่าจะเป็นถูกสุ่มตัวอย่างเป็นส่วนหนึ่งของโครงการโดยรวมที่ใหญ่ขึ้น เช่นจากนั้นP r ( Y = j ) = p j ) โดยการเรียงลำดับในกรณีนี้คุณกำลังเพิ่มการดำเนินการเรียงลำดับในการสุ่มตัวอย่างทุกครั้ง - ซึ่งจะเป็นการเพิ่มO ( n log ( n ) )pjDistPr(Y=j)=pjO(nlog(n))เวลาในการทำซ้ำแต่ละครั้ง อย่างไรก็ตามมันอาจมีประโยชน์ในการจัดเรียงโดยคาดเดาขนาดของความน่าจะเป็นที่เริ่มต้นในกรณีนี้
ความน่าจะเป็นที่เป็นไปได้

4

สมมติว่ามีผลต่อเนื่องไปได้ คุณแบ่งช่วง[ 0 , 1 ]เข้า subintervals ขึ้นอยู่กับมวลฟังก์ชันสะสมFเพื่อให้แบ่งพาร์ติชัน( 0 , 1 )ช่วงเวลาม.[0,1]F(0,1)

ผม1ผม2ผมม.

ที่และF ( 0 ) 0 ในตัวอย่างของคุณm = 3และผมJ=(F(J-1),F(J))F(0)0ม.=3

I1=(0,.04),     I2=(.04,.54),     I3=(.54,1)

ตั้งแต่และF ( 2 ) = 0.54และF ( 3 ) = 1F(1)=.04F(2)=.54F(3)=1

จากนั้นคุณสามารถสร้างด้วยการแจกจ่ายFโดยใช้อัลกอริทึมต่อไปนี้:XF

(1) สร้างUUniform(0,1)

(2) ถ้าแล้วX = JUIjX=j

  • ขั้นตอนนี้สามารถทำได้โดยดูว่านั้นน้อยกว่าความน่าจะเป็นที่สะสมแต่ละครั้งหรือไม่และดูว่าจุดเปลี่ยน (จากถึง) เกิดขึ้นที่ใดซึ่งควรเป็นเรื่องของการใช้ตัวดำเนินการบูลีนในภาษาโปรแกรมใด ๆ ค้นหาตำแหน่งที่เกิดขึ้นครั้งแรกในเวกเตอร์UTRUEFALSEFALSE

โปรดทราบว่าจะอยู่ในว่าหนึ่งในช่วงเวลาที่ฉันเจเนื่องจากพวกเขามีเคล็ดและพาร์ติชัน[ 0 , 1 ]UIj[0,1]


ไม่ควรช่วงเวลาเหล่านั้นทั้งหมดจะถูกปิดครึ่ง? มิฉะนั้นจะไม่รวมขอบเขตระหว่างช่วงเวลา .. เช่น {[0,0.04), [0.04,0.54), [0.54,1]}
naught101

1
สำหรับจุดใด ๆ u (เช่นการวัด Lebesgue ของช่วงเวลาเปิดครึ่งเหมือนกันกับช่วงเปิด) ดังนั้นฉันไม่คิดว่ามันจะสำคัญ P(U=u)=0u
มาโคร

1
บนเครื่องดิจิตอล จำกัด แม่นยำแม้ว่าบางทีสักวันหนึ่งก่อนที่จะสิ้นสุดของจักรวาลมันจะสำคัญ ...
jbowman

1
ยุติธรรมพอ @whuber ดูการแก้ไขของฉัน
มาโคร

1
ตกลงนั่นคืออัลกอริทึม BTW ทำไมคุณไม่ส่งคืนอย่างนั้นmin(which(u < cp))ล่ะ มันเป็นการดีที่จะหลีกเลี่ยงการคำนวณผลรวมสะสมอีกครั้งในการโทรแต่ละครั้งเช่นกัน กับที่ Precomputed min(which(runif(1) < cp))ขั้นตอนวิธีการทั้งหมดจะลดลงไป หรือดีกว่าเพราะ OP ถามเพื่อสร้างตัวเลข ( พหูพจน์ ) vectorize n<-10; apply(matrix(runif(n),1), 2, function(u) min(which(u < cp)))ว่ามันเป็น
whuber

2

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

นี่เป็นเรื่องดีที่จำนวนของค่า / ความน่าจะเป็นไม่มีที่สิ้นสุด แต่คุณจะต้องคำนวณความน่าจะเป็นเมื่อคุณเข้าใกล้ตัวเลขเหล่านั้น (สำหรับสิ่งที่ต้องการสร้างจากการแจกแจงปัวซองหรือการแจกแจงลบทวินาม)

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


2

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

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


2

ผมมีปัญหาเหมือนกัน. รับชุดซึ่งแต่ละรายการมีความน่าจะเป็นและมีความน่าจะเป็นรายการรวมถึงหนึ่งที่ผมอยากจะวาดได้อย่างมีประสิทธิภาพตัวอย่างเช่นโดยไม่ต้องเรียงลำดับอะไรและไม่มีซ้ำ ๆ วนกว่าชุด

N[a,1)r[0,1)

next(N,a)=1(1a)rN

(ai)NN=10

a0=next(10,0)
a1=next(9,a0)
a2=next(8,a1)

a9=next(1,a8)

(ai)P0k<|P|pkPaikp0pk>aipkai+1


{(1,0.04),(2,0.5),(3,0.46)}N=10

ฉัน a_i k การจับสลาก
0 0.031 0 0.04 1
1 0.200 1 0.54 2
2 0.236 1 0.54 2
3 0.402 1 0.54 2
4 0.488 1 0.54 2
5 0.589 2 1.0 3
6 0.625 2 1.0 3
7 0.638 2 1.0 3
8 0.738 2 1.0 3
9 0.942 2 1.0 3

(1,2,2,2,2,3,3,3,3,3)


nextN[a,x)x1


ดูเหมือนว่าคุณกำลังแก้ไขปัญหาที่เกิดขึ้นอย่างฉับพลันในย่อหน้าที่สองจากตัวอย่างหนึ่งจากตัวอย่างการแจกแจงแบบไม่ต่อเนื่องตามอำเภอใจไปจนถึงการสุ่มตัวอย่างจากการแจกแจงแบบสม่ำเสมอ วิธีแก้ปัญหาดูเหมือนจะไม่เกี่ยวข้องกับคำถามที่ถามที่นี่
whuber

ฉันชี้แจงส่วนสุดท้าย
casi

{1,2,3}

ฉันเพิ่มตัวอย่าง คำตอบของฉันมีบางอย่างที่เหมือนกันกับคำตอบของ David M Kaplan ( stats.stackexchange.com/a/26860/93386 ) แต่ต้องการเพียงหนึ่งซ้ำแทนการทำซ้ำ N (= ขนาดตัวอย่าง) เหนือชุด รากที่ ฉันทำโพรซีเดอร์ทั้งสองและฉันก็เร็วขึ้นมาก
casi

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