Python 随机选择 'percentage'

Python Random choice with 'percentage'

前言

它看起来像是几个 Whosebug 问题的重复,但我的情况(可能)有点独特。

我的情况

我有一本字典。 key 是一个 stringvalue 是一个 integer.

我希望 python 脚本随机选择 Nkeys.

值是被选中的可能性。密钥的值越高,随机选择密钥的机会就越大。

我的解决方案

所以使用其他一些 Whosebug post 和互联网的力量我设法使用 Weighted Random.

解决了这个问题
DICT_VAR= {'best':308281009, 'good':7066325, 'meh':26884, 'bad':71, 'terrible':16, 'never':0}

list_var = []
for i in DICT_VAR.keys():
    list_var.extend([i]*DICT_VAR[i])

print random.sample(list_var, 2) # get 2 random choice I suppose

问题(问题)

你可能注意到了,字典中的值可以非常大(可以无限大)也可以小到0(0是最小的,没有负数)。

运行 此代码(数字稍大)导致我的计算机死机并且没有响应,直到我硬重置它。

我的问题

我应该如何处理这种情况?有没有其他适合我情况的随机选择方式,因为 Weighted Random 是当前情况下最糟糕的解决方案。

我这里假设值0意味着永远不应该选择键,键可能在样本中重复(在字典中是无关紧要的),我们可能会使用第三方模块——在本例中为 numpy。这是在 Python 3.6.4 中测试的代码,但我对其进行了修改,因此它 应该 运行 在 Python 2.7 中,但我无法测试它那样。

DICT_VAR= {'best':308281009, 'good':7066325, 'meh':26884, 'bad':71,
           'terrible':16, 'never':0}

import numpy as np

keys, weights = zip(*DICT_VAR.items())
probs = np.array(weights, dtype=float) / float(sum(weights))
sample_np = np.random.choice(keys, 2, p=probs)
sample = [str(val) for val in sample_np]

然后 sample 将您的样本保存为关键字符串列表。请注意,键 'best' 的权重比其他权重大得多,因此您的样本几乎总是 ['best', 'best'].

解释一下我的代码:首先将字典的键(字符串)和值(权重)拆分成单独的列表。然后将权重更改为概率——权重越大概率越大,权重为零则概率为零。然后使用 numpy 的 choice 函数以概率作为权重来选择键样本。结果是一个 numpy 数组,但您似乎想要一个标准的 Python 列表,因此最后一行将键样本转换为标准列表。

当然,可以用标准 Python 编写一个相当短的例程,这样我们就可以避免使用 numpy。但它很可能会更慢。

您的例程运行缓慢的原因是它构建了一个大列表,每个键重复其值给定的次数,然后以均匀概率选择样本。对于您的示例数据,这意味着构建一个巨大的列表,比您的可用 RAM 大得多,这需要很多时间。 Numpy 的选择例程可以直接处理非均匀随机分布,而无需构建另一个列表。

在 Py 3.6 中,这是标准库的一部分,random.choices():

In []:
import random
random.choices(list(DICT_VAR.keys()), DICT_VAR.values(), k=2)

Out[]:
['best', 'best']

或者更神秘一点:

random.choices(*zip(*DICT_VAR.items()), k=2)