it-swarm-eu.dev

Převod Uniformní distribuce na normální distribuci

Jak lze převést jednotnou distribuci (jak většina generátorů náhodných čísel produkuje, např. Mezi 0,0 a 1,0) do normálního rozdělení? Co když chci střední a standardní odchylku mého výběru?

91
Terhorst

Zigguratův algoritmus je pro to velmi účinný, ačkoliv Box-Mullerova transformace je jednodušší implementovat od nuly (a ne bláznivě pomalu).

46
Tyler

Existuje spousta metod:

  • Do not použijte Box Muller. Zvláště pokud nakreslíte mnoho gaussovských čísel. Box Muller poskytuje výsledek, který je upnut mezi -6 a 6 (za předpokladu dvojité přesnosti. Věci se zhoršují s plováky.). A je to skutečně méně efektivní než jiné dostupné metody.
  • Ziggurat je v pořádku, ale potřebuje vyhledávání v tabulce (a některé úpravy specifické pro platformu kvůli problémům s velikostí mezipaměti)
  • Poměr-uniformy je můj nejoblíbenější, jen pár sčítání/násobení a log 1/50 času (např. podívejte se tam ).
  • Inverze CDF is efektivní (a přehlédnut, proč?), Máte rychlé implementace k dispozici, pokud hledáte google. Je to povinné pro kvazi-náhodné čísla.
38
Alexandre C.

Změna rozdělení jakékoli funkce na jinou zahrnuje použití inverzní funkce, kterou chcete.

Jinými slovy, pokud usilujete o specifickou pravděpodobnostní funkci p(x), získáte její rozdělení integrací nad ní -> d(x) = integrál (p (x)) a použijte jeho inverzní : Inv (d (x)). Nyní použijte náhodnou pravděpodobnostní funkci (která má rovnoměrné rozložení) a výslednou hodnotu přeneste pomocí funkce Inv (d (x)). Měli byste získat náhodné hodnoty s distribucí podle funkce, kterou jste zvolili.

Toto je obecný matematický přístup - pomocí něj můžete nyní zvolit libovolnou pravděpodobnostní nebo distribuční funkci, kterou máte, pokud má inverzní nebo dobrou inverzní aproximaci.

Doufám, že to pomohlo a díky za malou poznámku o využití distribuce a ne o samotné pravděpodobnosti.

25
Adi

Zde je implementace javascriptu pomocí polární formy transformace Box-Müller.

/*
 * 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

Použijte centrální limitní teorém vstup wikipediavstup mathworld ve váš prospěch.

Vygenerujte n z rovnoměrně rozložených čísel, spočítejte je, odečtěte n * 0,5 a budete mít výstup přibližně normálního rozdělení s průměrem rovným 0 a odchylkou rovnou (1/12) * (1/sqrt(N)) (viz wikipedia na jednotných distribucích pro poslední) 

n = 10 vám dává něco napůl slušného. Pokud chcete něco víc než polovinu slušného go pro tylers řešení (jak je uvedeno v wikipedia vstup na normální distribuce )

5
jilles de wit

Zdá se neuvěřitelné, že bych k tomu mohl po osmi letech něco přidat, ale pro případ Javy bych chtěl upozornit čtenáře na metodu Random.nextGaussian () , která generuje Gaussovo rozdělení s průměrem 0.0 a směrodatnou odchylkou 1.0 pro vás.

Jednoduché přidání a/nebo násobení změní průměr a směrodatnou odchylku podle vašich potřeb.

1
Pepijn Schmitz

Použil bych Box-Müller. O tom jsou dvě věci:

  1. Skončíte s dvěma hodnotami na iteraci
    Obvykle ukládáte jednu hodnotu do mezipaměti a vrátíte druhou hodnotu. Při dalším volání vzorku vrátíte hodnotu mezipaměti.
  2. Box-Müller dává Z-skóre
    Pak musíte změnit měřítko Z-skóre standardní směrodatnou odchylkou a přidat střední hodnotu pro získání plné hodnoty v normálním rozdělení.
1
hughdbrown

Standardní modul knihovny Python random má to, co chcete:

normální proměnná (mu, sigma)
Normální distribuce. mu je průměr a sigma je směrodatná odchylka.

Pro samotný algoritmus se podívejte do funkce v souboru random.py v knihovně Python.

Manuální zadání je zde

1

Kde R1, R2 jsou náhodná jednotná čísla:

NORMÁLNÍ DISTRIBUCE s SD 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)

To je přesné ... není třeba dělat všechny ty pomalé smyčky!

1
Erik Aronesty

Q Jak lze převést jednotnou distribuci (jak většina generátorů náhodných čísel produkuje, např. Mezi 0.0 a 1.0) do normálního rozdělení?

  1. Pro implementaci softwaru vím pár náhodných jmen generátorů, které vám dávají pseudo-jednotnou náhodnou sekvenci v [0,1] (Mersenne Twister, Linear Congruate Generator). Říkejme tomu U (x)

  2. Je to matematická oblast, která se nazývá teorie pravděpodobnosti. První věc: Pokud chcete modelovat r.v. s integrálním rozdělením F pak můžete zkusit zhodnotit F ^ -1 (U (x)). V pr.theory bylo prokázáno, že taková r.v. bude mít integrální distribuci F.

  3. Krok 2 může být použitelný pro generování r.v. ~ F bez použití jakýchkoliv metod počítání, když F ^ -1 může být odvozen analyticky bez problémů. (např. exp.distribution)

  4. Pro modelování normálního rozložení je možné vypočítat y1 * cos (y2), kde y1 ~ je jednotná v [0,2pi]. a y2 je distribuce relei.

Otázka: Co když chci střední a standardní odchylku mého výběru?

Můžete vypočítat sigma * N (0,1) + m.

Lze ukázat, že takové posunutí a změna měřítka vede k N (m, sigma)

0
bruziuz

Jedná se o implementaci Matlabu s využitím polární formy Box-Muller transformace:

Funkce 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

A vyvolání histfit(randn_box_muller(10000000),100); toto je výsledek:  Box-Muller Matlab Histfit

Je to samozřejmě neefektivní ve srovnání s vestavěným modulem Matlab randn .

0
madx

Mám následující kód, který by mohl pomoci:

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

Je také snazší použít implementovanou funkci rnorm (), protože je rychlejší než zápis generátoru náhodných čísel pro normální distribuci. Viz následující kód jako důkaz

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

Já bych to měl zkusit v Excelu: =norminv(Rand();0;1). To bude produkt náhodná čísla, která by měla být normálně distribuována s nulovým středem a sjednotit rozptyl. "0" může být dodáváno s libovolnou hodnotou, takže čísla budou mít požadovaný průměr a změnou "1" získáte rozptyl rovný čtverci vašeho vstupu.

Například: =norminv(Rand();50;3) přinese normálně rozdělená čísla s MEAN = 50 VARIANCE = 9.

0
Hippo