เกิดอะไรขึ้นกับอัลกอริธึมการสลับ "ไร้เดียงสา"


23

นี่คือการติดตามผลไปยัง Stackoverflow คำถามเกี่ยวกับการสับอาร์เรย์แบบสุ่ม

มีอัลกอริธึมที่กำหนดไว้แล้ว (เช่นKnuth-Fisher-Yates Shuffle ) ที่เราควรใช้เพื่อสับเปลี่ยนอาเรย์แทนที่จะใช้การปรับใช้ Ad-hoc แบบ "ไร้เดียงสา"

ตอนนี้ฉันสนใจที่จะพิสูจน์ (หรือหักล้าง) ว่าอัลกอริทึมไร้เดียงสาของฉันเสีย (เหมือนใน: ไม่ได้สร้างการเรียงสับเปลี่ยนที่เป็นไปได้ทั้งหมดด้วยความน่าจะเป็นที่เท่ากัน)

นี่คืออัลกอริทึม:

วนรอบสองสามครั้ง (ควรทำความยาวของอาเรย์) และในการวนซ้ำทุกครั้งรับดัชนีอาเรย์แบบสุ่มสองอันและสลับองค์ประกอบทั้งสองที่นั่น

เห็นได้ชัดว่าสิ่งนี้ต้องการตัวเลขสุ่มมากกว่า KFY (มากเป็นสองเท่า) แต่นอกเหนือจากนั้นมันทำงานได้อย่างถูกต้องหรือไม่ และจำนวนการวนซ้ำที่เหมาะสม (คือ "ความยาวของอาเรย์" เพียงพอ)?


4
ฉันไม่เข้าใจว่าทำไมคนคิดว่าการแลกเปลี่ยนนี้ง่ายกว่าหรือไร้เดียงสามากกว่าปีงบประมาณ ... เมื่อฉันแก้ไขปัญหานี้เป็นครั้งแรกฉันเพิ่งติดตั้ง FY (ไม่ทราบว่ามีชื่อ) เพียงเพราะดูเหมือนจะเป็นวิธีที่ง่ายที่สุดในการทำเพื่อฉัน

1
@mbq: โดยส่วนตัวแล้วฉันพบว่ามันง่ายพอ ๆ กันแม้ว่าฉันจะเห็นด้วยว่า FY ดูเหมือนจะเป็น "ธรรมชาติ" มากกว่าสำหรับฉัน
โก้

3
เมื่อฉันค้นคว้าอัลกอริธึมการสับหลังจากเขียนเอง (การปฏิบัติที่ฉันทิ้งไว้) ฉันเป็น "อึศักดิ์สิทธิ์ทุกอย่างเสร็จแล้วและมีชื่อ !!"
JM ไม่ใช่นักสถิติ

1
บล็อก DataGenetics ได้ดีภาพประกอบเขียนขึ้นในสิ่งที่ผิดปกติกับขั้นตอนวิธีการสับนี้
DMGregory

คำตอบ:


12

มันถูกทำลายแม้ว่าคุณจะทำการสับได้เพียงพอ แต่มันก็สามารถประมาณได้อย่างยอดเยี่ยม (ดังที่คำตอบก่อนหน้านี้ระบุไว้)

เพียงเพื่อให้ได้จัดการกับสิ่งที่เกิดขึ้นให้พิจารณาวิธีการที่มักอัลกอริทึมของคุณจะสร้างฟืของอาร์เรย์องค์ประกอบที่องค์ประกอบแรกได้รับการแก้ไข2 เมื่อการเรียงสับเปลี่ยนถูกสร้างขึ้นด้วยความน่าจะเป็นที่เท่ากันสิ่งนี้ควรเกิดขึ้นของเวลา ให้เป็นความถี่สัมพัทธ์ของเหตุการณ์นี้หลังจากสับด้วยอัลกอริทึมของคุณ ลองเผื่อแผ่ด้วยและสมมติว่าคุณกำลังเลือกดัชนีที่แตกต่างกันอย่างสุ่มสำหรับ shuffles ของคุณดังนั้นแต่ละคู่จะถูกเลือกด้วยความน่าจะเป็น =k 2 1 / k p n n 1 / ( kkk21/kพีnn 2/(k(k-1))1/(k2)2/(k(k-1)). (ซึ่งหมายความว่าไม่มี shuffles "เล็กน้อย" ในทางกลับกันมันจะแบ่งอัลกอริทึมของคุณสำหรับอาร์เรย์สององค์ประกอบโดยสิ้นเชิงเพราะคุณสลับระหว่างการแก้ไของค์ประกอบทั้งสองกับการแลกเปลี่ยนดังนั้นถ้าคุณหยุดหลังจากกำหนดจำนวน ขั้นตอนไม่มีการสุ่มผลลัพธ์ใด ๆ !)

ความถี่นี้เป็นไปตามการเกิดซ้ำง่าย ๆ เนื่องจากองค์ประกอบแรกถูกพบในตำแหน่งเดิมหลังจากการสับแบบในสองวิธี หนึ่งคือมันได้รับการแก้ไขหลังจาก shuffles และสับเปลี่ยนครั้งต่อไปจะไม่ย้ายองค์ประกอบแรก อีกอันคือมันถูกย้ายหลังจาก shuffles แต่ shuffle จะย้ายกลับ โอกาสที่จะไม่ย้ายองค์ประกอบแรกเท่ากับ =ในขณะที่โอกาสในการเคลื่อนย้ายองค์ประกอบแรกกลับเท่ากับ =ขวา) มาจากไหน:n n n + 1 s t ( k - 1n+1nnn+1sเสื้อ (k-2)/k1/ ( k(k-12)/(k2)(k-2)/k 2/(k(k-1))1/(k2)2/(k(k-1))

พี0=1
เพราะองค์ประกอบแรกเริ่มต้นในตำแหน่งที่ถูกต้อง

พีn+1=k-2kพีn+2k(k-1)(1-พีn).

ทางแก้คือ

pn=1/k+(k3k1)nk1k.

ลบเราจะเห็นว่าความถี่ที่ไม่ถูกต้องโดย{K} สำหรับขนาดใหญ่และ , ประมาณการที่ดีคือ{K-1}) สิ่งนี้แสดงให้เห็นว่าข้อผิดพลาดในความถี่นี้จะลดลงแบบทวีคูณด้วยจำนวนการแลกเปลี่ยนที่สัมพันธ์กับขนาดของอาเรย์ ( ) ซึ่งเป็นการยากที่จะตรวจจับด้วยอาร์เรย์ขนาดใหญ่หากคุณทำการสลับจำนวนค่อนข้างมาก - แต่ข้อผิดพลาดอยู่ที่นั่นเสมอ( k - 31/k knk-1(k3k1)nk1kknn/kk1kexp(2nk1)n/k

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

n>12(1(k1)log(ϵ))

ที่ควรมีขนาดเล็กมากเมื่อเทียบกับ k นี่หมายความว่าควรจะหลายครั้งสำหรับการประมาณคร่าวๆ ( เช่นที่อยู่ในคำสั่งของครั้งหรือดังนั้น)1 / k n k ϵ 0.01 1 / kϵ1/knkϵ0.011/k

ทั้งหมดนี้ทำให้เกิดคำถามว่า: ทำไมคุณถึงเลือกใช้อัลกอริทึมที่ไม่ถูกต้อง (แต่เพียงประมาณ) ถูกต้องใช้เทคนิคเดียวกันกับอัลกอริทึมอื่นที่ถูกต้องและยังต้องใช้การคำนวณมากขึ้น

แก้ไข

ความคิดเห็นของ Thilo นั้นฉลาด (และฉันหวังว่าจะไม่มีใครชี้เรื่องนี้ได้ดังนั้นฉันจึงไม่สามารถทำงานพิเศษนี้ได้!) ผมขออธิบายเหตุผล

  • หากคุณแน่ใจว่าจะสร้างการแลกเปลี่ยนที่เกิดขึ้นจริงในแต่ละครั้งคุณจะเมาอย่างเต็มที่ ปัญหาที่ฉันชี้ให้เห็นในกรณีครอบคลุมไปถึงอาร์เรย์ทั้งหมด เพียงครึ่งหนึ่งของการเปลี่ยนลำดับที่เป็นไปได้ทั้งหมดสามารถทำได้โดยใช้การสลับจำนวนคู่ อีกครึ่งหนึ่งได้มาจากการใช้จำนวน swaps ที่เป็นเลขคี่ ดังนั้นในสถานการณ์นี้คุณไม่สามารถสร้างที่ไหนก็ได้ใกล้กับการกระจายของพีชคณิตแบบสม่ำเสมอ (แต่มีหลายอย่างที่เป็นไปได้มากที่การศึกษาแบบจำลองสำหรับมีขนาดใหญ่จะไม่สามารถตรวจจับปัญหาได้) มันแย่มากจริงๆkk=2k

  • ดังนั้นจึงเป็นการดีที่จะสร้างการแลกเปลี่ยนโดยการสุ่มโดยการสร้างทั้งสองตำแหน่งอย่างอิสระโดยการสุ่ม ซึ่งหมายความว่ามีโอกาสในแต่ละครั้งที่เปลี่ยนองค์ประกอบด้วยตัวเอง นั่นคือไม่ทำอะไรเลย กระบวนการนี้ทำให้อัลกอริทึมช้าลงเล็กน้อยอย่างมีประสิทธิภาพ: หลังจากขั้นตอนเราคาดหวังเพียงแลกเปลี่ยนจริงที่เกิดขึ้นn k - 11/knk1kN<N

  • ขอให้สังเกตว่าขนาดของข้อผิดพลาดลดลงแบบ monotonically ด้วยจำนวนของการแลกเปลี่ยนที่แตกต่างกัน ดังนั้นการดำเนินการแลกเปลี่ยนโดยเฉลี่ยน้อยลงจึงเพิ่มข้อผิดพลาดโดยเฉลี่ย แต่นี่คือราคาที่คุณควรจะยินดีจ่ายเพื่อเอาชนะปัญหาที่อธิบายไว้ในหัวข้อย่อยแรก ดังนั้นประมาณการข้อผิดพลาดของฉันอยู่ในระดับต่ำอนุรักษ์นิยมโดยประมาณโดยปัจจัยของ K(k1)/k

ฉันยังอยากจะชี้ให้เห็นข้อยกเว้นที่เห็นได้ชัดที่น่าสนใจ: มองใกล้ที่สูตรข้อผิดพลาดที่แสดงให้เห็นว่ามีไม่มีข้อผิดพลาดในกรณีที่ 3 นี่ไม่ใช่ข้อผิดพลาด: ถูกต้อง อย่างไรก็ตามที่นี่ฉันได้ตรวจสอบเพียงหนึ่งสถิติที่เกี่ยวข้องกับการกระจายตัวของพีชคณิต ความจริงที่ว่าอัลกอริธึมสามารถสร้างสถิตินี้ขึ้นมาใหม่เมื่อ (กล่าวคือการได้รับความถี่ที่ถูกต้องของการเรียงสับเปลี่ยนที่แก้ไขตำแหน่งที่กำหนด) ไม่รับประกันว่าพีชคณิตมีการกระจายอย่างสม่ำเสมอ อันที่จริงหลังจากswaps จริงการเรียงสับเปลี่ยนที่เป็นไปได้เท่านั้นที่สามารถสร้างได้คือ ,k = 3 2 n ( 123 ) ( 321 ) 2 n + 1 ( 12 ) ( 23 ) ( 13 )k=3k=32n(123)(321)และตัวตน เฉพาะตำแหน่งหลังเท่านั้นที่แก้ไขตำแหน่งที่กำหนดดังนั้นแน่นอนว่าหนึ่งในสามของการเปลี่ยนลำดับจะแก้ไขตำแหน่ง แต่การเปลี่ยนลำดับครึ่งหายไป! ในกรณีอื่น ๆ หลังจากสัญญาแลกเปลี่ยนที่เกิดขึ้นจริงพีชคณิตเป็นไปได้เพียง แต่เป็น ,และ(13)อีกครั้งหนึ่งในสิ่งเหล่านี้จะแก้ไขตำแหน่งที่กำหนดดังนั้นเราจึงได้ความถี่ที่ถูกต้องของการเปลี่ยนลำดับการแก้ไขตำแหน่งนั้น แต่อีกครั้งเราได้รับเพียงครึ่งหนึ่งของการเปลี่ยนลำดับที่เป็นไปได้2n+1(12)(23)(13)

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


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

1
@Thilo: ขอบคุณ ความคิดเห็นของคุณสมควรได้รับคำตอบเพิ่มเติมดังนั้นฉันจึงวางคำตอบไว้ในนั้น ฉันขอชี้ให้เห็นที่นี่ว่า "ความใจดี" ไม่ได้ทิ้งการเปลี่ยนแปลงวิธีการใด ๆ : แค่กำจัดขั้นตอนในอัลกอริทึมที่ไม่ทำอะไรเลย
whuber

2
ปัญหานี้สามารถวิเคราะห์ได้อย่างสมบูรณ์ว่าเป็นห่วงโซ่มาร์คอฟบนกราฟ Cayley ของกลุ่มการเปลี่ยนแปลง การคำนวณเชิงตัวเลขสำหรับ k = 1 ถึง 7 (เมทริกซ์ 5040 คูณ 5040!) ยืนยันว่าค่าลักษณะเฉพาะที่ใหญ่ที่สุดในขนาด (หลังจาก 1 และ -1) มีค่าแน่นอน-1) นี่ก็หมายความว่าเมื่อคุณรับมือกับปัญหาการสลับเครื่องหมายของการเปลี่ยนแปลง (ตรงกับค่าลักษณะเฉพาะของ -1) ข้อผิดพลาดในความน่าจะเป็นทั้งหมดจะสลายตัวในอัตราหรือ ได้เร็วขึ้น ฉันสงสัยว่านี้ยังคงยึดสำหรับทุกขนาดใหญ่k( 1 - 2 / ( k - 1 ) ) n k(k3)/(k1)=12/(k1)(12/(k1))nk
whuber

1
คุณสามารถทำได้ดีกว่าเนื่องจากความน่าจะเป็นคงที่ในคลาส conjugacy และมีเพียงพาร์ติชั่นดังนั้นคุณสามารถวิเคราะห์เมทริกซ์แทน 5040×504015715×15
Douglas Zare

8

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

สมมติว่าคุณมีไพ่สามใบ: {A, B, C} สมมติว่าไพ่ของคุณเริ่มต้นตามลำดับต่อไปนี้: A, B, C จากนั้นหลังจากหนึ่งสลับคุณมีชุดค่าผสมต่อไปนี้:

{A,B,C}, {A,B,C}, {A,B,C} #You get this if choose the same RN twice.
{A,C,B}, {A,C,B}
{C,B,A}, {C,B,A}
{B,A,C}, {B,A,C}

ดังนั้นความน่าจะเป็นของการ์ด A ที่อยู่ในตำแหน่ง {1,2,3} คือ {5/9, 2/9, 2/9}

หากเราสุ่มไพ่เป็นครั้งที่สองแล้ว:

Pr(A in position 1 after 2 shuffles) = 5/9*Pr(A in position 1 after 1 shuffle) 
                                     + 2/9*Pr(A in position 2 after 1 shuffle) 
                                     + 2/9*Pr(A in position 3 after 1 shuffle) 

นี่ให้ 0.407

ด้วยแนวคิดเดียวกันนี้เราสามารถสร้างความสัมพันธ์ที่เกิดซ้ำได้เช่น:

Pr(A in position 1 after n shuffles) = 5/9*Pr(A in position 1 after (n-1) shuffles) 
                                     + 2/9*Pr(A in position 2 after (n-1) shuffles) 
                                     + 2/9*Pr(A in position 3 after (n-1) shuffles).

การเขียนโค้ดนี้ใน R (ดูรหัสด้านล่าง) ให้ความน่าจะเป็นของการ์ด A ที่อยู่ในตำแหน่ง {1,2,3} เป็น {0.33334, 0.33333, 0.33333} หลังจากสิบสับ

รหัส R

## m is the probability matrix of card position
## Row is position
## Col is card A, B, C
m = matrix(0, nrow=3, ncol=3)
m[1,1] = 1; m[2,2] = 1; m[3,3] = 1

## Transition matrix
m_trans = matrix(2/9, nrow=3, ncol=3)
m_trans[1,1] = 5/9; m_trans[2,2] = 5/9; m_trans[3,3] = 5/9

for(i in 1:10){
  old_m = m
  m[1,1] = sum(m_trans[,1]*old_m[,1])
  m[2,1] = sum(m_trans[,2]*old_m[,1])
  m[3,1] = sum(m_trans[,3]*old_m[,1])

  m[1,2] = sum(m_trans[,1]*old_m[,2])
  m[2,2] = sum(m_trans[,2]*old_m[,2])
  m[3,2] = sum(m_trans[,3]*old_m[,2])

  m[1,3] = sum(m_trans[,1]*old_m[,3])
  m[2,3] = sum(m_trans[,2]*old_m[,3])
  m[3,3] = sum(m_trans[,3]*old_m[,3])
}  
m

1
+1 นั่นแสดงให้เห็นว่าความน่าจะเป็นของไพ่ที่กำหนดให้จบลงในตำแหน่งที่กำหนดนั้นใกล้เคียงกับอัตราส่วนที่คาดไว้เมื่อจำนวนการสับเพิ่มขึ้น อย่างไรก็ตามเช่นเดียวกันจะเป็นจริงของอัลกอริทึมที่เพิ่งหมุนอาร์เรย์หนึ่งครั้งโดยการสุ่มจำนวน: การ์ดทั้งหมดมีความน่าจะเป็นเท่ากันที่จะจบลงในทุกตำแหน่ง แต่ยังไม่มีการสุ่มเลย (อาร์เรย์ยังคงเรียงลำดับ)
Thilo

@Thilo: ขออภัยฉันไม่ได้ติดตามความคิดเห็นของคุณ "อัลกอริทึมจะหมุนตามจำนวนการสุ่ม" แต่ยังไม่มี "การสุ่ม" หรือไม่ คุณช่วยอธิบายเพิ่มเติมได้ไหม
csgillespie

หากคุณ "สับเปลี่ยน" อาร์เรย์องค์ประกอบ N โดยการหมุนระหว่าง 0 และ N-1 ตำแหน่ง (สุ่ม) การ์ดทุกใบมีความน่าจะเป็นแบบเดียวกันที่จะสิ้นสุดในตำแหน่ง N ใด ๆ แต่ 2 ยังคงอยู่ระหว่าง 1 เสมอ และ 3
Thilo

1
@ Thio: อ่าฉันได้รับจุดของคุณ ทีนี้คุณสามารถหาความน่าจะเป็น (ใช้แนวคิดเดียวกันกับด้านบน) สำหรับ Pr (A ในตำแหน่งที่ 2) และ Pr (A ในตำแหน่งที่ 3) - dito สำหรับการ์ด B และ C คุณจะเห็นว่าความน่าจะเป็นทั้งหมด 1/3 หมายเหตุ: คำตอบของฉันให้เฉพาะกรณีเฉพาะขณะที่ @whuber คำตอบที่ดีจะให้กรณีทั่วไป
csgillespie

4

วิธีหนึ่งที่จะเห็นว่าคุณจะไม่ได้รับการแจกแจงที่เหมือนกันอย่างสมบูรณ์คือการแบ่งแยก ในการแจกแจงแบบเดียวกันความน่าจะเป็นของการเปลี่ยนแปลงแต่ละครั้งคือ. เมื่อคุณสร้างลำดับของ transpositions สุ่มและลำดับแล้วเก็บโดยผลิตภัณฑ์ของพวกเขาน่าจะเป็นที่คุณได้รับอยู่ในรูปแบบสำหรับบางจำนวนเต็ม ถ้าจากนั้นa โดย Bertrand's Postulate (ทฤษฎีบท) สำหรับมีช่วงเวลาที่เกิดขึ้นในตัวส่วนและไม่แบ่งดังนั้นไม่ใช่จำนวนเต็มและไม่มีวิธีแบ่งการแปลงสัญญาณเท่ากันเป็นt A / n 2 t A 1 / n ! = A / n 2 t n 2 t / n ! = A n 3 n n 2 t / n ! n ! n = 52 1 / 52 ! 3 , 5 , 7 , . . , 47 1 /1/n!tA/n2tA1/n!=A/n2tn2t/n!=An3nn2t/n!n!พีชคณิต ตัวอย่างเช่นถ้าดังนั้นตัวหารของหารด้วยในขณะที่ตัวหารของไม่ดังนั้นไม่สามารถลดเหลือ.n=521/52!3,5,7,...,47 / 52 2 T 1 / 52 !1/522tA/522t1/52!

คุณต้องการประมาณการเรียงสับเปลี่ยนแบบสุ่มด้วยกี่คน? การสร้างการเปลี่ยนรูปแบบสุ่มโดยการแปลงแบบสุ่มถูกวิเคราะห์โดย Diaconis และ Shahshahani โดยใช้ทฤษฎีการเป็นตัวแทนของกลุ่มสมมาตรใน

Diaconis, P. , Shahshahani, M. (1981): "การสร้างการเปลี่ยนแปลงแบบสุ่มด้วย transpositions แบบสุ่ม" Z. Wahrsch hnen; verw Geb. 57, 159–179

ข้อสรุปหนึ่งก็คือมันต้องใช้ transpositions ในแง่ที่ว่าหลังจากการเปลี่ยนลำดับนั้นอยู่ไกลจากการสุ่ม แต่หลังจากผลลัพธ์ใกล้เคียงกับการสุ่มทั้งในแง่ของความแปรปรวนทั้งหมดและระยะทางปรากฏการณ์ cutoff ประเภทนี้เป็นเรื่องปกติในการเดินแบบสุ่มในกลุ่มและสัมพันธ์กับผลลัพธ์ที่มีชื่อเสียงที่คุณต้องการshuffles riffle ก่อนที่ดาดฟ้าจะใกล้เคียงกับการสุ่ม(1-ϵ)112nlogn(1+ϵ)1(1ϵ)12nlognL27(1+ϵ)12nlognL27


2

จำไว้ว่าฉันไม่ใช่นักสถิติ แต่ฉันจะใส่ 2 เซ็นต์ของฉัน

ฉันทำการทดสอบเล็กน้อยใน R (ระวังมันช้ามากสูงnumTrialsรหัสอาจจะปรับให้เหมาะสม):

numElements <- 1000
numTrials <- 5000

swapVec <- function()
    {
    vec.swp <- vec

    for (i in 1:numElements)
        {
        i <- sample(1:numElements)
        j <- sample(1:numElements)

        tmp <- vec.swp[i]
        vec.swp[i] <- vec.swp[j]
        vec.swp[j] <- tmp
        }

    return (vec.swp)
    }

# Create a normally distributed array of numElements length
vec <- rnorm(numElements)

# Do several "swapping trials" so we can make some stats on them
swaps <- vec
prog <- txtProgressBar(0, numTrials, style=3)

for (t in 1:numTrials)
    {
    swaps <- rbind(swaps, swapVec())
    setTxtProgressBar(prog, t)
    }

สิ่งนี้จะสร้างเมทริกซ์ที่swapsมีnumTrials+1แถว (หนึ่งต่อการทดลอง + ดั้งเดิม) และnumElementsคอลัมน์ (หนึ่งต่อแต่ละองค์ประกอบเวกเตอร์) หากวิธีการนั้นถูกต้องการแจกแจงของแต่ละคอลัมน์ (เช่นค่าสำหรับแต่ละองค์ประกอบที่อยู่เหนือการทดลอง) ไม่ควรแตกต่างจากการกระจายตัวของข้อมูลดั้งเดิม

เนื่องจากปกติแล้วข้อมูลดั้งเดิมของเราจะถูกกระจายเราจึงคาดหวังว่าคอลัมน์ทั้งหมดจะไม่เบี่ยงเบนไป

ถ้าเราวิ่ง

par(mfrow= c(2,2))
# Our original data
hist(swaps[1,], 100, col="black", freq=FALSE, main="Original")
# Three "randomly" chosen columns
hist(swaps[,1], 100, col="black", freq=FALSE, main="Trial # 1") 
hist(swaps[,257], 100, col="black", freq=FALSE, main="Trial # 257")
hist(swaps[,844], 100, col="black", freq=FALSE, main="Trial # 844")

เราได้รับ:

ฮิสโทแกรมของการทดลองแบบสุ่ม

ซึ่งดูมีแนวโน้มมาก ทีนี้ถ้าเราต้องการยืนยันทางสถิติการแจกแจงไม่เบี่ยงเบนไปจากต้นฉบับฉันคิดว่าเราสามารถใช้การทดสอบ Kolmogorov-Smirnov (โปรดนักสถิติบางคนยืนยันได้ว่าสิ่งนี้ถูกต้องหรือไม่) และทำเช่น

ks.test(swaps[1, ], swaps[, 234])

ซึ่งให้เรา p = 0.9926

หากเราตรวจสอบคอลัมน์ทั้งหมด:

ks.results <- apply(swaps, 2, function(col){ks.test(swaps[1,], col)})
p.values <- unlist(lapply(ks.results, function(x){x$p.value})

และเราก็วิ่ง

hist(p.values, 100, col="black")

เราได้รับ:

ฮิสโตแกรมของค่า Kolmogorov-Smirnov ทดสอบ p

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

1> quantile(p.values)
       0%       25%       50%       75%      100% 
0.6819832 0.9963731 0.9999188 0.9999996 1.0000000

โปรดสังเกตว่าเห็นได้ชัดว่ามีการทดลองน้อยกว่าสถานการณ์ไม่ดี:

50 การทดลอง

1> quantile(p.values)
          0%          25%          50%          75%         100% 
0.0003399635 0.2920976389 0.5583204486 0.8103852744 0.9999165730

100 การทดลอง

          0%         25%         50%         75%        100% 
 0.001434198 0.327553996 0.596603804 0.828037097 0.999999591 

500 การทดลอง

         0%         25%         50%         75%        100% 
0.007834701 0.504698404 0.764231550 0.934223503 0.999995887 

0

นี่คือวิธีที่ฉันตีความอัลกอริทึมของคุณในโค้ดหลอก:

void shuffle(array, length, num_passes)
  for (pass = 0; pass < num_passes; ++pass) 
    for (n = 0; n < length; ++)
      i = random_in(0, length-1)
      j = random_in(0, lenght-1)
      swap(array[i], array[j]

2×ล.อีnก.เสื้อชั่วโมง×nยูม._พีassอีs[0,ล.อีnก.เสื้อชั่วโมง-1]ล.อีnก.เสื้อชั่วโมง

ล.อีnก.เสื้อชั่วโมง2×ล.อีnก.เสื้อชั่วโมง×nยูม._พีassอีs

ล.อีnก.เสื้อชั่วโมง!ล.อีnก.เสื้อชั่วโมง!<ล.อีnก.เสื้อชั่วโมง2×ล.อีnก.เสื้อชั่วโมง×nยูม._พีassอีs

ล.อีnก.เสื้อชั่วโมง!|ล.อีnก.เสื้อชั่วโมง2×ล.อีnก.เสื้อชั่วโมง×nยูม._พีassอีs

พีพี<ล.อีnก.เสื้อชั่วโมงพีล.อีnก.เสื้อชั่วโมงล.อีnก.เสื้อชั่วโมง>2พี|ล.อีnก.เสื้อชั่วโมง!ล.อีnก.เสื้อชั่วโมง2×ล.อีnก.เสื้อชั่วโมง×nยูม._พีassอีsล.อีnก.เสื้อชั่วโมง!ล.อีnก.เสื้อชั่วโมง2×ล.อีnก.เสื้อชั่วโมง×nยูม._พีassอีsล.อีnก.เสื้อชั่วโมง>2

ล.อีnก.เสื้อชั่วโมงพี<ล.อีnก.เสื้อชั่วโมงล.อีnก.เสื้อชั่วโมง-1ล.อีnก.เสื้อชั่วโมง-1ล.อีnก.เสื้อชั่วโมง

ล.อีnก.เสื้อชั่วโมงlength1length!length!|length!. ไม่ยากที่จะแสดงให้เห็นว่าการติดตามแต่ละครั้งจะส่งผลให้เกิดการเปลี่ยนแปลงที่แตกต่างกันและจากที่นั่นเป็นเรื่องง่ายที่จะเห็นว่า Fisher-Yates สร้างการเปลี่ยนแปลงแต่ละครั้งด้วยความน่าจะเป็นที่เท่ากัน

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