Wybrane metody generowania zmiennych losowych
Poniżej przedstawimy algorytmy losowania zmiennych losowych z różnych popularnych i przydatnych rozkładów, których nie omówiliśmy w poprzednim rozdziale.
Proces Poissona
Jednorodny proces Poissona z częstością , to proces zliczający z niezależnymi przyrostami, spełniający warunki: Czas oczekiwania pomiędzy kolejnymi skokami procesu Poissona ma rozkład wykładniczy .
Do generowania trajektorii jednorodnego procesu Poissona często wykorzystuje się jeden z poniższych sposobów. Każdy wykorzystuje inną właściwość procesu Poissona.
Sposób 1
- Losujemy wektor czasów oczekiwania na kolejne zdarzenie z rozkładu wykładniczego.
- Wyznaczamy czasy pojawiania się kolejnych skoków procesu, jako kumulowane sumy
- Wyznaczamy liczbę skoków do czasu
Sposób 2
- Losujemy liczbę skoków procesu do czasu , liczba skoków ma rozkład Poissona z parametrem
- Na odcinku losujemy skoków z rozkładu jednostajnego
Drugi sposób jest szybszy, ponieważ po pierwszym losowaniu wiemy już ile wartości z rozkładu jednostajnego musimy wylosować. Losowanie z rozkładu jednostajnego jest też szybsze niż losowanie z rozkładu wykładniczego. Poniżej przedstawimy przykładową implementację drugiego sposobu.
rPoisProcess <- function (T=1, lambda=1) {
N <- rpois(1, T*lambda)
sort(runif(N,0,T))
}
Przykładowe wywołanie powyższej funkcji.
set.seed(1313)
rPoisProcess(T=10, lambda=0.2)
## [1] 0.6637362
W podobny sposób możemy generować zmienne z jednorodnego pola losowego, czyli z dwuwymiarowego procesu Poissona.
Polem losowym Poissona nazwiemy proces zliczający z niezależnymi przyrostami, określony na płaszczyźnie, spełniający warunek: Liczba zdarzeń w prostokącie o polu ma rozkład Poissona o częstości . Punkty skoków takiego procesu możemy wyznaczyć następująco
- Losujemy liczbę skoków procesu na prostokącie
- Na prostokącie generujemy punktów z rozkładu jednostajnego.
I implementacja tego algorytmu w programie R.
rRandomField <- function (T1=1, T2=1, lambda=1) {
N = rpois(1, T1*T2*lambda)
data.frame(x=runif(N,0,T1), y=runif(N,0,T2))
}
Przykładowe wywołanie powyższej funkcji.
rRandomField(T1=10, T2=10, lambda=0.02)
## x y
## 1 5.297950 9.469024
## 2 9.142406 5.634131
## 3 5.115911 6.146278
Rozważmy teraz proces Poissona, którego częstość skoków nie jest stała, ale wynosi . Taki proces nazywamy niejednorodnym procesem Poissona. Jest to bardzo często wykorzystywany proces w modelowaniu liczby szkód, częstość występowania szkód najczęściej zmienia się z czasem (liczba oszustw bankomatowych zależy od liczby bankomatów i najczęściej rośnie z czasem, liczba szkód OC zależy od liczby ubezpieczonych samochodów i od szkodowości, oba parametry zmieniają się w czasie itp.).
Załóżmy, że istnieje jakieś maksymalne , takie że . W takim przypadku trajektorie procesu jednorodnego można przetransformować w trajektorie procesu niejednorodnego.
Taką transformację można wykonać na dwa sposoby.
Sposób 1
- Wygenerować jednorodny proces Poissona o częstości .
- Każdy punkt skoku procesu z prawdopodobieństwem uznać za punkt skoku procesu . Czyli dla każdego punktu z wyjściowego procesu losuje się z prawdopodobieństwem czy pozostawić ten punkt w nowym procesie. Metoda ta nosi nazwę metody odsiewania. Odrzucając/odsiewając niektóre punkty skoków redukujemy częstość procesu jednorodnego do niejednorodnego.
Sposób 2
- Wygenerować jednorodny proces Poissona o częstości .
- Przekształcić czasy skoków procesu na czasy procesu tak by czyli , gdzie . Ta metoda nazywana jest metodą zmiany czasu.
Wielowymiarowy rozkład normalny
Gęstość wielowymiarowego rozkładu normalnego jest postaci gdzie to macierz kowariancji, symetryczna dodatnio określona o wymiarach a to wektor średnich o długości .
Zmienne z rozkładu wielowymiarowego normalnego generuje się w dwóch krokach
- W pierwszym kroku generuje się niezależnych zmiennych o rozkładzie normalnym,
- W drugim kroku przekształca się te zmienne by otrzymać średnią i macierz kowariancji . Korzysta się z faktu, że jeżeli , to
W takim razie aby wylosować pożądane zmienne wystarczy wylosować wektor niezależnych zmiennych z następnie przekształcić je liniowo . W tym celu macierz musimy rozłożyć na iloczyn . Można to zrobić używając różnych faktoryzacji macierzy . Wymieńmy trzy
Dekompozycja spektralna gdzie to macierz diagonalna wartości własnych na przekątnej a to macierz wektorów własnych . Macierze i dla macierzy można znaleźć z użyciem funkcji
eigen()
.Dekompozycja SVD, czyli uogólnienie dekompozycji spektralnej na macierze prostokątne,
Jeżeli jest symetryczna i dodatnio określona, to , więc
Funkcje fortranowe dla bibliotek LAPACK pozwalają na uwzględnienie faktu, że rozkładana macierz jest symetryczna i dodatnio określona, ale wrappery R już tego nie uwzględniają, więc ta transformacja jest mniej efektywna. Macierze , i dla macierzy można znaleźć z użyciem funkcji svd()
.
- Dekompozycja Choleskiego, tzw. pierwiastek Choleskiego,
gdzie to macierz górna trójkątna. Macierz dla macierzy można znaleźć z użyciem funkcji
chol()
.
Który z tych algorytmów najlepiej wybrać? Szybszy i numerycznie bardziej stabilny! Porównajmy czasy działania różnych faktoryzacji.
- Faktoryzacja (rozkład) Choleskiego.
n <- 200; d <- 100; N <- 10000
Sigma <- cov(matrix(rnorm(n*d),n,d))
X <- matrix(rnorm(n*d),n,d)
system.time(replicate(N, {Q <- chol(Sigma)
X %*% Q} ))
## user system elapsed
## 20.557 2.025 23.770
- Faktoryzacja SVD
system.time(replicate(N, {tmp <- svd(Sigma)
X %*% (tmp$u %*% diag(sqrt(tmp$d)) %*% t(tmp$v))}))
## user system elapsed
## 101.648 8.117 119.463
- Rozkład spektralny / na wartości własne.
system.time(replicate(N, {tmp <- eigen(Sigma, symmetric=T)
X %*% (tmp$vectors %*% diag(sqrt(tmp$values)) %*% t(tmp$vectors))
}))
## user system elapsed
## 66.521 5.227 78.655
Powyższe czasy zostały policzone dla pewnych przykładowych danych i mogą różnić się w zależności od zainstalowanych bibliotek. Ogólnie jednak najszybszą procedurą jest faktoryzacja Choleskiego i to ona najczęściej jest wykorzystywana do generowania zmiennych o wielowymiarowym rozkładzie normalnym.
W programie R nie musimy do generacji zmiennych z rozkładu normalnego wielowymiarowego ręcznie wykonywać dekompozycji macierzy , wystarczy użyć funkcji rmvnorm(mvtnorm)
. Pozwala ona wskazać metodę faktoryzacji argumentem method=c("eigen", "svd", "chol")
. Domyślnie wykorzystywana jest dekompozycja na wartości spektralne (na wypadek gdyby macierz była niepełnego rzędu), ale jeżeli zależy nam na szybkości i mamy pewność że macierz jest dodatnio określona to lepiej użyć pierwiastka Choleskiego.