2013-04-19 22 views
7

Javascript Math.random() restituisce un numero psuedo-random con distribuzione "uniforme".Genera un numero casuale con una distribuzione non uniforme

Devo generare un numero casuale nell'intervallo [0,1] inclinato su entrambi i lati. (Significato, maggiore possibilità di ottenere più numeri accanto a 0 o accanto a 1)

Idealmente mi piacerebbe avere un parametro per impostare questa curva.

Suppongo di poter fare Math.random^2 per ottenere un risultato del genere, ma quali sono i modi più sofisticati per raggiungere questo obiettivo?

+0

Per la risposta di seguito, le distribuzioni di Poisson non sono [0,1]. Sono [0, infinito). Quindi quale vuoi? – djechlin

+0

+1, questa è una buona domanda con una soluzione non banale. – Nishanth

+0

@djechlin tecnicamente Le variabili casuali di Poisson hanno il supporto su {0, ..., ∞}, questo è importante per pensare di prelevare campioni dai processi di Poisson su spazi che generano una variabile casuale di Poisson basata sulla distribuzione di tasso sottostante sullo spazio [0, ∞) di solito è considerato nei processi di Poisson. Se consideri la totalità di quello spazio, ottieni un numero variabile di eventi di Poisson con la media ∞, che tradizionalmente è vista come un caso limite valido in cui ti aspetti la variabile casuale di Poisson = ∞ (p.p. = 1). – mpacer

risposta

12

Penso che si desidera beta distribution with alpha=beta=0.5

E 'possibile trasformare numero casuale uniforme distribuzione beta con distribuzione cumulativa inversa.

unif = Math.random() 

non ho familiarità con javascript, ma questo dovrebbe essere chiaro:

beta = sin(unif*pi/2)^2 

PS: è possibile generare molti di questi numeri e trama istogramma enter image description here

Edit:

Per inclinazione verso 0, trasformare beta valori -

beta_left = (beta < 0.5) ? 2*beta : 2*(1-beta); 

enter image description here

Per inclinazione verso 1, trasformare come -

beta_right = (beta > 0.5) ? 2*beta-1 : 2*(1-beta)-1; 

enter image description here

+0

Interessante! Ci proverò. Grazie per l'illustrazione del grafico. Cosa farei se desidero che la distribuzione sia inclinata solo da un lato? – OpherV

+1

Bene, ci sono modi per mappare la distribuzione uniforme a * qualsiasi * distribuzione usando il metodo inverso CDF. Aggiornerò la mia risposta per trasformare i numeri già in obliquità destra/sinistra. – Nishanth

+0

Questo è esattamente ciò di cui avevo bisogno! Grazie mille – OpherV

2

Penso che tu debba ripensare alla tua domanda. Il Poisson è una distribuzione di conteggio specificata in termini di un tasso, come il numero di occorrenze di qualcosa che vedo in media per periodo di tempo. Produce interi positivi, quindi il risultato non può essere solo nell'intervallo [0,1]. Puoi per favore chiarire cosa vuoi?

Indipendentemente, per generare una Poisson di lambda tasso a un algoritmo è:

threshold = Math.exp(-lambda) 
count = 0 
product = 1.0 
while (product *= rand) >= threshold { 
     count += 1 
} 
return count 

dove "Rand" è la chiamata di funzione per un Uniform (0,1). Non conosco il javascript, ma dovrebbe essere abbastanza semplice da implementare.

Rispondendo alla domanda modificato:

Ci sono diverse distribuzioni che generano i risultati su una serie limitata, ma molti di loro non sono per i deboli di cuore, come la famiglia Johnson o la distribuzione Beta.

Uno facile sarebbe distribuzioni triangolari. Sqrt (rand) darà una distribuzione triangolare ammucchiata verso 1, mentre (1-Sqrt (1-rand)) darà una distribuzione triangolare raggruppata verso zero.

Un triangolo più generale con la modalità (valore più frequente) in m (dove 0 < = m < = 1) può essere generata con

if rand <= m 
    return m * Sqrt(rand) 
else 
    return 1 - ((1 - m) * Sqrt(1 - rand)) 

noti che ogni chiamata Rand è un Uniform separato casuale numero, questo non sarà corretto se si genera un valore per Rand e lo si utilizza in tutto.

+0

Hai assolutamente ragione. Stavo pensando di pensare a tutto questo all'indietro :) Grazie per avermi messo dritto (e nella giusta direzione!). In ogni caso, buono a sapersi riguardo all'algoritmo – OpherV

2

Yoy può utilizzare window.crypto.getRandomValues dove disponibile

<div id="result"></div> 

var randVal = new Uint8Array(1); 

window.crypto.getRandomValues(randVal); 

document.getElementById("result").textContent = randVal[0]/255; 

Su jsfiddle

(se questo è ciò che il vostro chiedere, io non sono sicuro)

O forse come questo

<div id="result"></div> 

function poissonRandomNumber(lambda) { 
    var L = Math.exp(-lambda), 
     k = 0, 
     p = 1; 

    do { 
     k = k + 1; 
     p = p * Math.random(); 
    } while (p > L); 

    return k - 1; 
} 

document.getElementById("result").textContent = poissonRandomNumber(100); 

anche su jsfiddle

1

Ho appena si avvicinò con un modo più semplice per ottenere numeri casuali asimmetrico a ogni lato, e che non ha alcuna dipendenza.

Questo metodo utilizza due numeri casuali regolari di Javascript. Il primo si moltiplica con se stesso (più grande è l'esponente, più grande è l'effetto di distorsione) e il secondo sceglie quale lato della distribuzione deve inclinarsi.

function skewedRandom() { 
    const a = Math.pow(Math.random(), 2); 
    if (Math.random() < 0.5) { 
     return a; 
    } 
    return 1 - a; 
} 

In questo codice l'esponente è impostato su 2. Un campione istogramma da 10.000 esecuzioni con l'esponente a 2 come sopra:

Histogram with exponent 2

con esponente 3:

Histogram with exponent 3

E con esponente 10: Histogram with exponent 10

+0

Prendo nota di un possibile problema con questo metodo. Math.random() produce numeri da 0 compreso a 1 esclusivo. Questo metodo, tuttavia, può produrre numeri da 0 a 1 inclusi.Se questo è un problema per te, una possibile soluzione potrebbe essere quella di cambiare l'ultima riga in 'return 1 - Number.EPSILON - a;'. Anche se non sono sicuro che questo potrebbe mai produrre un valore leggermente inferiore a 0. – tremby

Problemi correlati