使用numpy离散到高斯分布

时间:2018-12-01 17:17:31

标签: python numpy convolution gaussian

我正在尝试使n> = 2的高斯分布离散接近。

因此,假设n = 2时,离散接近度将为[0.5,0.5]。

当n = 3时,它将是[0.25,0.5,0.25]

当n = 4时将是[0.125,0.375,0.375,0.125]

我希望你明白我的意思。

返回的离散邻近数组总和应始终为1。

这是我的代码:

import numpy as np
import matplotlib.pyplot as plt
import math
import scipy 
from random import randint

def discrete_gauss(n):
    g = [0.5, 0.5]
    f = g
    for x in range(1, n - 1):
        f = np.convolve(f,g)

    if(sum(f) != 1):
        print("The distribution sum is not 1.")
    else:
        return f

现在,当我使用(1 67)时,f的总和不同于1(有时更多,有时更少),我不知道为什么。 有任何线索吗?

很抱歉,我试图将其简短化。如果不清楚,我将很乐意澄清。 谢谢。

1 个答案:

答案 0 :(得分:2)

tl; dr

阅读paper,了解使用浮点数学的挑战,然后重新考虑您的方法。

解决方案

这是生成所需“分布”的另一种方法,可避免np.convolve执行的求和中的浮点舍入错误:

import numpy as np
import scipy.special as sps

def discrete_gauss(n):
    f = np.array([sps.comb(n - 1, i, exact=True) for i in range(n)], dtype='O')
    f = np.float64(f)/np.float64(f).sum()

    if not np.allclose(f.sum(), 1.0):
        raise ValueError("The distribution sum is not close to 1.\n" 
                         "f.sum(): %s" % f.sum())

    return f

解决方案的说明

您想要的序列等效于Pascal三角形的第n级(请参见Wiki on Binomial theorem顶部的图),并对其进行了归一化,以便可以表示概率。上面的解决方案使用标准的Python int值(在Python 3中默认为任意精度)来查找第n级的值,然后仅在最后转换为浮点数学。标准化步骤(即np.float64(f)/np.float64(f).sum())。

请注意,在上面的检查中使用了not np.allclose(f.sum(), 1.0),而不是f.sum() != 1.0。如下面的更深层次部分所述,对于{1- {1}}中f.sum()值的〜90%,1.0等于n。但是,总的来说,您不能假定浮点计算的结果将与您使用实数从等效计算中获得的结果完全匹配(有关所有详细信息,请参阅此paper)。在处理浮点数时,通常应(我几乎总是这样)检查结果是否接近(而不是等于给定的公差/误差)。

深潜

此解决方案并不完美。 n的大多数值所产生的结果总和为1.0,而有些则不然。以下代码检查1-1000中discrete_gauss(n)的值是否为n

nnot1 = []
for n in range(1,1001):
    if discrete_gauss(n).sum() != 1.0:
        nnot1.append(n)

print('discrete_gauss(n).sum() was not equal to 1.0 for %d values of n.' % len(nnot1))
print(nnot1)

输出:

discrete_gauss(n).sum() was not equal to 1.0 for 75 values of n.
[78, 89, 110, 114, 125, 127, 180, 182, 201, 206, 235, 248, 273, 342, 346, 348, 365, 373, 383, 390, 402, 403, 421, 427, 429, 451, 454, 471, 502, 531, 540, 556, 558, 574, 579, 584, 587, 595, 600, 609, 617, 631, 633, 647, 648, 651, 657, 669, 674, 703, 705, 728, 731, 763, 765, 772, 778, 783, 798, 816, 837, 852, 858, 860, 861, 867, 874, 877, 906, 912, 941, 947, 959, 964, 972]

因此,对于其中的约8%,dicrete_gauss(n).sum()不完全等于1.0。但是,由于未引发任何错误,因此np.allclose(dicrete_gauss(n).sum(), 1.0)始终是True

注释