抽样时不使用相同权重的无放回抽样

4
我正在寻找一种算法,根据每个元素的概率从25个元素的列表中选择12个。这些元素不能重复。
我尝试使用无替换的函数,但是当我进行1000次迭代以检查是否正确时,我无法让它保留权重。只有在使用replace = True函数时我才成功了。
由于该函数返回重复项,因此我清理列表以删除重复项。这样做会导致我获取每个数字的概率与一开始定义的不同。我知道错误在这里,我应该使用replace = False函数,但我无法得到结果。
import numpy as np
from collections import Counter 

nameList = ['AAAAAA', 'B', 'C', 'D','E','F','G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','Q','R','S','T','U','V','W','X','ZZZZZZZZZZZZZZZZ']
probability_nameList = [0.10, 0.01, 0.02, 0.03, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]

sampleNames =[]
sampleNamesControl =[]
cleaned_result = []
test_list = []

for i in range(1000):
    sampleNames += np.random.choice(nameList, 100,replace=True, p=probability_nameList)
    for item in sampleNames:    
        if not item in cleaned_result:
            cleaned_result += [item] 
    sampleNames =[]
    test_list += cleaned_result[0:12]
    cleaned_result = []

print(Counter(test_list))

响应:

Counter({'AAAAAA': 832, 'F': 522, 'X': 513, 'ZZZZZZZZZZZZZZZZ': 506, 'I': 505, 'L': 504, 'N': 501, 'S': 499, 'T': 498, 'U': 496, 'R': 492, 'O': 491, 'J': 489, 'P': 488, 'E': 487, 'V': 485, 'K': 482, 'Q': 479, 'H': 473, 'G': 471, 'M': 468, 'W': 461, 'D': 404, 'C': 297, 'B': 157})

从上述公式可以看出,AAAAA必须比B大10倍,但实际情况并不是这样。 P(AAAAA)= 10xP(B)

2个回答

5
这不是编程问题,而是基本数学问题:你想要的是不可能的。 你需要考虑条件概率
我给你举个小例子。我们选取4个字母A、B、C、D中的2个字母,不放回,其中A被选中的概率为97%,其他字母的概率为1%。
由于A的高概率,它大多数情况下会被选中。但是一旦我们选择了它,由于我们是不放回的,就没有A可选了,而是有1/3的机会选择其他三个值之一。
确实如此:
from itertools import chain
from collections import Counter

Counter(chain.from_iterable(np.random.choice(list('ABCD'),
                                             2, replace=False,
                                             p=[.97, .01, .01, .01])
                            for i in range(10000)))

输出:

Counter({'A': 9995, 'C': 3358, 'B': 3317, 'D': 3330})

大部分时间都会选择A,其他选项被选中的概率约为三分之一。

注意:B、C、D的最终频率大约为1/3,因为A的概率接近于1,如果p(A)更小,最终频率的计算将会更加复杂。B(或C或D)的最终频率为0.97*1/3+0.01*(0.01/0.99)*2+0.01,略高于1/3,而A的频率为0.97+0.01*(0.97/0.99)*3,约为0.9994。


1

如果您不介意逐个弹出,请使用 random.choices 而不是 Numpy 的随机函数:

from random import choices

nameList = ['AAAAAA', 'B', 'C', 'D','E','F','G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','Q','R','S','T','U','V','W','X','ZZZZZZZZZZZZZZZZ']

probability_nameList = [0.10, 0.01, 0.02, 0.03, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]

tuples = list(zip(nameList, probability_nameList))

results = []
for _ in range(12):
    element = choices(*list(zip(*tuples)))
    tuples = [tup for tup in tuples if tup[0] != element]
    results.append(element)

print(results)

# [['AAAAAA'], ['G'], ['X'], ['U'], ['R'], ['U'], ['K'], ['D'], ['Q'], ['AAAAAA'], ['S'], ['AAAAAA']]

以上的方法是通过创建元素/概率对,例如('AAAAAA', 0.01)('B', 0.01)等等。我们使用第二部分作为概率调用random.choices来获取一个元素。然后我们从列表中删除相应的元组并再次执行。结果将附加到输出列表中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接