Come generare valori distribuiti uniformemente ordinati in un intervallo in modo efficiente?


12

Diciamo che voglio generare un insieme di numeri casuali dall'intervallo (a, b). La sequenza generata dovrebbe anche avere la proprietà che è ordinata. Posso pensare a due modi per raggiungere questo obiettivo.

Lascia che nsia la lunghezza della sequenza da generare.

1 ° algoritmo:

Let `offset = floor((b - a) / n)`
for i = 1 up to n:
   generate a random number r_i from (a, a+offset)
   a = a + offset
   add r_i to the sequence r

2 ° algoritmo:

for i = 1 up to n:
    generate a random number s_i from (a, b)
    add s_i to the sequence s
sort(r)

La mia domanda è: l'algoritmo 1 produce sequenze buone quanto quelle generate dall'algoritmo 2?


A proposito, è straordinariamente facile generare un elenco di numeri casuali ordinati in R. Al fine di generare un array di insiemi di numeri casuali in un intervallo uniforme , il seguente codice funziona: . kn[a,b]rand_array <- replicate(k, sort(runif(n, a, b))
RobertF,

Risposte:


18

Il primo algoritmo fallisce male per due motivi:

  1. Prendere il piano di può ridurlo drasticamente. Infatti, quando , sarà zero, dandoti un set i cui valori sono tutti uguali!(ab)/nba<n

  2. Quando non prendi la parola, i valori risultanti sono distribuiti in modo troppo uniforme . Ad esempio, in qualsiasi campione casuale semplice di uniforme iid variates (dire tra e ), c'è una possibilità che il il più grande non sarà nell'intervallo superiore da a . Con l'algoritmo 1, esiste una probabilità del che il massimo sia compreso in quell'intervallo. Per alcuni scopi questa superuniformità è buona, ma in generale è un terribile errore perché (a) molte statistiche verranno rovinate ma (b) può essere molto difficile determinare il perché.na=0b=1(11/n)n1/e37%11/n1100%

  3. Se si desidera evitare l'ordinamento, generare invece variate indipendenti distribuite esponenzialmente. Normalizza la loro somma cumulativa per l'intervallo dividendo per la somma. Rilascia il valore più grande (che sarà sempre ). Ridimensiona l'intervallo .n+1(0,1)1(a,b)

Vengono visualizzati gli istogrammi di tutti e tre gli algoritmi. (Ciascuno raffigura i risultati cumulativi di insiemi indipendenti di valori ciascuno.) La mancanza di qualsiasi variazione visibile nell'istogramma per l'algoritmo 1 mostra il problema lì. La variazione negli altri due algoritmi è esattamente ciò che ci si aspetta - e ciò che è necessario da un generatore di numeri casuali.1000n=100

Per molti altri modi (divertenti) per simulare varianze uniformi indipendenti, vedere Simulazione di disegni da una distribuzione uniforme usando disegni da una distribuzione normale .

Figura: istogrammi

Ecco il Rcodice che ha prodotto la figura.

b <- 1
a <- 0
n <- 100
n.iter <- 1e3

offset <- (b-a)/n
as <- seq(a, by=offset, length.out=n)
sim.1 <- matrix(runif(n.iter*n, as, as+offset), nrow=n)
sim.2 <- apply(matrix(runif(n.iter*n, a, b), nrow=n), 2, sort)
sim.3 <- apply(matrix(rexp(n.iter*(n+1)), nrow=n+1), 2, function(x) {
  a + (b-a) * cumsum(x)[-(n+1)] / sum(x)
})

par(mfrow=c(1,3))
hist(sim.1, main="Algorithm 1")
hist(sim.2, main="Algorithm 2")
hist(sim.3, main="Exponential")

Cosa ne pensi dell'algoritmo (basato sulle statistiche degli ordinamenti) nella mia risposta? ;-)
QUIT - Anony-Mousse

@Anony È una versione meno efficiente del mio algoritmo 3. (La tua sembra comportare molti inutili riscalaggi.) Generi le variate esponenziali prendendo i registri delle uniformi, che è standard.
whuber

6

Il primo algoritmo produce numeri troppo uniformemente distanziati

Vedi anche serie a bassa discrepanza .

Supponendo di volere 2 numeri casuali in . Con dati uniformi reali, la probabilità è 50:50 che siano entrambi più grandi o più piccoli di 0,5 contemporaneamente. Con il tuo approccio, la possibilità è 0. Quindi i tuoi dati non sono uniformi.[0;1]

(Come sottolineato, questo può essere un esempio proprietà desiderata per la stratificazione. Serie a bassa discrepanza come Halton e Sobel non hanno i loro casi d'uso.)

Un approccio corretto ma costoso (per valori reali)

... è usare numeri casuali distribuiti in beta. La statistica dell'ordine di rango della distribuzione uniforme è distribuita in beta. Puoi usarlo per disegnare casualmente il più piccolo , quindi il secondo più piccolo, ... ripeti.

Supponendo che i dati debbano essere generati in . Il valore più piccolo è distribuito. (Per i casi successivi, ridurre e riscalare all'intervallo rimanente). Per generare un casuale beta generale, dovremmo generare due valori casuali distribuiti Gamma. Ma . Quindi . Possiamo campionare numeri casuali da questa distribuzione come per questo.[0;1]Beta[1,n]n1XBeta[n,1]ln(1X)Exponential[n]ln(U[0;1])n

ln(1x)=ln(1u)n1x=u1nx=1u1n

Che produce il seguente algoritmo:

x = a
for i in range(n, 0, -1):
    x += (b-x) * (1 - pow(rand(), 1. / i))
    result.append(x) 

Potrebbero esserci delle instabilità numeriche, e il calcolo powe una divisione per ogni oggetto potrebbero risultare più lenti dell'ordinamento.

Per i valori interi potrebbe essere necessario utilizzare una distribuzione diversa.

L'ordinamento è incredibilmente economico, quindi basta usarlo

Ma non preoccuparti. L'ordinamento è così ridicolmente economico, quindi basta ordinare. Nel corso degli anni, abbiamo capito bene come implementare algoritmi di ordinamento che l'ordinamento raddoppia non vale la pena evitare. Teoricamente è ma il termine costante è così ridicolmente piccolo in una buona implementazione che questo è l'esempio perfetto di come possano essere inutili risultati di complessità teorica . Esegui un benchmark. Genera 1 milione di random con e senza ordinamento. Eseguilo un paio di volte e non sarei sorpreso se abbastanza spesso l'ordinamento batte il non ordinamento, perché il costo dell'ordinamento sarà comunque molto inferiore all'errore di misurazione.O(nlogn)


1
Ci possono essere motivi per evitare l'ordinamento. Uno è quando si desidera generare un numero enorme di variate casuali, così tante che una normale routine di ordinamento non può gestirle.
whuber

Penso che i problemi numerici con le somme usando la matematica in virgola mobile diventino un problema molto prima. (E i problemi con schemi ciclici in numeri pseudo casuali!) È abbastanza facile ridimensionare l'approccio di ordinamento ai terabyte e agli exabyte su sistemi distribuiti.
Ha QUIT - Anony-Mousse il

Con un ridimensionamento così grande, il termine log inizia a diventare più ... interessante. Anche se è bene preoccuparsi degli errori in virgola mobile, non avranno alcuna conseguenza fino a quando non si sommano più di circa valori e il problema viene facilmente risolto (anche se con più programmazione, lo ammetto) rompendo le somme in sottogruppi. Il mio punto è che quando si esegue un calcolo che deve passare in sequenza attraverso una serie di variate uniformi, i metodi di non ordinamento evitano completamente di doverli generare, archiviare e ordinare inizialmente tutti. 1012
whuber

Ok, non doverli archiviare è un argomento. Ma poi avrai bisogno del mio approccio, la tua variante 3 che utilizza la somma cumulativa non funzionerà.
Ha QUIT - Anony-Mousse il

Questo è un punto eccellente. Ora vedo la virtù dei calcoli extra! (+1)
whuber

5

Dipende anche da cosa stai facendo con i numeri casuali. Per i problemi di integrazione numerica il metodo 1 (se corretto rimuovendo l'operatore del pavimento) produrrebbe un set di punti superiore. Quello che stai facendo è una forma di campionamento stratificato e ha il vantaggio di evitare l'aggregazione. ad esempio, è impossibile ottenere tutti i valori nell'intervallo 0- (ba) / n. Detto questo per altre applicazioni questo potrebbe essere molto male, dipende da cosa vuoi farci.


2
+1 Penso che questo sia un utile contributo alla domanda, soprattutto caratterizzando l'algoritmo 1 in termini di stratificazione.
whuber
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.