Python 概率分布和浮动变量,概率必须加1

Python 概率分布和浮动变量,概率必须加1,python,python-3.x,numpy,distribution,probability,Python,Python 3.x,Numpy,Distribution,Probability,我正在编写一个脚本,它是这样的:程序分析了一堆特定语言的文本文档,绘制了每个k的概率分布,其中k是文本中每个单词中字母表的每个给定字母后面出现的第一个字符。然后,程序使用这些知识尝试使用马尔可夫链编写真实的单词 我已经写了大部分的脚本,它已经吐出了有趣的单词,关键是生成单词的函数使用了一种尝试和排除机制,以避免陷入困境。它被卡住了,因为一些概率分布不加1,我想是因为浮点类型不是那么精确,或者类似的东西,应该与这些分布一起工作的numpy函数会产生一个值错误,因为概率加起来不等于1 通过触发某些发

我正在编写一个脚本,它是这样的:程序分析了一堆特定语言的文本文档,绘制了每个k的概率分布,其中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:概率加起来不等于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.0
1.0
1.0
0
1.0
1.0
在评论中:

这是这个函数外部的一个简单for循环,它打印出作为这个函数返回值存储的每个分布的总和

所以,你的一些频率分布总和为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

…实际上是一个问题:这不是你需要解决的问题

但我还是会回答的。简短的回答是:不。浮点是精度为固定位数的二进制分数。如果您试图将任意实数存储在浮点数中,将出现舍入错误。你可以很容易地看到这一点:

>>> 1.0 + 1e-17
1.0
没有足够的位将1.0和1.00000000000000001存储为不同的二进制分数


如果您想进一步了解,您应该阅读关于该主题的经典介绍性文章。

您的频率是多少?它来自哪里?对不起,它应该是absFreq而不是freqAss。那是个打字错误。刚刚编辑,谢谢!你能告诉我们当总和不是1时崩溃的代码吗?除非你所有的概率都是精确的二进制分数,否则期望1e-17级的舍入误差是完全合理和不可避免的。浮动就是这样工作的。你不能通过消除舍入误差来解决这个问题;您只能通过更改代码以合理的方式处理舍入错误来解决此问题。由于您没有向我们展示相关代码,因此我们无法向您展示如何更改它。当我运行np.random.choice时,只有当概率之和偏离相对大小的-5个数量级时,我才会得到该错误。一个1+3e-17的总和是非常幸福的;只有当你超过1+1e-5时,它才会抱怨。所以,我很确定这不是你的真实数据,你在某处有一个实际的误差,不仅仅是舍入误差。就是这样!有些字母根本不出现,因此它们的分布总和为0,导致采样时出现错误。我怀疑这是件愚蠢的事。。。谢谢阿巴内特!我去看看报纸@米克克:我是这么想的。大多数bug都是由简单的边缘情况引起的,这些情况你永远不会事先想到,但一旦你知道如何查找它们,这一点就显而易见了。好吧,那个,还有我自己的代码中看不到的愚蠢的打字错误,不管我多么努力地盯着它……你不高兴计算机科学不是你的主要领域吗+1个好球@米克克克:你可以试着解决这个问题。@abarnert:就此而言:是的:然而,CS如此有用和迷人的事实使得这些恼人的问题即使对于一个ne来说也是完全可以忍受的 wbie和我一样: