it-swarm.cn

将均匀分布转换为正态分布

如何将均匀分布(大多数随机数生成器产生,例如介于0.0和1.0之间)转换为正态分布?如果我想要选择的平均值和标准偏差怎么办?

93
Terhorst

Ziggurat算法 对此非常有效,尽管 Box-Muller变换 更容易从头开始实现(而不是疯狂慢)。

46
Tyler

有很多方法:

  • Do not 使用Box Muller。特别是如果你绘制许多高斯数字。 Box Muller产生的结果夹在-6和6之间(假设是双精度。浮子会恶化)。它的效率确实低于其他可用方法。
  • Ziggurat很好,但需要一个表查找(由于缓存大小问题,还有一些特定于平台的调整)
  • 制服比例是我最喜欢的,只有少数加法/乘法和1/50的时间日志(例如 看那里 )。
  • 反转CDF有效(并忽略,为什么?),如果你搜索谷歌,你可以快速实现它。准随机数是强制性的。
39
Alexandre C.

将任何函数的分布更改为另一个函数涉及使用所需函数的反函数。

换句话说,如果你瞄准一个特定的概率函数p(x)你通过积分得到分布 - > d(x) =积分(p(x))并使用其逆:Inv(d(x))。现在使用随机概率函数(具有均匀分布)并通过函数Inv(d(x))投射结果值。您应该根据您选择的函数获得随分布的随机值。

这是一般的数学方法 - 通过使用它,您现在可以选择任何概率或分布函数,只要它具有反向或良好的反向近似。

希望这有助于并感谢关于使用分布的小注释,而不是概率本身。

26
Adi

这是一个使用Box-Muller转换的极性形式的javascript实现。

/*
 * Returns member of set with a given mean and standard deviation
 * mean: mean
 * standard deviation: std_dev 
 */
function createMemberInNormalDistribution(mean,std_dev){
    return mean + (gaussRandom()*std_dev);
}

/*
 * Returns random number in normal distribution centering on 0.
 * ~95% of numbers returned should fall between -2 and 2
 * ie within two standard deviations
 */
function gaussRandom() {
    var u = 2*Math.random()-1;
    var v = 2*Math.random()-1;
    var r = u*u + v*v;
    /*if outside interval [0,1] start over*/
    if(r == 0 || r >= 1) return gaussRandom();

    var c = Math.sqrt(-2*Math.log(r)/r);
    return u*c;

    /* todo: optimize this algorithm by caching (v*c) 
     * and returning next time gaussRandom() is called.
     * left out for simplicity */
}
20
user5084

使用中心限制定理 维基百科条目mathworld条目 对您有利。

生成n个均匀分布的数,求和,减去n * 0.5,得到近似正态分布的输出,均值等于0,方差等于(1/12) * (1/sqrt(N))(参见 统一分布的维基百科 最后一个)

n = 10给你一些快速的东西。如果你想要一些超过一半的东西去tylers解决方案(如 维基百科条目正常分布中所述

5
jilles de wit

八年后我可以添加一些内容似乎令人难以置信,但对于Java的情况,我想将读者指向 Random.nextGaussian() 方法,它生成平均值为0.0和标准差的高斯分布1.0为你。

简单的加法和/或乘法将根据您的需要改变均值和标准差。

1
Pepijn Schmitz

我会用Box-Muller。关于这个的两件事:

  1. 每次迭代最终会得到两个值
    通常,您缓存一个值并返回另一个值。在下一次调用样本时,返回缓存的值。
  2. Box-Muller给出了Z分数
    然后,您必须按标准偏差缩放Z分数,并添加均值以获得正态分布中的完整值。
1
hughdbrown

标准的Python库模块 random 有你想要的:

normalvariate(mu,sigma)
正态分布。 mu是平均值,sigma是标准偏差。

对于算法本身,请查看Python库中random.py中的函数。

手动输入在这里

1
Brent.Longborough

其中R1,R2是随机统一数字:

正态分布,SD为1:sqrt(-2 * log(R1))* cos(2 * pi * R2)

这是确切的......不需要做所有那些缓慢的循环!

1
Erik Aronesty

问:如何将均匀分布(大多数随机数生成器产生,例如介于0.0和1.0之间)转换为正态分布?

  1. 对于软件实现,我知道有一些随机生成器名称,它们在[0,1](Mersenne Twister,Linear Congruate Generator)中为您提供伪均匀随机序列。我们称之为U(x)

  2. 存在称为概率论的数学领域。第一件事:如果你想模特r.v.使用积分分布F,您可以尝试仅评估F ^ -1(U(x))。在理论上证明了这样的r.v.将有积分分布F.

  3. 当可以在没有问题的情况下分析地导出F ^ -1时,步骤2可以适用于生成r.v.~F而不使用任何计数方法。 (例如exp.distribution)

  4. 要模拟正态分布,您可以计算y1 * cos(y2),其中y1~在[0,2pi]中是均匀的。和y2是relei发行版。

问:如果我想要选择的平均值和标准偏差怎么办?

你可以计算sigma * N(0,1)+ m。

可以证明,这种移动和缩放导致N(m,sigma)

0
bruziuz

这是一个使用 Box-Muller transformation的极性形式的Matlab实现:

函数randn_box_muller.m

function [values] = randn_box_muller(n, mean, std_dev)
    if nargin == 1
       mean = 0;
       std_dev = 1;
    end

    r = gaussRandomN(n);
    values = r.*std_dev - mean;
end

function [values] = gaussRandomN(n)
    [u, v, r] = gaussRandomNValid(n);

    c = sqrt(-2*log(r)./r);
    values = u.*c;
end

function [u, v, r] = gaussRandomNValid(n)
    r = zeros(n, 1);
    u = zeros(n, 1);
    v = zeros(n, 1);

    filter = r==0 | r>=1;

    % if outside interval [0,1] start over
    while n ~= 0
        u(filter) = 2*Rand(n, 1)-1;
        v(filter) = 2*Rand(n, 1)-1;
        r(filter) = u(filter).*u(filter) + v(filter).*v(filter);

        filter = r==0 | r>=1;
        n = size(r(filter),1);
    end
end

并调用histfit(randn_box_muller(10000000),100);这是结果: Box-Muller Matlab Histfit 

显然,与Matlab内置的 randn 相比,它的效率非常低。

0
madx

我有以下代码可能会有所帮助:

set.seed(123)
n <- 1000
u <- runif(n) #creates U
x <- -log(u)
y <- runif(n, max=u*sqrt((2*exp(1))/pi)) #create Y
z <- ifelse (y < dnorm(x)/2, -x, NA)
z <- ifelse ((y > dnorm(x)/2) & (y < dnorm(x)), x, z)
z <- z[!is.na(z)]
0
great_minds_think_alike

使用实现的函数rnorm()也更容易,因为它比为正态分布编写随机数生成器更快。请参阅以下代码作为证明

n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
0
peterweethetbeter

我应该在Excel中尝试这个:=norminv(Rand();0;1)。这将产生随机数,这些随机数应该正态分布,具有零均值和联合方差。 “0”可以提供任何值,因此数字将是所需的平均值,通过更改“1”,您将获得等于输入平方的方差。

例如:=norminv(Rand();50;3)将产生正态分布的数字,其中MEAN = 50 VARIANCE = 9。

0
Hippo