র্যান্ডম.চয়েসের একটি ভারী সংস্করণ


245

আমাকে এলোমেলো.চয়েসের ভারী সংস্করণ লিখতে হবে (তালিকার প্রতিটি উপাদান নির্বাচনের জন্য আলাদা সম্ভাবনা রয়েছে)। এটিই আমি নিয়ে এসেছি:

def weightedChoice(choices):
    """Like random.choice, but each element can have a different chance of
    being selected.

    choices can be any iterable containing iterables with two items each.
    Technically, they can have more than two items, the rest will just be
    ignored.  The first item is the thing being chosen, the second item is
    its weight.  The weights can be any numeric values, what matters is the
    relative differences between them.
    """
    space = {}
    current = 0
    for choice, weight in choices:
        if weight > 0:
            space[current] = choice
            current += weight
    rand = random.uniform(0, current)
    for key in sorted(space.keys() + [current]):
        if rand < key:
            return choice
        choice = space[key]
    return None

এই ফাংশনটি আমার কাছে অত্যধিক জটিল এবং কুৎসিত বলে মনে হয়। আমি আশা করছি এখানকার প্রত্যেকে এটির উন্নতি বা এটি করার বিকল্প উপায় সম্পর্কে কিছু পরামর্শ দিতে পারে। কোড পরিচ্ছন্নতা এবং পঠনযোগ্যতার মতো দক্ষতা আমার পক্ষে ততটা গুরুত্বপূর্ণ নয়।

উত্তর:


297

সংস্করণ 1.7.0 থেকে, NumPy এর একটি choiceফাংশন রয়েছে যা সম্ভাব্যতা বন্টনকে সমর্থন করে।

from numpy.random import choice
draw = choice(list_of_candidates, number_of_items_to_pick,
              p=probability_distribution)

probability_distributionএটি একই ক্রমের একটি ক্রম নোট করুন list_of_candidatesreplace=Falseআচরণ পরিবর্তন করতে আপনি কীওয়ার্ডটিও ব্যবহার করতে পারেন যাতে টানা আইটেমগুলি প্রতিস্থাপন না করা হয়।


11
আমার পরীক্ষার দ্বারা, এটি random.choicesপৃথক কলগুলির চেয়ে ধীর গতিতে ক্রম । আপনার যদি প্রচুর এলোমেলো ফলাফলের প্রয়োজন হয় তবে সামঞ্জস্য করে একবারে সেগুলি বেছে নেওয়া সত্যিই গুরুত্বপূর্ণ number_of_items_to_pick। যদি আপনি এটি করেন, এটি দ্রুততার একটি ক্রম।
jpmc26

2
এই tuples ইত্যাদি সাথে কাজ করে না ( "ValueError: একটি 1-মাত্রিক হতে হবে"), যাতে ক্ষেত্রে একটি চয়ন করতে numpy অনুরোধ করতে পারেন সূচক তালিকা, অর্থাত মধ্যে len(list_of_candidates), এবং তারপর কিlist_of_candidates[draw]
xjcl

218

পাইথন ৩.6 choicesথেকে randomমডিউলটি থেকে একটি পদ্ধতি রয়েছে ।

Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.0.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import random

In [2]: random.choices(
...:     population=[['a','b'], ['b','a'], ['c','b']],
...:     weights=[0.2, 0.2, 0.6],
...:     k=10
...: )

Out[2]:
[['c', 'b'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['c', 'b']]

নোট যে প্রতিস্থাপনের সাথে দস্তাবেজ প্রতি random.choicesনমুনা হবে :

kপ্রতিস্থাপনের সাথে জনসংখ্যা থেকে নির্বাচিত উপাদানগুলির একটি আকারের তালিকা ফিরিয়ে দিন।

যদি আপনার প্রতিস্থাপন ছাড়াই নমুনা প্রয়োজন হয়, তবে @ রোনান-প্যাক্সেসোর উজ্জ্বল উত্তরটি হিসাবে , আপনি ব্যবহার করতে পারেন numpy.choice, যার replaceযুক্তি যেমন আচরণ নিয়ন্ত্রণ করে।


4
এটি numpy.random.choice এর চেয়ে অনেক বেশি দ্রুত। ৮ টি ওজনযুক্ত আইটেমের তালিকা 10,000 বার বার থেকে নেওয়া, numpy.random.choice এ 0.3286 সেকেন্ড সময় নিয়েছে যেখানে এলোমেলো.চয়েজগুলি 0.0416 সেকেন্ড, প্রায় 8x দ্রুত নিয়েছে।
অ্যান্টন

@ অ্যান্টন কোডস এই উদাহরণটি চেরি বাছাই করা। নম্পির কিছু ধ্রুবক-ওভারহেড থাকবে যা random.choicesএটি নয়, অবশ্যই এটি 8 টি আইটেমের একটি মিনিসিকিউলের তালিকায় ধীর। এবং আপনি যদি এই জাতীয় তালিকা থেকে 10 কে বার বেছে নিচ্ছেন, আপনি ঠিক বলেছেন। তবে ক্ষেত্রে যখন তালিকাটি বৃহত্তর হয় (আপনি কীভাবে পরীক্ষা করছেন তার উপর নির্ভর করে, আমি ১০০-৩০০ উপাদানের মধ্যে ব্রেক পয়েন্ট দেখতে পাচ্ছি), বেশ প্রশস্ত ফাঁক np.random.choiceদিয়েই পারফর্ম random.choicesকরা শুরু করে। উদাহরণস্বরূপ, নম্পি কলের সাথে স্বাভাবিককরণের পদক্ষেপ সহ random.choices10 কে উপাদানগুলির তালিকার জন্য আমি প্রায় 4x স্পিডআপ পেয়েছি ।
ggorlen

@ অ্যান্টকোডস রিপোর্ট করেছে এমন পারফরম্যান্স উন্নতির ভিত্তিতে এটি নতুন উত্তর হওয়া উচিত।
ওয়েইন ওয়ার্কম্যান

132
def weighted_choice(choices):
   total = sum(w for c, w in choices)
   r = random.uniform(0, total)
   upto = 0
   for c, w in choices:
      if upto + w >= r:
         return c
      upto += w
   assert False, "Shouldn't get here"

10
লুপের ভিতরে বিবৃতিগুলি upto +=w; if upto > r
উল্টিয়ে

5
অবধি মুছে ফেলা এবং প্রতিবার ওজন কমিয়ে r হ্রাস করে একটি পরিবর্তনশীল সংরক্ষণ করুন। তারপরে তুলনাটি হ'লif r < 0
JnBrymn

@ JnBrymn আপনার যাচাই করা দরকার r <= 0। 1 টি আইটেমের ইনপুট সেট এবং 1.0 এর রোল বিবেচনা করুন। দৃ then়তা তখন ব্যর্থ হবে। আমি উত্তরে সেই ত্রুটিটি সংশোধন করেছি।
moooeeeep

1
@ সারদাথ্রিয়ন আপনি লুপটিকে আংশিক হিসাবে চিহ্নিত করতে একটি প্রগমা ব্যবহার করতে পারেন:# pragma: no branch
নেড ব্যাচেল্ডার

1
@ mLstudent33 আমি উদাসিটি ব্যবহার করি না।
অ্যান্টন

70
  1. ওজনকে সামগ্রিক বিতরণে সাজান।
  2. একটি এলোমেলো ফ্লোট বাছাই করতে random.random () ব্যবহার করুন 0.0 <= x < total
  3. ব্যবহার বন্টন অনুসন্ধান bisect.bisect যেমন এ উদাহরণে দেখানো http://docs.python.org/dev/library/bisect.html#other-examples
from random import random
from bisect import bisect

def weighted_choice(choices):
    values, weights = zip(*choices)
    total = 0
    cum_weights = []
    for w in weights:
        total += w
        cum_weights.append(total)
    x = random() * total
    i = bisect(cum_weights, x)
    return values[i]

>>> weighted_choice([("WHITE",90), ("RED",8), ("GREEN",2)])
'WHITE'

আপনার যদি একাধিক পছন্দ করার প্রয়োজন হয় তবে এটিকে দুটি ফাংশনে বিভক্ত করুন, একটি ক্রমবর্ধমান ওজন তৈরি করতে এবং অন্যটি এলোমেলো পয়েন্টে বিভক্ত করতে।


5
নেডের উত্তরের চেয়ে এটি আরও দক্ষ। মূলত, পছন্দগুলির মাধ্যমে লিনিয়ার (ও (এন)) অনুসন্ধান করার পরিবর্তে তিনি বাইনারি অনুসন্ধান (ও (লগ এন)) করছেন। +1 টি!
এনএইচডালি

টিপল সূচকটি সীমার বাইরে থাকলে (এলোমেলোভাবে 1.0) ফিরে আসে
জন ভন

10
O(n)ক্রমবর্ধমান বিতরণ গণনার কারণে এটি এখনও চলছে ।
লেভ লেভিটস্কি

6
একই ধরণের পছন্দগুলির জন্য ওয়েটেড-চয়েসে একাধিক কল প্রয়োজন হলে এই সমাধানটি আরও ভাল। সেক্ষেত্রে আপনি একবারে ক্রমসংখ্যাটি তৈরি করতে পারেন এবং প্রতিটি কলটিতে বাইনারি অনুসন্ধান করতে পারেন।
আমোস

1
@JonVaughan random() না পারেন, 1.0 ফিরে যান। ডক্স প্রতি, এটা অর্ধ খোলা ব্যবধান ফলে ফেরৎ [0.0, 1.0), যা বলতে চাই যে এটা করতে ঠিক 0.0 আসতে, কিন্তু করতে পারে না আসতে ঠিক 1.0। এটি ফিরে আসতে পারে এমন বৃহত্তম মানটি 0.99999999999999988897769753748434595763683319091796875 (যা পাইথনটি 0.9999999999999999 হিসাবে প্রিন্ট করে এবং এটি 1 এর চেয়ে বৃহত্তম 64-বিট ফ্লোট)।
মার্ক অ্যামেরি

21

আপনি numpy ব্যবহার কিছু মনে না করেন, তাহলে আপনি ব্যবহার করতে পারেন numpy.random.choice

উদাহরণ স্বরূপ:

import numpy

items  = [["item1", 0.2], ["item2", 0.3], ["item3", 0.45], ["item4", 0.05]
elems = [i[0] for i in items]
probs = [i[1] for i in items]

trials = 1000
results = [0] * len(items)
for i in range(trials):
    res = numpy.random.choice(items, p=probs)  #This is where the item is selected!
    results[items.index(res)] += 1
results = [r / float(trials) for r in results]
print "item\texpected\tactual"
for i in range(len(probs)):
    print "%s\t%0.4f\t%0.4f" % (items[i], probs[i], results[i])

আপনার যদি আগে থেকে কতগুলি নির্বাচন করা দরকার তা আপনি জানেন তবে আপনি এটির মতো লুপ ছাড়াই এটি করতে পারেন:

numpy.random.choice(items, trials, p=probs)

15

অপরিশোধিত, তবে যথেষ্ট হতে পারে:

import random
weighted_choice = lambda s : random.choice(sum(([v]*wt for v,wt in s),[]))

এটা কি কাজ করে?

# define choices and relative weights
choices = [("WHITE",90), ("RED",8), ("GREEN",2)]

# initialize tally dict
tally = dict.fromkeys(choices, 0)

# tally up 1000 weighted choices
for i in xrange(1000):
    tally[weighted_choice(choices)] += 1

print tally.items()

ছাপে:

[('WHITE', 904), ('GREEN', 22), ('RED', 74)]

ধরে নেওয়া যায় যে সমস্ত ওজন পূর্ণসংখ্যা হয়। তাদের 100 টি যোগ করার দরকার নেই, আমি পরীক্ষার ফলাফলগুলি আরও সহজে ব্যাখ্যা করার জন্য এটি করেছি। (যদি ওজনগুলি ভাসমান পয়েন্ট সংখ্যা হয় তবে সমস্ত ওজন> = 1 না হওয়া পর্যন্ত এগুলি সমস্ত 10 বার বার করুন)

weights = [.6, .2, .001, .199]
while any(w < 1.0 for w in weights):
    weights = [w*10 for w in weights]
weights = map(int, weights)

1
ভাল, আমি নিশ্চিত না যে আমি সমস্ত ওজন পূর্ণসংখ্যা হিসাবে ধরে নিতে পারি।
কলিন 19

1
মনে হচ্ছে আপনার উদাহরণগুলি এই উদাহরণটিতে নকল হবে। এটি অদক্ষ হয়ে উঠবে (এবং ওজনকে পূর্ণসংখ্যায় রূপান্তর করার জন্য কাজটিও তাই)। তবুও, পূর্ণসংখ্যার ওজন কম হলে এই দ্রবণটি ভাল ওয়ান-লাইনার।
wei2912

প্রিমিটিভগুলি অনুলিপি করা হবে, তবে বস্তুগুলির কেবলমাত্র রেফারেন্সগুলি নকল হবে, বস্তুগুলি সেগুলি নিজেই নয়। (এ কারণেই আপনি তালিকা ব্যবহার করে তালিকার তালিকা তৈরি করতে পারবেন না [[]]*10- বাইরের তালিকার সমস্ত উপাদান একই তালিকার দিকে নির্দেশ করে।
পলমিসজি

@ পলমিসজি নং; রেফারেন্সগুলি ছাড়া আর কিছুই নকল হবে না। পাইথনের টাইপ সিস্টেমে আদিম ধারণা নেই। আপনি নিশ্চিত করতে পারেন যে, উদাহরণস্বরূপ একটি সহ intআপনি এখনও একই জিনিসটির মতো অনেক কিছু করে রেফারেন্স পেয়ে যাচ্ছেন [id(x) for x in ([99**99] * 100)]এবং পর্যবেক্ষণ করুন যা idপ্রতিটি কলে একই মেমরি ঠিকানা ফেরত দেয়।
মার্ক

14

যদি আপনার তালিকার পরিবর্তে ভারী অভিধান থাকে তবে আপনি এটি লিখতে পারেন

items = { "a": 10, "b": 5, "c": 1 } 
random.choice([k for k in items for dummy in range(items[k])])

নোট যে [k for k in items for dummy in range(items[k])]এই তালিকা উত্পাদন করে['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'b', 'b', 'b', 'b', 'b']


10
এটি ছোট মোট জনসংখ্যার মানগুলির জন্য কাজ করে তবে বড় ডেটাসেটের জন্য নয় (উদাহরণস্বরূপ মার্কিন যুক্তরাষ্ট্রে জনসংখ্যা এতে 300 মিলিয়ন আইটেম সহ একটি ওয়ার্কিং লিস্ট তৈরি করবে)।
রায়ান

রিয়ান এটি অ-পূর্ণসংখ্যক ওজনগুলির জন্যও কাজ করে না, যা আরও একটি বাস্তব চিত্র (যেমন আপনার যদি ওজন নির্বাচনের সম্ভাবনা হিসাবে প্রকাশ করা থাকে)।
মার্ক

12

পাইথন এর হিসাবে v3.6, random.choicesএকটি ফিরে যাওয়ার ব্যবহার করা যেতে পারে listঐচ্ছিক ওজন দিয়ে নির্দিষ্ট জনসংখ্যা থেকে নির্দিষ্ট করা আকার উপাদান।

random.choices(population, weights=None, *, cum_weights=None, k=1)

  • জনসংখ্যা : listঅনন্য পর্যবেক্ষণ সমন্বিত। (খালি থাকলে, উত্থাপন IndexError)

  • ওজন : নির্বাচন করার জন্য আরও নির্দিষ্টভাবে তুলনামূলকভাবে ওজন প্রয়োজন required

  • কাম_উইটস : নির্বাচনগুলি করার জন্য ক্রমযুক্ত ওজন প্রয়োজন।

  • কে : আকার ( len) এর listআউটপুট করা হবে। (ডিফল্ট len()=1)


কয়েকটি গুহাত:

1) এটি প্রতিস্থাপনের সাথে ওজনযুক্ত নমুনা ব্যবহার করে যাতে আঁকানো আইটেমগুলি পরে প্রতিস্থাপন করা হয়। ওজন ক্রমের মানগুলি নিজেই মূল্য দেয় না, তবে তাদের তুলনামূলক অনুপাত হয়।

np.random.choiceযা কেবলমাত্র ওজন হিসাবে সম্ভাব্যতা গ্রহণ করতে পারে এবং পৃথক সম্ভাবনার সংশ্লেষ 1 মানদণ্ড অবধি নিশ্চিত করতে হবে তার বিপরীতে , এখানে এ জাতীয় কোনও বিধিবিধান নেই। যতক্ষণ না তারা সংখ্যার ধরণের ( প্রকার int/float/fractionব্যতীত Decimal) অন্তর্ভুক্ত থাকে ততক্ষণ এগুলি সম্পাদন করবে।

>>> import random
# weights being integers
>>> random.choices(["white", "green", "red"], [12, 12, 4], k=10)
['green', 'red', 'green', 'white', 'white', 'white', 'green', 'white', 'red', 'white']
# weights being floats
>>> random.choices(["white", "green", "red"], [.12, .12, .04], k=10)
['white', 'white', 'green', 'green', 'red', 'red', 'white', 'green', 'white', 'green']
# weights being fractions
>>> random.choices(["white", "green", "red"], [12/100, 12/100, 4/100], k=10)
['green', 'green', 'white', 'red', 'green', 'red', 'white', 'green', 'green', 'green']

2) ওজন বা কাম_উইট উভয়ই নির্দিষ্ট না করা থাকলে, সমান সম্ভাবনা নিয়ে নির্বাচন করা হয়। যদি একটি ওজন ক্রম সরবরাহ করা হয় তবে এটি অবশ্যই জনসংখ্যার ক্রমের সমান দৈর্ঘ্য হতে হবে ।

উভয় নির্দিষ্ট করা ওজন এবং cum_weights একটি উত্থাপন TypeError

>>> random.choices(["white", "green", "red"], k=10)
['white', 'white', 'green', 'red', 'red', 'red', 'white', 'white', 'white', 'green']

3) কাম_উইটগুলি সাধারণত itertools.accumulateফাংশনের ফলাফল যা এই পরিস্থিতিতে সত্যই কার্যকর।

লিঙ্কযুক্ত ডকুমেন্টেশন থেকে:

অভ্যন্তরীণভাবে, তুলনা করার আগে আপেক্ষিক ওজনগুলি संचयी ওজনে রূপান্তরিত হয়, সুতরাং ক্রমবর্ধমান ওজনের সরবরাহ কাজ সাশ্রয় করে।

সুতরাং, সরবরাহ করা হয় weights=[12, 12, 4]বা cum_weights=[12, 24, 28]আমাদের দ্বন্দ্বযুক্ত ক্ষেত্রে একই ফলাফল উত্পন্ন করে এবং পরবর্তীকালে আরও দ্রুত / দক্ষ বলে মনে হয়।


11

পাইথন 3.6 এর জন্য স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্ভুক্ত করা সংস্করণটি এখানে:

import itertools as _itertools
import bisect as _bisect

class Random36(random.Random):
    "Show the code included in the Python 3.6 version of the Random class"

    def choices(self, population, weights=None, *, cum_weights=None, k=1):
        """Return a k sized list of population elements chosen with replacement.

        If the relative weights or cumulative weights are not specified,
        the selections are made with equal probability.

        """
        random = self.random
        if cum_weights is None:
            if weights is None:
                _int = int
                total = len(population)
                return [population[_int(random() * total)] for i in range(k)]
            cum_weights = list(_itertools.accumulate(weights))
        elif weights is not None:
            raise TypeError('Cannot specify both weights and cumulative weights')
        if len(cum_weights) != len(population):
            raise ValueError('The number of weights does not match the population')
        bisect = _bisect.bisect
        total = cum_weights[-1]
        return [population[bisect(cum_weights, random() * total)] for i in range(k)]

সূত্র: https://hg.python.org/cpython/file/tip/Lib/random.py#l340


2
import numpy as np
w=np.array([ 0.4,  0.8,  1.6,  0.8,  0.4])
np.random.choice(w, p=w/sum(w))

2

দরকারী কিছু অবদানের জন্য আমি সম্ভবত খুব দেরি করেছি, তবে এখানে একটি সহজ, সংক্ষিপ্ত এবং খুব দক্ষ স্নিপেট রয়েছে:

def choose_index(probabilies):
    cmf = probabilies[0]
    choice = random.random()
    for k in xrange(len(probabilies)):
        if choice <= cmf:
            return k
        else:
            cmf += probabilies[k+1]

আপনার সম্ভাব্যতাগুলি বাছাই করতে বা আপনার সেমিফের সাহায্যে একটি ভেক্টর তৈরি করার দরকার নেই এবং এটি তার পছন্দটি খুঁজে পাওয়ার পরে এটি সমাপ্ত হয়। স্মৃতি: ও (1), সময়: ও (এন), গড় চলমান সময় সহ with N / 2।

যদি আপনার ওজন হয় তবে কেবল একটি লাইন যুক্ত করুন:

def choose_index(weights):
    probabilities = weights / sum(weights)
    cmf = probabilies[0]
    choice = random.random()
    for k in xrange(len(probabilies)):
        if choice <= cmf:
            return k
        else:
            cmf += probabilies[k+1]

1
এর সাথে বেশ কয়েকটি জিনিস ভুল। অতিমাত্রায়, এখানে কিছু টাইপযুক্ত ভেরিয়েবলের নাম রয়েছে এবং এটি ব্যবহার করার জন্য কোনও যুক্তি দেওয়া হয়নি, বলুন np.random.choice। তবে আরও মজার বিষয় হল একটি ব্যর্থতা মোড রয়েছে যেখানে এটি একটি ব্যতিক্রম বাড়ে। করা probabilities = weights / sum(weights)গ্যারান্টি দেয় না যে probabilities1 এর সমষ্টি হবে; উদাহরণস্বরূপ, যদি weightsহয় [1,1,1,1,1,1,1]তবে probabilitiesকেবলমাত্র 0.99999999999999988 এর সমষ্টি হবে, এটির বৃহত্তম সম্ভাব্য রিটার্ন মানের চেয়ে ছোট random.random(যা 0.9999999999999999)। তারপর choice <= cmfকখনও সন্তুষ্ট হয় না।
মার্ক

2

যদি আপনার ওজনযুক্ত পছন্দগুলির তালিকা তুলনামূলক স্থিতিশীল হয় এবং আপনি ঘন ঘন নমুনা চান তবে আপনি এই সম্পর্কিত উত্তরের ক্রিয়াগুলি ব্যবহার করে একটি ও (এন) প্রিপ্রোসেসিং পদক্ষেপ করতে পারেন এবং তারপরে ও (1) এ নির্বাচন করতে পারেন ।

# run only when `choices` changes.
preprocessed_data = prep(weight for _,weight in choices)

# O(1) selection
value = choices[sample(preprocessed_data)][0]

1

আমি অন্য নির্দেশিত থ্রেডটি দেখলাম এবং আমার কোডিং শৈলীতে এই প্রকরণটি নিয়ে এসেছি, এটি টালিংয়ের উদ্দেশ্যে পছন্দের সূচকটি ফেরত দেয় তবে স্ট্রিংটি ফিরে আসা সহজ (মন্তব্যযুক্ত রিটার্ন বিকল্প):

import random
import bisect

try:
    range = xrange
except:
    pass

def weighted_choice(choices):
    total, cumulative = 0, []
    for c,w in choices:
        total += w
        cumulative.append((total, c))
    r = random.uniform(0, total)
    # return index
    return bisect.bisect(cumulative, (r,))
    # return item string
    #return choices[bisect.bisect(cumulative, (r,))][0]

# define choices and relative weights
choices = [("WHITE",90), ("RED",8), ("GREEN",2)]

tally = [0 for item in choices]

n = 100000
# tally up n weighted choices
for i in range(n):
    tally[weighted_choice(choices)] += 1

print([t/sum(tally)*100 for t in tally])

1

আপনি কতবার বিতরণটি নমুনা করতে চান তার উপর নির্ভর করে।

মনে করুন আপনি কে কে ডিস্ট্রিবিউশনটি নমুনা করতে চান। তারপর, ব্যবহার সময় জটিলতা np.random.choice()প্রতিটি সময় হয় O(K(n + log(n)))যখন nবন্টন আইটেম সংখ্যা।

আমার ক্ষেত্রে, আমার একই ডিস্ট্রিবিউশন 10 the 3 ক্রমের একাধিক বার নমুনা করা দরকার যেখানে এন 10 10 6 এর ক্রম। আমি নীচের কোডটি ব্যবহার করেছি, যা সংযোজনীয় বিতরণকে পূর্বরূপ দেয় এবং এতে নমুনা দেয় O(log(n))। সামগ্রিকভাবে সময় জটিলতা হয় O(n+K*log(n))

import numpy as np

n,k = 10**6,10**3

# Create dummy distribution
a = np.array([i+1 for i in range(n)])
p = np.array([1.0/n]*n)

cfd = p.cumsum()
for _ in range(k):
    x = np.random.uniform()
    idx = cfd.searchsorted(x, side='right')
    sampled_element = a[idx]

1

আপনি যদি পাইথন 3 পেয়ে থাকেন এবং numpyনিজের লুপগুলি ইনস্টল বা লেখার ভয় পান তবে আপনি এটি করতে পারেন:

import itertools, bisect, random

def weighted_choice(choices):
   weights = list(zip(*choices))[1]
   return choices[bisect.bisect(list(itertools.accumulate(weights)),
                                random.uniform(0, sum(weights)))][0]

কারণ আপনি প্লাম্বিং অ্যাডাপ্টারগুলির একটি ব্যাগের বাইরে যা কিছু তৈরি করতে পারেন ! যদিও ... আমাকে অবশ্যই তা স্বীকার করতে হবে যে নেডের উত্তরটি কিছুটা দীর্ঘ সময় ধরে বোঝা সহজ।


0

একটি সাধারণ সমাধান:

import random
def weighted_choice(choices, weights):
    total = sum(weights)
    treshold = random.uniform(0, total)
    for k, weight in enumerate(weights):
        total -= weight
        if total < treshold:
            return choices[k]

0

এখানে ওয়েটেড চয়েসের আর একটি সংস্করণ রয়েছে যা নিম্পি ব্যবহার করে। ওয়েট ভেক্টরে পাস করুন এবং এটি 0 এর একটি অ্যারে ফিরে আসবে যেখানে 1 টি নির্দেশ করে কোনটি বেছে নেওয়া হয়েছিল। কোডটি কেবল একটি একক ড্র করার জন্য ডিফল্ট হয় তবে আপনি যে অঙ্কন করতে হবে তার সংখ্যাটিতে পাস করতে পারবেন এবং প্রতি বিন্যাসের অঙ্কগুলি ফিরিয়ে দেওয়া হবে।

যদি ওয়েট ভেক্টর 1 এর সমষ্টি না হয় তবে এটি স্বাভাবিক হবে যাতে এটি হয়।

import numpy as np

def weighted_choice(weights, n=1):
    if np.sum(weights)!=1:
        weights = weights/np.sum(weights)

    draws = np.random.random_sample(size=n)

    weights = np.cumsum(weights)
    weights = np.insert(weights,0,0.0)

    counts = np.histogram(draws, bins=weights)
    return(counts[0])

0

এটি করার আর একটি উপায়, ধরে নিই যে উপাদান সূচিতে থাকা উপাদানগুলির মতো একই সূচীতে আমাদের ওজন রয়েছে।

import numpy as np
weights = [0.1, 0.3, 0.5] #weights for the item at index 0,1,2
# sum of weights should be <=1, you can also divide each weight by sum of all weights to standardise it to <=1 constraint.
trials = 1 #number of trials
num_item = 1 #number of items that can be picked in each trial
selected_item_arr = np.random.multinomial(num_item, weights, trials)
# gives number of times an item was selected at a particular index
# this assumes selection with replacement
# one possible output
# selected_item_arr
# array([[0, 0, 1]])
# say if trials = 5, the the possible output could be 
# selected_item_arr
# array([[1, 0, 0],
#   [0, 0, 1],
#   [0, 0, 1],
#   [0, 1, 0],
#   [0, 0, 1]])

এখন ধরে নেওয়া যাক, 1 পরীক্ষায় আমাদের 3 টি আইটেমের নমুনা বের করতে হবে। আপনি ধরে নিতে পারেন যে ওজন অ্যারের দ্বারা প্রদত্ত ওজনের অনুপাত অনুসারে তিনটি বল আর, জি, বি প্রচুর পরিমাণে উপস্থিত রয়েছে, নিম্নলিখিত সম্ভাব্য ফলাফল হতে পারে:

num_item = 3
trials = 1
selected_item_arr = np.random.multinomial(num_item, weights, trials)
# selected_item_arr can give output like :
# array([[1, 0, 2]])

আপনি সেটগুলির মধ্যে দ্বি-দ্বি / বহুজাতিক ট্রায়ালগুলির সংখ্যা হিসাবে নির্বাচিত আইটেমগুলির সংখ্যাও ভাবতে পারেন। সুতরাং, উপরোক্ত উদাহরণ হিসাবে এখনও কাজ হতে পারে

num_binomial_trial = 5
weights = [0.1,0.9] #say an unfair coin weights for H/T
num_experiment_set = 1
selected_item_arr = np.random.multinomial(num_binomial_trial, weights, num_experiment_set)
# possible output
# selected_item_arr
# array([[1, 4]])
# i.e H came 1 time and T came 4 times in 5 binomial trials. And one set contains 5 binomial trails.

0

রোবোটিক্সের ফ্রি উদ্যাটি কোর্স এআই-তে সেবাস্তিন থর্নের এই বিষয়ে বক্তৃতা রয়েছে। মূলত তিনি মোড অপারেটরটি ব্যবহার করে সূচকযুক্ত ওজনের একটি বৃত্তাকার অ্যারে তৈরি করেন %, 0 এ একটি পরিবর্তনশীল বিটা সেট করে, এলোমেলোভাবে একটি সূচক নির্বাচন করে N এর মাধ্যমে লুপের জন্য যেখানে এন সূচকগুলির সংখ্যা এবং লুপের জন্য সূত্রের মাধ্যমে প্রথমে ইনক্রিমেন্ট বিটা:

বিটা = বিটা + ইউনিফর্ম নমুনা থেকে {0 ... 2 * ওজন_ম্যাক্স}

এবং তারপরে নীচে প্রতি লুপের জন্য কিছুক্ষণ লুপটিতে নেস্ট করলেন:

while w[index] < beta:
    beta = beta - w[index]
    index = index + 1

select p[index]

তারপরে সম্ভাব্যতার উপর ভিত্তি করে পুনরায় নমুনা করার জন্য পরবর্তী সূচীতে (বা কোর্সে উপস্থাপিত ক্ষেত্রে সাধারন সম্ভাবনা)।

বক্তৃতার লিঙ্ক: https://classroom.udacity.com/courses/cs373/lessons/48704330/concepts/487480820923

আমি আমার স্কুল অ্যাকাউন্টের সাথে উদাসিতে লগইন করেছি তাই লিঙ্কটি যদি কাজ না করে তবে এটি পাঠ 8, রোবোটিক্সের জন্য কৃত্রিম বুদ্ধিমত্তার 21 নম্বর ভিডিও যেখানে তিনি কণা ফিল্টারগুলিতে বক্তৃতা দিচ্ছেন।


-1

একটি উপায় হ'ল সমস্ত ওজনের মোটের উপর র্যান্ডমাইজ করা এবং তারপরে প্রতিটি ভ্যারির সীমা পয়েন্ট হিসাবে মানগুলি ব্যবহার করা। এখানে জেনারেটর হিসাবে একটি অপরিশোধিত প্রয়োগ রয়েছে।

def rand_weighted(weights):
    """
    Generator which uses the weights to generate a
    weighted random values
    """
    sum_weights = sum(weights.values())
    cum_weights = {}
    current_weight = 0
    for key, value in sorted(weights.iteritems()):
        current_weight += value
        cum_weights[key] = current_weight
    while True:
        sel = int(random.uniform(0, 1) * sum_weights)
        for key, value in sorted(cum_weights.iteritems()):
            if sel < value:
                break
        yield key

-1

অদ্ভুত ব্যবহার

def choice(items, weights):
    return items[np.argmin((np.cumsum(weights) / sum(weights)) < np.random.rand())]

নুমপি ইতিমধ্যে np.random.choice২০১৪ সাল থেকে এখানে থাকা স্বীকৃত উত্তরে উল্লিখিত রয়েছে your আপনার নিজের ঘূর্ণায়মানটি কী?
মার্ক

-1

আমি শেষ পর্যন্ত এই টেমপ্লেটটি তৈরি করেছি ধারণাগুলি অনুসন্ধান করা থেকে, সত্যিই খুব দ্রুত সত্যই এরকম কিছু করার দরকার ছিল। ধারণাটি এপিআই থেকে একটি জসনের আকারে ভারিত মানগুলি গ্রহণ করে যা এখানে ডিক দ্বারা অনুকরণযুক্ত।

তারপরে এটিকে এমন তালিকায় অনুবাদ করুন যাতে প্রতিটি মান তার ওজনের সাথে আনুপাতিকভাবে পুনরাবৃত্তি করে এবং তালিকা থেকে কোনও মান নির্বাচন করতে কেবল এলোমেলোভাবে পছন্দ বেছে নিন।

আমি এটি 10, 100 এবং 1000 পুনরাবৃত্তির সাথে চালানোর চেষ্টা করেছি। বিতরণটি বেশ শক্ত বলে মনে হচ্ছে।

def weighted_choice(weighted_dict):
    """Input example: dict(apples=60, oranges=30, pineapples=10)"""
    weight_list = []
    for key in weighted_dict.keys():
        weight_list += [key] * weighted_dict[key]
    return random.choice(weight_list)

-1

আমি এগুলির কোনওটির বাক্য গঠনটি পছন্দ করি না। আমি সত্যিই কেবল আইটেমগুলি কী ছিল এবং প্রত্যেকের ওজন কী তা নির্দিষ্ট করতে চেয়েছিলাম। আমি বুঝতে পারি আমি ব্যবহার করতে পারতাম random.choicesতবে পরিবর্তে আমি দ্রুত নীচের ক্লাসটি লিখেছিলাম।

import random, string
from numpy import cumsum

class randomChoiceWithProportions:
    '''
    Accepts a dictionary of choices as keys and weights as values. Example if you want a unfair dice:


    choiceWeightDic = {"1":0.16666666666666666, "2": 0.16666666666666666, "3": 0.16666666666666666
    , "4": 0.16666666666666666, "5": .06666666666666666, "6": 0.26666666666666666}
    dice = randomChoiceWithProportions(choiceWeightDic)

    samples = []
    for i in range(100000):
        samples.append(dice.sample())

    # Should be close to .26666
    samples.count("6")/len(samples)

    # Should be close to .16666
    samples.count("1")/len(samples)
    '''
    def __init__(self, choiceWeightDic):
        self.choiceWeightDic = choiceWeightDic
        weightSum = sum(self.choiceWeightDic.values())
        assert weightSum == 1, 'Weights sum to ' + str(weightSum) + ', not 1.'
        self.valWeightDict = self._compute_valWeights()

    def _compute_valWeights(self):
        valWeights = list(cumsum(list(self.choiceWeightDic.values())))
        valWeightDict = dict(zip(list(self.choiceWeightDic.keys()), valWeights))
        return valWeightDict

    def sample(self):
        num = random.uniform(0,1)
        for key, val in self.valWeightDict.items():
            if val >= num:
                return key

-1

প্রাক-ওজনযুক্ত তালিকার সাথে র্যান্ডম.চয়েস () সরবরাহ করুন:

সমাধান এবং পরীক্ষা:

import random

options = ['a', 'b', 'c', 'd']
weights = [1, 2, 5, 2]

weighted_options = [[opt]*wgt for opt, wgt in zip(options, weights)]
weighted_options = [opt for sublist in weighted_options for opt in sublist]
print(weighted_options)

# test

counts = {c: 0 for c in options}
for x in range(10000):
    counts[random.choice(weighted_options)] += 1

for opt, wgt in zip(options, weights):
    wgt_r = counts[opt] / 10000 * sum(weights)
    print(opt, counts[opt], wgt, wgt_r)

আউটপুট:

['a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'd', 'd']
a 1025 1 1.025
b 1948 2 1.948
c 5019 5 5.019
d 2008 2 2.008
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.