概率分布与浮点变量,概率必须加到1
我正在写一个脚本,流程是这样的:程序会分析一堆用特定语言写的文本文件,然后为每个字母后面出现的第一个字符绘制概率分布。这里的k就是指这个字符。接着,程序利用这些信息尝试用马尔可夫链生成“真实”的单词。
我已经写好了大部分代码,程序也能生成一些有趣的单词。关键是,生成单词的函数使用了“尝试和捕获”的机制,以避免程序卡住。程序会卡住是因为有些概率分布的总和并不等于1(我猜是因为浮点数的精度问题或者其他原因),而numpy函数在处理这些分布时会因为概率不等于1而抛出一个错误。
由于某些分布触发了异常,导致有些单词根本无法生成,最终的结果就没有那么有趣了。
现在,我想问的是:有没有办法让这些概率分布在生成时就能加起来等于1?我试过gmpy2和round()函数,但似乎都不管用。也许这个问题有点傻,我只是需要透透气……无论如何,任何帮助都很有用!
这是生成概率分布的代码:
def FreqRel(self,listValues):
absFreq = self.AbsFreq(listValues)
freqRel = []
for i in absFreq:
freqRel.append(i/sum(absFreq))
if sum(freqRel) != 1:
print("Frequencies do not add up to 1")
if sum(freqRel) - 1 < 0:
diff = sum(freqRel) - 1
#This should be an adjustment which should not interfere
#that much on the probability distribution
freqRel[1] = freqRel[1] - diff
print("missing",diff)
elif sum(freqRel) - 1 > 0:
diff = sum(freqRel) - 1
#This should be an adjustment which should not interfere
#that much on the probability distribution
freqRel[1] = freqRel[1] - diff
print("Too much",diff)
return freqRel
这是我在运行这个函数时在控制台上看到的输出:

这是在总和不等于1时崩溃的代码。崩溃的地方是numpy的那几行,错误信息是:ValueError: probabilities do not add up to 1.
def spitText(n):
i = 0
while i < n:
try:
word = ""
#This oldChar setting is arbitrary, later I'm going to fix it
oldChar = "b"
for k in range(np.random.choice(distributions[0],replace=True,p=distributions[1])):
newChar = np.random.choice(alphabet,replace=True,p=distRel[alphabet.index(oldChar)])
word = word + newChar
oldChar = newChar
print(word)
time.sleep(0.2)
i+=1
except:
pass
1 个回答
你有一些输出,看起来像这样:
1.0
1.0
1.0
0
1.0
1.0
根据一个评论:
这是一个简单的循环,位于这个函数外面,它打印出这个函数返回的每个分布的总和。
所以,你的一些频率分布的总和是 0
。这就是你的问题所在。
可以推测,你用来构建分布的代码中有一些特殊情况,导致返回了一个空的分布,或者返回的分布全是零。无论是哪种情况,显然都是不行的。
很多 1.0
的值因为累积的舍入误差可能达到 8e-17,这个问题其实并不重要。你可以看到,numpy 是为了处理这些情况而设计的:
>>> np.random.choice(2, 3, p=[0.4, 0.6+3e-17])
array([1, 0, 0])
只有当误差变得足够大时(大多数 numpy 的默认相对误差是 1e-5),它才会发出警告:
>>> np.random.choice(2, 3, p=[0.4, 0.6+3e-5])
ValueError: probabilities do not sum to 1
所以,你一定有一些概率分布,它们的总和与 1
的差距超过了 1e-5
。当然,你确实有一些分布的总和差了整整 1
。
这就引出了你的主要问题:
有没有办法让这些概率分布在生成时加起来等于 1?
… 其实这是一个 XY问题:这并不是你需要解决的关键问题。
不过我还是会回答这个问题。简短的回答是:不可以。浮点数是固定精度的二进制分数。如果你试图用浮点数存储任意的实数,就会出现舍入误差。你可以很容易地看到这一点:
>>> 1.0 + 1e-17
1.0
实际上没有足够的位数来将 1.0
和 1.00000000000000001
作为不同的二进制分数存储。
如果你想进一步了解(而且你应该了解),可以阅读 每个计算机科学家都应该知道的浮点数知识,这是关于这个主题的经典入门文章。