Python numpy.random.normal 仅正值

问题描述 投票:0回答:9

我想使用 numpy.random.normal 创建一个仅包含正值的正态分布数组。 例如,下面的例子说明它有时返回负值,有时返回正值。我该如何修改它,使其只返回正值?

>>> import numpy
>>> numpy.random.normal(10,8,3)
array([ -4.98781629,  20.12995344,   4.7284051 ])
>>> numpy.random.normal(10,8,3)
array([ 17.71918829,  15.97617052,   1.2328115 ])
>>> 

我想我可以这样解决它:

myList = numpy.random.normal(10,8,3)

while item in myList <0:
       # run again until all items are positive values
       myList = numpy.random.normal(10,8,3)
python numpy normal-distribution
9个回答
12
投票

根据定义,正态分布从 -inf 延伸到 +inf,因此您所要求的在数学上没有意义。

您可以采用正态分布并将绝对值“剪辑”为正值,或者只是丢弃负值,但您应该明白它将不再是正态分布。


5
投票

我假设你的意思是你想要修改概率密度,使其在正范围内与正常形状相同,在负范围内为零。这是一个非常常见的实际案例。在这种情况下,您不能简单地取生成的正态随机变量的绝对值。相反,您必须生成一个新的独立正态分布数,直到得出一个正数。一种方法是递归,见下文。


import numpy as np
def PosNormal(mean, sigma):
    x = np.random.normal(xbar,delta_xbar,1)
    return(x if x>=0 else PosNormal(mean,sigma))


1
投票

沿着这些思路使用对数正态怎么样:

    mu = np.mean(np.log(list))
    sigma = np.std(np.log(list))

    new_list = np.random.lognormal(mu, sigma, length_of_new_list)

1
投票

数据 = np.random.randint(低=1,高=100,大小=(4,4),dtype='int')


1
投票

或者也许您可以通过减去最小值(或添加最小值的绝对值)来将整个分布“移动”到“右侧”:

y = np.random.normal(0.0, 1.0, 10)

y
array([-0.16934484,  0.06163384, -0.29714508, -0.25917105, -0.0395456 ,
        0.17424635, -0.42289079,  0.71837785,  0.93113373,  1.12096384])

y - min(y)
array([0.25354595, 0.48452463, 0.12574571, 0.16371974, 0.38334519,
       0.59713714, 0.        , 1.14126864, 1.35402452, 1.54385463])

1
投票

这个问题很有道理。对于动机,请考虑生物细胞的模拟。细胞中某种分子的计数分布可以用正态分布来近似,但必须是非负数才具有物理意义。

我的整体模拟器使用此方法对分子计数的初始分布进行采样:

def non_neg_normal_sample(random_state, mean, std, max_iters=1000):
    """ Obtain a non-negative sample from a normal distribution

    The distribution returned is normal for 0 <= x, and 0 for x < 0

    Args:
        random_state (:obj:`numpy.random.RandomState`): a random state
        mean (:obj:`float`): mean of the normal dist. to sample
        std (:obj:`float`): std of the normal dist. to sample
        max_iters (:obj:`int`, optional): maximum number of draws of the true normal distribution

    Returns:
        :obj:`float`: a normal sample that is not negative

    Raises:
        :obj:`ValueError`: if taking `max_iters` normal sample does not obtain one that is not negative
    """
    iter = 0
    while True:
        sample = random_state.normal(mean, std)
        iter += 1
        if 0 <= sample:
            return sample
        if max_iters <= iter:
            raise ValueError(f"{iter} draws of a normal dist. with mean {mean:.2E} and std {std:.2E} "
                             f"fails to obtain a non-negative sample")

我以两种方式扩展@gena-kukartsev 的答案:首先,我避免可能溢出调用堆栈的递归。 (让我们避免可能在stackoverflow上溢出堆栈的答案!)其次,我通过限制分布的样本数量来捕获可能的错误输入。


0
投票

您可以将整个数组偏移数组的最低值(最左边)。你得到的可能不是真正的“正态分布”,但在你的工作范围内,处理有限数组,你可以确保这些值是正数并且符合钟形曲线。

>>> mu,sigma = (0,1.0)
>>> s = np.random.normal(mu, 1.0, 100)
>>> s
array([-0.58017653,  0.50991809, -1.13431539, -2.34436721, -1.20175652,
        0.56225648,  0.66032708, -0.98493441,  2.72538462, -1.28928887])
>>> np.min(s)
-2.3443672118476226
>>> abs(np.min(s))
2.3443672118476226
>>> np.add(s,abs(np.min(s)))
array([ 1.76419069,  2.85428531,  1.21005182,  0.        ,  1.14261069,
        2.90662369,  3.00469429,  1.3594328 ,  5.06975183,  1.05507835])

0
投票

您可以使用低比例的高位置:

np.random.normal(100, 10, 10) /100

[0.96568643 0.92123722 0.83242272 0.82323367 1.07532713 0.90125736
 0.91226052 0.90631754 1.08473303 0.94115643]

0
投票
arr=np.random.normal(0,1,10)
arr[gdp_cap<0]=-arr[gdp_cap<0] #Just invert the elements less than 0
print(gdp_cap)
© www.soinside.com 2019 - 2024. All rights reserved.