सरल-से-कोड O (N + K * log (K)) तरीका है
सूचकांकों के प्रतिस्थापन के बिना एक यादृच्छिक नमूना लें, सूचकांकों को क्रमबद्ध करें, और उन्हें मूल से लें।
indices = random.sample(range(len(myList)), K)
[myList[i] for i in sorted(indices)]
या अधिक संक्षेप में:
[x[1] for x in sorted(random.sample(enumerate(myList),K))]
अनुकूलित O (N) -टाइम, O (1) -ऑक्सिलरी-स्पेस तरीका
आप वैकल्पिक रूप से एक गणित चाल का उपयोग कर सकते हैं और myList
गतिशील रूप से बदलती संभावना के साथ संख्याओं को उठाते हुए, बाएं से दाएं की ओर से चलने वाले हैं (N-numbersPicked)/(total-numbersVisited)
। इस दृष्टिकोण का लाभ यह है कि यह एक O(N)
एल्गोरिथ्म है क्योंकि इसमें छंटाई शामिल नहीं है!
from __future__ import division
def orderedSampleWithoutReplacement(seq, k):
if not 0<=k<=len(seq):
raise ValueError('Required that 0 <= sample_size <= population_size')
numbersPicked = 0
for i,number in enumerate(seq):
prob = (k-numbersPicked)/(len(seq)-i)
if random.random() < prob:
yield number
numbersPicked += 1
अवधारणा का प्रमाण और परीक्षण कि संभावनाएँ सही हैं :
5 घंटे के दौरान 1 ट्रिलियन छद्म आयामी नमूनों के साथ नकली:
>>> Counter(
tuple(orderedSampleWithoutReplacement([0,1,2,3], 2))
for _ in range(10**9)
)
Counter({
(0, 3): 166680161,
(1, 2): 166672608,
(0, 2): 166669915,
(2, 3): 166667390,
(1, 3): 166660630,
(0, 1): 166649296
})
संभावनाएं 1.0001 से कम कारक द्वारा वास्तविक संभावनाओं से भिन्न होती हैं। इस परीक्षण को फिर से चलाने के परिणामस्वरूप एक अलग क्रम होता है जिसका अर्थ है कि यह एक आदेश देने के लिए पक्षपाती नहीं है। के लिए कम नमूनों के साथ परीक्षण चलाना [0,1,2,3,4], k=3
और [0,1,2,3,4,5], k=4
इसके समान परिणाम थे।
संपादित करें: यह निश्चित नहीं है कि लोग गलत टिप्पणियों को क्यों वोट कर रहे हैं या अपवोट करने से डरते हैं ... नहीं, इस पद्धति में कुछ भी गलत नहीं है। =)
(टिप्पणियों में उपयोगकर्ता टेगन से एक उपयोगी नोट भी: यदि यह python2 है, तो आप xrange का उपयोग करना चाहेंगे, हमेशा की तरह, यदि आप वास्तव में अतिरिक्त स्थान की परवाह करते हैं।)
संपादित करें : प्रमाण: आकार की k
आबादी से बाहर का सबसेट चुनने के समान वितरण (प्रतिस्थापन के बिना) को देखते हुए , हम एक मनमाने बिंदु पर 'बाएं' (0,1, ..., i-1) में विभाजन पर विचार कर सकते हैं। और 'सही' (i, i + 1, ..., len (seq))। यह देखते हुए कि हमने बाएं ज्ञात उपसमुच्चय से उठाया है, शेष को समान अज्ञात उपधारा पर समान वितरण से आना चाहिए, हालांकि पैरामीटर अब अलग हैं। विशेष रूप से, संभावना जिसमें एक चुना तत्व शामिल है , याseq
len(seq)
i
numbersPicked
seq[i]
#remainingToChoose/#remainingToChooseFrom
(k-numbersPicked)/(len(seq)-i)
, इसलिए हम इसका अनुकरण करते हैं और परिणाम पर पुनरावृत्ति करते हैं। (यह समाप्त हो जाना चाहिए क्योंकि अगर #remainingToChoose == #remainingToChooseFrom, तो शेष सभी संभावनाएं 1 हैं।) यह एक संभावना वाले पेड़ के समान है जो गतिशील रूप से उत्पन्न होता है। मूल रूप से आप पूर्व चुनावों पर कंडीशनिंग द्वारा एक समान संभाव्यता वितरण का अनुकरण कर सकते हैं (जैसा कि आप संभाव्यता के पेड़ को बढ़ाते हैं, आप वर्तमान शाखा की संभावना को उठाते हैं जैसे कि यह पूर्व पत्तियों के समान है, अर्थात पूर्व विकल्पों पर वातानुकूलित; यह काम करेगा क्योंकि यह संभावना समान रूप से N / k) है।
संपादित करें : टिमोथी शील्ड्स ने जलाशय नमूनाकरण का उल्लेख किया है , जो len(seq)
अज्ञात होने पर (जैसे कि एक जनरेटर अभिव्यक्ति के साथ) इस पद्धति का सामान्यीकरण है । विशेष रूप से "एल्गोरिथ्म आर" के रूप में विख्यात ओ-एन (ओ) और ओ (1) स्थान है यदि इन-प्लेस किया जाता है; इसमें पहला N तत्व लेना और धीरे-धीरे उन्हें प्रतिस्थापित करना (एक संकेत प्रमाण पर एक संकेत भी दिया गया है) शामिल है। विकिपीडिया पृष्ठ पर पाए जाने वाले जलाशय के नमूने के उपयोगी वितरित संस्करण और विविध प्रकार भी हैं।
संपादित करें : यहाँ एक और अधिक स्पष्ट अर्थ में इसे नीचे कोड करने का एक और तरीका है।
from __future__ import division
import random
def orderedSampleWithoutReplacement(seq, sampleSize):
totalElems = len(seq)
if not 0<=sampleSize<=totalElems:
raise ValueError('Required that 0 <= sample_size <= population_size')
picksRemaining = sampleSize
for elemsSeen,element in enumerate(seq):
elemsRemaining = totalElems - elemsSeen
prob = picksRemaining/elemsRemaining
if random.random() < prob:
yield element
picksRemaining -= 1
from collections import Counter
Counter(
tuple(orderedSampleWithoutReplacement([0,1,2,3], 2))
for _ in range(10**5)
)
random.sample
और फिर छाँटें?