2010-01-31 16 views
16

Dato un array di dimensione n voglio generare probabilità casuali per ogni indice tale che Sigma(a[0]..a[n-1])=1Generazione di una distribuzione di probabilità

Un possibile risultato potrebbe essere:

0  1  2  3  4 
0.15 0.2 0.18 0.22 0.25 

Un altro risultato perfettamente legale può essere:

0  1  2  3  4 
0.01 0.01 0.96 0.01 0.01 

Come posso generare questi facilmente e rapidamente? Le risposte in qualsiasi lingua vanno bene, preferisco Java.

+0

da Sigma intendi deviazione standard? Spero ti renderai conto che non appena dici la deviazione standard, implichi automaticamente che stai tracciando i numeri casuali dalla normale distribuzione. – ldog

+0

La maggior parte dei numeri di estrazione RNG del computer dalla distribuzione uniforme. – ldog

+0

Puoi affrontare questo problema realizzando che il teorema del Limite centrale può essere d'aiuto: http://en.wikipedia.org/wiki/Central_limit_theorem – ldog

risposta

15

L'operazione che si sta tentando di realizzare equivale a disegnare un punto casuale dall'unità simplex N-dimensionale.

http://en.wikipedia.org/wiki/Simplex#Random_sampling potrebbe aiutarti.

Una soluzione ingenua potrebbe andare come segue:

public static double[] getArray(int n) 
    { 
     double a[] = new double[n]; 
     double s = 0.0d; 
     Random random = new Random(); 
     for (int i = 0; i < n; i++) 
     { 
      a [i] = 1.0d - random.nextDouble(); 
      a [i] = -1 * Math.log(a[i]); 
      s += a[i]; 
     } 
     for (int i = 0; i < n; i++) 
     { 
      a [i] /= s; 
     } 
     return a; 
    } 

Per disegnare un punto uniformemente dall'unità simplex N-dimensionale, dobbiamo prendere un vettore di variabili casuali in modo esponenziale distribuiti, allora normalizzarlo dalla somma di quelle variabili. Per ottenere un valore distribuito in modo esponenziale, prendiamo un valore negativo log di valore uniformemente distribuito.

+3

Nella maggior parte delle lingue, dovresti creare 'Random' solo una volta, altrimenti otterrai risultati casuali (e in molti casi - lo stesso numero più e più volte). Sono anche preoccupato per l'uso di 'log' - puoi spiegare perché è lì? – Kobi

+0

+1 per un buon riferimento, ma penso che 'nextDouble()' si aggiusta già per la distribuzione uniforme: http://java.sun.com/javase/6/docs/api/java/util/Random.html#nextDouble() – trashgod

+0

Kobi, grazie per aver sottolineato la 'nuova cosa Random()'. Per quanto riguarda 'log' - Ho modificato il mio post per includere una spiegazione più approfondita. – viaclectic

22

ottenere numeri casuali n, calcolare la loro somma e normalizzare la somma di 1 dividendo ogni numero con la somma.

+0

Bello :) non pensavo che ... תודה! –

+12

Questo introduce pregiudizi. Non è possibile campionare uniformemente da un simplex in questo modo. – dreeves

+0

@dreeves - puoi elaborare? –

0

Se si desidera generare valori da una distribuzione normale in modo efficiente, provare il Box Muller Transformation.

+0

Un buon consiglio, ma credo che non sia pertinente. – dreeves

1

Questo è relativamente tardi, ma per mostrare l'ammendamento alla risposta semplice e diretta di @ Kobi fornita in questo paper puntata da @dreeves che rende uniforme il campionamento. Il metodo (se la comprendo chiaramente) è

  1. Genera n-1 distinte valori nell'intervallo [1, 2, ..., M-1].
  2. Ordinare il vettore risultante
  3. Aggiungere 0 e M come primo e ultimo elemento del vettore risultante.
  4. Generare un nuovo vettore calcolando x i - x i-1 dove i = 1,2, ... n. Cioè, il nuovo vettore è costituito dalle differenze tra elementi consecutivi del vecchio vettore.
  5. Dividi ogni elemento del nuovo vettore di M. Hai la tua distribuzione uniforme!

Sono curioso di sapere se generare distinte valori casuali e normalizzazione a 1 dividendo per la loro somma produrrà anche una distribuzione uniforme.

0

Ottenere n numeri casuali, calcolare la loro somma e normalizzare la somma a 1 dividendo ciascun numero con la somma.

Expanding on Kobi's answer, ecco una funzione Java che fa esattamente questo.

public static double[] getRandDistArray(int n) { 
    double randArray[] = new double[n]; 
    double sum = 0; 

    // Generate n random numbers 
    for (int i = 0; i < randArray.length; i++) { 
     randArray[i] = Math.random(); 
     sum += randArray[i]; 
    } 

    // Normalize sum to 1 
    for (int i = 0; i < randArray.length; i++) { 
     randArray[i] /= sum; 
    } 
    return randArray; 
} 

In una corsa di prova, getRandDistArray(5) restituito il seguente

[0.1796505603694718, 0.31518724882558813, 0.15226147256596428, 0.30954417535503603, 0.043356542883939767] 
Problemi correlati