【问题标题】:Randomly selection of number from list of integers which is proportional to its magnitude从整数列表中随机选择与其大小成正比的数字
【发布时间】:2019-12-15 17:25:25
【问题描述】:

从给定的 n 个元素数组中随机选择一个数字,其概率与它的大小成正比 考虑一个实验,从列表 A 中随机选择一个元素,概率与它的大小成正比。 假设我们在替换的情况下进行 100 次相同的实验,在每个实验中,您将打印一个从 A 中随机选择的数字。

例 1:A = [0 5 27 6 13 28 100 45 10 79] 令 f(x) 表示 x 在 100 次实验中被选中的次数。 f(100) > f(79) > f(45) > f(28) > f(27) > f(13) > f(10) > f(6) > f(5) > f(0)

def pick_a_number_from_list(A):
    sum=0
    cum_sum=[]
    for i in range(len(A)):
        sum = sum + A[i]
        cum_sum.append(sum)
    #print(cum_sum)           
    r = random.uniform(0,sum)
    number=0
    for index,i in enumerate(cum_sum):
        if(r>=cum_sum[index] and r<cum_sum[index+1]):
            return A[index]
    return number

def sampling_based_on_magnitued():
    A = [0,5,27,6,13,28,100,45,10,79]
    for i in range(1,100):
        number = pick_a_number_from_list(A)
        print(number)

sampling_based_on_magnitued()

我已经编写了上面的代码,但没有得到正确的输出。

【问题讨论】:

  • **我已经编写了上面的代码,但没有得到正确的输出。有人可以帮我理解我做错了什么。
  • 您面临的问题是什么?
  • 根据问题它应该从列表中返回 100 的最大次数和 0 分钟的次数,但代码没有返回预期的输出

标签: python random


【解决方案1】:

这是您犯的逻辑错误。当您检查范围时 r&gt;=cum_sum[index] and r&lt;cum_sum[index+1],您实际上使用的是号码A[index+1],而不是A[index]

import random

def pick_a_number_from_list(A):
    sum=0
    cum_sum=[]
    for i in range(len(A)):
        sum = sum + A[i]
        cum_sum.append(sum)
    #print(cum_sum) 
    r = int(random.uniform(0,sum))
    print(r)
    number=0
    for index in range(len(cum_sum)):
        if(r>=cum_sum[index] and r<cum_sum[index+1]):
            return A[index+1]
    return number

def sampling_based_on_magnitued():
    A = [0,5,27,6,13,28,100,45,10,79]
    a = dict()
    #A.sort()
    print(A,sum(A))
    for i in range(1,100):
        number = pick_a_number_from_list(A)
        #print(number)
        if number not in a:
            a[number] = 1
        else:
            a[number]+=1
    print(a)

sampling_based_on_magnitued()

这是我在机器上得到的最终选择频率

{100: 35, 5: 1, 45: 15, 79: 20, 28: 8, 13: 8, 6: 2, 27: 9, 10: 1}

【讨论】:

  • 您在哪里进行了更改?
  • 嗨 Raj,它总是不能提供正确的输出,有时小数字打印的时间比大数字多。
  • 不能仅使用100 测试样本进行分析。对于足够大的样本和真正的随机数生成器,这将正常工作。
【解决方案2】:
from random import uniform

def pick_a_number_from_list(A):
    # picking an element from with the probability propotional to its 
    magnitude
 
    #Find the sum of the elements of List A
    sum=0
    for ele in A:
        sum+=ele
    #print(sum)

    #Normalizing the values using the sum
    D=[]
    for ele in A:
        d=ele/sum
        e=round(d,5)
        D.append(e)
    #print(D)

    #Cumulative Normalized Values
    C=[0]
    c=0
    for ele in D:
        c=c+ele
        f=round(c,5)
        C.append(f)
     #print(len(C))
     #print(C)

    #Find the Ramdom sampling by using uniform() between 0 to 1
    r=uniform(0.0,1.0)
    ran=round(r,5)
    #print(ran)

    # proportional Sampling 
    #number=0
    for i in range(len(C)-1):
        if(r>=C[i] and r <C[i+1]):
            #print(A[i])
            return A[i]
    #return number
    
def sampling_based_on_magnitued():
    A=[]
    n=int(input("Enter the length of List\n"))
    print("Enter the Elements between 1 to 100 in List A")
    for i in range(n):
        A.append(float(input()))
    print("The Elements in a List A are\n")
    print("A =",A)
    B=[]
    print("The Random Numbers generated between 1 to 100 are \n")
    for i in range(1,100):
         number = pick_a_number_from_list(A)
         B.append(number)
    print(B)
    #print(number)
    # To Print the Count of no of occurence of Number Ramdonly
    c=(sorted(A, reverse=True))
    print(c)
    for ele in c:
        print("count of {} is".format(ele),B.count(ele))     
sampling_based_on_magnitued()

【讨论】:

    【解决方案3】:

    如果您的权重列表 > 0,您可以根据这些权重从概率分布中抽样,方法是将每个权重映射到指数分布中的样本,然后选择结果最低的元素。参数为 0 的指数分布是不可能的,但我们可以通过映射到 math.inf 来处理 0。这保证了概率与权重成正比 (see Wikipedia)。

    import math
    import random
    
    def choose_with_weights(weights, lst=None):
        def sample(w):
            if w < 0:
                raise ValueError('Negative weight')
            elif w == 0:
                return math.inf
            else:
                return random.expovariate(w)
    
        _, min_i = min((sample(w), i) for i, w in enumerate(weights))
        return (lst or weights)[min_i]
    

    如果你的权重不能包含0,那么你可以删除sample辅助函数,直接使用random.expovariate

    示例,通过Counter 显示生成的分布:

    >>> from collections import Counter
    >>> Counter(choose_with_weights([1, 2, 3]) for i in range(60000))
    Counter({3: 29812, 2: 20089, 1: 10099})
    >>> Counter(choose_with_weights([1, 2, 3], ['a', 'b', 'c']) for i in range(60000))
    Counter({'c': 30079, 'b': 20127, 'a': 9794})
    

    【讨论】:

      【解决方案4】:

      Numpy 可以选择额外的随机函数来解释概率分布。你应该使用这个。

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

      在你的情况下你可以使用

      from numpy.random import choice
      
      A = [0,5,27,6,13,28,100,45,10,79]
      sumA=sum(A)
      probability=[item/sumA for item in A]
      for i in range(1,100):
          number = choice(A, 1, p=probability)
          print(number)
      

      打印出来的数字的概率分布与其大小成正比。这里值 0 的概率为 0,但如果您想将某些概率设为零,您可以提供一个更好的公式来计算概率分布

      【讨论】:

        猜你喜欢
        • 2020-01-13
        • 2015-10-26
        • 1970-01-01
        • 1970-01-01
        • 2021-03-05
        • 2021-12-15
        • 1970-01-01
        • 1970-01-01
        • 2013-01-16
        相关资源
        最近更新 更多