【问题标题】:Adjusting the mean and standard deviation of a list of random numbers?调整随机数列表的均值和标准差?
【发布时间】:2019-08-20 23:21:31
【问题描述】:

我必须在 -3 和 3 之间创建一个随机数列表(带小数)。问题是该列表的平均值必须为 0,标准差必须为 1。如何调整平均值和标准偏差参数?有什么可以使用的功能吗?

我已经能够创建一个介于 -3 和 3 之间的随机数列表。

import random


def lista_aleatorios(n):
    lista = [0] * n
    for i in range(n):
        lista[i] = random.uniform(-3, 3)
    return lista

print("\nHow many numbers do you want?: ")
n = int(input())

print (lista_aleatorios(n))

【问题讨论】:

  • a mean of 0 到底是什么意思?分布平均值与样本平均值不同 - 如果我从简单的高斯 N(0,1) 开始采样,没有界限,那么即使分布平均值为 0,采样平均值也会不同,并且当数样本将无穷大。您希望分布均值为零吗?或者您希望任何采样序列的样本均值(实际上是总和)始终完全为零?这两个条件完全不同

标签: python random mean python-3.7 normal-distribution


【解决方案1】:

函数random.normalvariate(mu, sigma) 允许您指定正态分布随机变量的均值和标准差。

【讨论】:

  • 谢谢!但是如何使用这个函数控制从 -3 到 3 的范围呢?问候!
  • 我还注意到,无论是使用此函数还是使用 random.gauss(mu, sigma),sd 和均值都接近我指出的值。然而,它们并不完全是我建立的。有什么办法可以调整吗?
【解决方案2】:

使用random.gauss,然后缩放:

import numpy as np

from random import gauss

def bounded_normal(n, mean, std, lower_bound, upper_bound):

    # generate numbers between lower_bound and upper_bound

    result = []
    for i in range(n):
        while True:
            value = gauss(mean, std)
            if lower_bound < value < upper_bound:
                break

        result.append(value)

    # modify the mean and standard deviation

    actual_mean = np.mean(result)
    actual_std = np.std(result)
    mean_difference = mean - actual_mean
    std_difference = std / actual_std
    new_result = [(element + mean_difference) * std_difference for element in result]

    return new_result

【讨论】:

  • 不错!谢谢老哥!
  • 1.它通常被称为截断高斯/截断法线。 2. 您刚刚对生成的 RV 设置了两个硬条件 - 总和等于 0,平方和等于另一个固定值。当人们说平均值为零时,通常不是他们的意思。 3. 在返回之前移位和重新缩放后,有时您会得到超出范围的数字。
  • @SeverinPappadeux 那么你有什么建议呢?
  • 如果您想继续使用en.wikipedia.org/wiki/Truncated_normal_distribution,请查看那里的公式。基本上,你有你不知道的分布值(\mu,\sigma),以及你想要达到的平均值和标准差。您将 TN 的均值表达式分配给所需的均值,将方差表达式分配给所需的 stddev^2,两个未知数的两个方程,就会有一个解决方案。幸运的是,\mu 将是 0,因为 min/max 是对称的,并且所需的平均值为 0。对于 \sigma,将有一个非线性方程,可以求解,然后从 (mu, sigma) 中采样跨度>
  • 使用这个 - stackoverflow.com/questions/18441779/…。我希望 \sigma 比 1 大一点,但不会大很多。基本上,您正在削减高斯的尾部,这意味着高 sigma 样本现在已经消失 - 您必须通过稍微扩大分布来进行补偿。
【解决方案3】:

好的,这是解决问题的快速方法(如果您想使用截断高斯)。设置边界和所需的标准差。我假设平均值为 0。然后快速粗略的代码对分布 sigma 进行二进制搜索,求解非线性根(brentq() 应在生产代码中使用)。所有公式均取自 Truncated Normal 上的 Wiki 页面。它(sigma)应大于所需的 stddev,因为截断会删除导致大 stddev 的随机值。然后我们进行快速抽样测试——均值和标准差接近期望值,但从不完全等于它们。代码(Python-3.7、Anaconda、Win10 x64)

import numpy as np
from scipy.special import erf
from scipy.stats import truncnorm

def alpha(a, sigma):
    return a/sigma

def beta(b, sigma):
    return b/sigma

def xi(x, sigma):
    return x/sigma

def fi(xi):
    return 1.0/np.sqrt(2.0*np.pi) * np.exp(-0.5*xi*xi)

def Fi(x):
    return 0.5*(1.0 + erf(x/np.sqrt(2.0)))

def Z(al, be):
    return Fi(be) - Fi(al)

def Variance(sigma, a, b):
    al = alpha(a, sigma)
    be = beta(b, sigma)
    ZZ = Z(al, be)

    return sigma*sigma*(1.0 + (al*fi(al) - be*fi(be))/ZZ - ((fi(al)-fi(be))/ZZ)**2)

def stddev(sigma, a, b):
    return np.sqrt(Variance(sigma, a, b))

m = 0.0 # mean
s =  1.0 # this is what we want
a = -3.0 # left boundary
b =  3.0 # right boundary

#print(stddev(s , a, b))
#print(stddev(s + 0.1, a, b))

slo = 1.0
shi = 1.1

stdlo = stddev(slo, a, b)
stdhi = stddev(shi, a, b)

sigma = -1.0
while True: # binary search for sigma
    sme = (slo + shi) / 2.0
    stdme = stddev(sme, a, b)
    if stdme - s == 0.0:
        sigma = stdme
        break
    elif stdme - s < 0.0:
        slo = sme
    else:
        shi = sme

    if shi - slo < 0.0000001:
        sigma = (shi + slo) / 2.0
        break

print(sigma) # we got it, shall be slightly bigger than s, desired stddev

np.random.seed(73123457)

rvs = truncnorm.rvs(a, b, loc=m, scale=sigma, size=1000000) # quick sampling test

print(np.mean(rvs))
print(np.std(rvs))

对我来说是打印出来的

sigma = 1.0153870105743408
mean = -0.000400729471992301
stddev = 1.0024267696681475

使用不同的种子或序列长度,您可能会得到类似

的输出
1.0153870105743408
-0.00015923177289006116
0.9999974266369461

【讨论】:

    猜你喜欢
    • 2020-07-30
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 2016-04-17
    • 1970-01-01
    相关资源
    最近更新 更多