【问题标题】:Python numpy.random.normal only positive valuesPython numpy.random.normal 只有正值
【发布时间】:2013-04-25 02:07:18
【问题描述】:

我想用 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)

【问题讨论】:

  • “只回馈积极的价值观”是什么意思?如果它返回负值,你希望它做什么?
  • 根据定义,正态分布扩展到所有可能的值,包括正值和负值。您无法将“正态分布”与“仅正值”调和起来,所以我的问题是……您真正想要什么?
  • 我需要将正态分布值输入函数。该函数只取正值。
  • 正态分布扩展到所有可能的值,包括正的和负的。如果您阻止它返回负值,则根据定义,它不再是正态分布。因此,根据定义,您为函数提供的任何分布都不能是负数。考虑到上述情况,您想要什么分布?
  • 二项分布类似于正态分布,但离散,仅在正值范围内:en.wikipedia.org/wiki/Binomial_distribution

标签: python numpy normal-distribution


【解决方案1】:

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

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

【讨论】:

  • “根据定义,正态分布从 -inf 扩展到 +inf ...”,这并不意味着您不能在数值上获得裁剪/偏离中心/x 位移分布。这种情况可能出现在典型的光谱检测器中。在使用 np.random.normal(fix_mean,fix_sigma) 绘制每个数字之后,您仍然可以检查非负性条件并改为绘制一个新的。
  • @jaydeepsb ...这正是我在答案中提到的? ?
  • 该问题与您希望仅保留正态分布中的正值但希望在定义中定义数组大小的情况相匹配。这个问题确实有意义并且有效。
【解决方案2】:

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

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))

【讨论】:

  • 这对于某些用例来说可能是合理的,但请注意,从这个分布中采样会偏向更高的值,尤其是在平均值接近零的情况下。如果你特别不走运,也可能会出现堆栈溢出。
  • 是的,这不再是一个正态分布,我们改变了它,它有一个不同的 PDF,截断为零。但我认为这就是问题所在,而且这样做通常很实际。关于在这种情况下您担心堆栈溢出,除非您只有几个字节的 RAM,否则没有人会这么倒霉。
  • 关于在这种情况下您担心堆栈溢出,如果您只对分布的几西格玛右尾感兴趣,即如果分布的平均值为几西格玛的负数,那么您是对的.在这种情况下,该解决方案的性能将恶化并最终溢出。但我怀疑这是预期的用例。它更像是一种快速破解。
  • 看起来效率很低,因为你也可以使用abs()
  • 你不需要递归函数来达到同样的结果while x&lt;=0: x = np.random.normal(mean, sigma)
【解决方案3】:

如何在这些方面使用对数正态:

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

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

【讨论】:

    【解决方案4】:

    数据 = np.random.randint(low=1,high=100,size=(4,4),dtype='int')

    【讨论】:

    • 这正是我想要的。谢谢!
    • 如果问题是关于获得非负正态分布数,您的解决方案是错误的。由于 np.random.randint 从均匀分布中抽取随机数,因此您仍需要使用 np.random.normal。正如 ustroetz 所建议的,解决方法是不断绘制新数字(具有相同的均值,sigma)直到它为非负数,然后将其包含在您的数组中。
    【解决方案5】:

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

    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])
    

    【讨论】:

      【解决方案6】:

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

      >>> 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])
      

      【讨论】:

        【解决方案7】:

        这个问题是有道理的。对于动机,请考虑simulations of biological cells。细胞中一种分子的计数分布可以近似为正态分布,但必须是非负的才能具有物理意义。

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

        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 上溢出堆栈的答案!)其次,我通过限制分布的样本数量来捕捉可能的错误输入。

        【讨论】:

        • 如果 P[0 non_neg_normal_sample 的调用。但是non_neg_normal_sample 的结构适​​用于任何包含负值和正值的分布。
        【解决方案8】:

        你可以使用低比例的高位:

        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]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-04
          • 2021-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多