np.random.choice:概率值不为1

27

我如何在这里使用np.random.choice? 有一个计算由某些操作产生的p,例如:

 p=[  1.42836755e-01,   1.42836735e-01  , 1.42836735e-01,   1.42836735e-01
,   4.76122449e-05,   1.42836735e-01  , 4.76122449e-05  , 1.42836735e-01,
   1.42836735e-01,   4.76122449e-05]

通常情况下,和P并不完全等于1:

>>> sum(p)
1.0000000017347

我想按照概率=p进行随机选择:

>>> np.random.choice([1,2,3,4,5,6,7,8,9, 10], 4, p=p, replace=False)
array([4, 3, 2, 9])

这里的代码可以运行!但在程序中却有一个错误:

Traceback (most recent call last):
    indexs=np.random.choice(range(len(population)), population_number, p=p, replace=False)
  File "mtrand.pyx", line 1141, in mtrand.RandomState.choice (numpy/random/mtrand/mtrand.c:17808)
ValueError: probabilities do not sum to 1

如果我打印 p

[  4.17187500e-05   2.49937500e-01   4.16562500e-05   4.16562500e-05
   2.49937500e-01   4.16562500e-05   4.16562500e-05   4.16562500e-05
   2.49937500e-01   2.49937500e-01]

但是在 Python Shell 中,可以通过以下 p 运行:

>>> p=[  4.17187500e-05 ,  2.49937500e-01   ,4.16562500e-05  , 4.16562500e-05,
   2.49937500e-01  , 4.16562500e-05  , 4.16562500e-05  , 4.16562500e-05,
   2.49937500e-01   ,2.49937500e-01]
>>> np.random.choice([1,2,3,4,5,6,7,8,9, 10], 4, p=p, replace=False)
array([ 9, 10,  2,  5])

更新 我已经通过15位精度进行了测试:

 np.set_printoptions(precision=15)
 print(p)
[  2.499375625000002e-01   2.499375000000000e-01   2.499375000000000e-01
   4.165625000000000e-05   4.165625000000000e-05   4.165625000000000e-05
   4.165625000000000e-05   4.165625000000000e-05   2.499375000000000e-01
   4.165625000000000e-05]

测试:

>>> p=np.array([  2.499375625000002e-01   ,2.499375000000000e-01   ,2.499375000000000e-01,
   4.165625000000000e-05   ,4.165625000000000e-05,   4.165625000000000e-05,
   4.165625000000000e-05  , 4.165625000000000e-05 ,  2.499375000000000e-01,
   4.165625000000000e-05])
>>> np.sum(p)
1.0000000000000002

如何使用 np.random.choice 修复此问题?


尝试打印[repr(x) for x in p],如果p是一个numpy数组,则打印p.dtype。尽管普遍认为可以从print的输出中重新创建一系列浮点数,但并非总是如此。 - Stop harming Monica
谢谢。我怎样在这里使用 np.random.choice? - pd shah
这对我有效。你需要更加努力地创建一个[mcve]。 - Stop harming Monica
p=np.array([0.1999600079984003, 0.1999600079984003, 0.1999600079984003, 3.9992001599680064e-05, 0.1999600079984003, 3.9992001599680064e-05, 3.9992001599680064e-05, 0.1999600079984003, 3.9992001599680064e-05, 3.9992001599680064e-05]) np.sum(p) 0.99999999999999978
- pd shah
我不明白为什么你一直发布那些不能触发错误的示例。它们对解决你的问题没有用处。 - Stop harming Monica
4个回答

29
这是一个与numpy有关的已知问题。随机选择函数使用给定的公差(源代码在此处)检查概率之和。
解决方法是,如果总和接近1,则通过将概率除以它们的总和来归一化概率。
示例:
>>> p=[  1.42836755e-01,   1.42836735e-01  , 1.42836735e-01,   1.42836735e-01
,   4.76122449e-05,   1.42836735e-01  , 4.76122449e-05  , 1.42836735e-01,
   1.42836735e-01,   4.79122449e-05]
>>> sum(p) 
1.0000003017347 # over tolerance limit
>>> np.random.choice([1,2,3,4,5,6,7,8,9, 10], 4, p=p, replace=False)

Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    np.random.choice([1,2,3,4,5,6,7,8,9, 10], 4, p=p, replace=False)
  File "mtrand.pyx", line 1417, in mtrand.RandomState.choice (numpy\random\mtrand\mtrand.c:15985)
ValueError: probabilities do not sum to 1

使用规范化:

>>> p = np.array(p)
>>> p /= p.sum()  # normalize
>>> np.random.choice([1,2,3,4,5,6,7,8,9, 10], 4, p=p, replace=False)
array([8, 4, 1, 6])

7
谢谢,但不行。ValueError: probabilities do not sum to 1. 怎么办? - pd shah
@pdshah 你尝试过通过 p /= p.sum() 对概率进行归一化吗? - user2314737
是的:>>> p=np.array([0.1999600079984003, 0.1999600079984003, 0.1999600079984003, 3.9992001599680064e-05, 0.1999600079984003, 3.9992001599680064e-05, 3.9992001599680064e-05, 0.1999600079984003, 3.9992001599680064e-05, 3.9992001599680064e-05])
np.sum(p) 0.99999999999999978
p /= p.sum() np.sum(p) 1.0000000000000002
- pd shah
@pdshah 好的,总和仍然不完全等于一,但是 np.random.choice 能用吗? - user2314737
我想做的第一件事情也是这样,但它没有起作用。 - Michael Tamillow
由于除法累积的舍入误差,这可能无法正常工作。请参阅我的答案https://dev59.com/ZsPra4cB1Zd3GeqPn8U7#71400320,以获取明确的解决方案。 - Fırat Kıyak

15

1
在我看来,这个应该有更多的投票。当我的p = [1,1,1]时,其他答案都不适用于我的情况,只有这个适用。谢谢! - Jan Pisl

5
ValueError: 概率总和不为1。
这是已知的numpy错误。当numpy无法处理精度足够高的浮点运算时,就会出现此错误。有时,概率总和可能会变成类似于0.9999999999997或1.0000000000003这样的数字。它们将破坏np.random.choice()。
有一个解决方法:np.random.multinomial()。这种方法可以更优雅地处理概率,而无需完全等于1.0。
例如,我有一些选择和与选择相关联的归一化权重。
np.random.multinomial()基于归一化权重进行20次选择,并返回每个选择被选择的次数。
choices = [......]
weights = np.array([......])
normalized_weights = weights / np.sum(weights)

number_of_choices = 20
resample_counts = np.random.multinomial(number_of_choices,
                                        normalized_weights)

chosen = []
resample_index = 0
for resample_count in resample_counts:
    for _ in range(resample_count):
        chosen.append(choices[resample_index])
    resample_index += 1

它并不总是加起来的。 - Soid

3

看待这个问题的一种方式是:

numpy.set_printoptions(precision=15)
print(p)

这可能会向您展示,您的4.17187500e-05实际上是4.17187500005e-05。请参见此处的手册


谢谢。我在帖子上添加了更多的注释。如何解决这个问题? - pd shah

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