Muszę wygenerować liczby losowe zgodnie z rozkładem normalnym w przedziale $ (a, b) $. (Pracuję w R.)
Wiem, że funkcja rnorm(n,mean,sd)
wygeneruje liczby losowe zgodnie z rozkładem normalnym, ale jak ustawić limity interwałów w tym? Czy są do tego dostępne jakieś funkcje języka R?
Komentarze
Odpowiedź
Wygląda na to, że chcesz przeprowadzić symulację z obciętej dystrybucji , a w Twoim konkretnym przykładzie , a zwykłe obcięte .
Jest na to wiele metod, niektóre proste, inne względnie wydajny.
Zilustruję niektóre podejścia na twoim normalnym przykładzie.
-
Oto jedna bardzo prosta metoda generowania pojedynczo (w jakimś pseudokodzie ):
$ \ tt {repeat} $ wygeneruj $ x_i $ z N (średnia, sd) $ \ tt {do} $ dolna $ \ leq x_i \ leq $ górna
Jeśli większość dystrybucji mieści się w granicach, jest to całkiem rozsądne, ale może działać powoli, jeśli prawie zawsze generujesz poza granicami.
W R możesz uniknąć pojedynczej pętli, obliczając obszar w granicach i generując wystarczającą liczbę wartości, abyś był prawie pewien, że po wyrzuceniu wartości poza granicami, w których nadal miałeś tyle wartości, ile potrzeba.
-
Możesz użyć akceptacji-odrzucenia z jakąś odpowiednią funkcją majoralizującą w interwale (w niektórych przypadkach uniform będzie być wystarczająco dobrym). Gdyby granice były dość wąskie w stosunku do s.d. ale nie byłeś daleko w ogonie, na przykład ujednolicenie ujednolicenia działałoby dobrze z normalnym.
-
Jeśli masz wystarczająco wydajne pliki cdf i odwrotne cdf (takie jak
pnorm
iqnorm
dla rozkład normalny w R) możesz użyć metody odwrotnego CDF opisanej w pierwszym akapicie sekcji symulującej strony Wikipedii na obciętej normalnej . [W efekcie jest to to samo, co pobranie obciętego uniforma (obciętego do wymaganych kwantyli, co w rzeczywistości nie wymaga żadnych odrzuceń, ponieważ jest to tylko kolejny uniform) i zastosować do tego odwrotną normalną wartość cdf. Zwróć uwagę, że może się to nie udać, jeśli „jesteś daleko w tyle] -
Istnieją inne podejścia; ta sama strona Wikipedii wspomina o dostosowaniu metody ziggurat , która powinna działać w różnych dystrybucjach.
ten sam link do Wikipedii wspomina o dwóch konkretnych pakietach (oba w CRAN) z funkcjami do generowania obciętych normalnych:
Pakiet
MSM
w języku R ma funkcjęrtnorm
, która oblicza rysunki na podstawie obciętego normalny. Pakiettruncnorm
w R ma również funkcje do rysowania z obciętej normy.
Rozglądając się wokół, wiele z tego jest omówionych w odpowiedziach na inne pytania (ale nie są one dokładnie duplikatami, ponieważ to pytanie jest bardziej ogólne niż zwykłe ucięte) … zobacz dodatkową dyskusję w
a. Ta odpowiedź
b. Xi „an” s odpowiedź tutaj , która zawiera link do jego artykułu arXiv (wraz z innymi wartościowymi odpowiedziami).
Odpowiedź
Szybkim i łatwym podejściem jest użycie reguły 68-95-99.7 .
W rozkładzie normalnym 99,7% wartości mieści się w 3 odchyleniach standardowych średniej. Tak więc, jeśli ustawisz swoją średnią na środku pożądanej wartości minimalnej i maksymalnej oraz ustawisz odchylenie standardowe na 1/3 średniej, otrzymasz (głównie) wartości, które mieszczą się w pożądanym przedziale. Następnie możesz po prostu wyczyścić resztę.
minVal <- 0 maxVal <- 100 mn <- (maxVal - minVal)/2 # Generate numbers (mostly) from min to max x <- rnorm(count, mean = mn, sd = mn/3) # Do something about the out-of-bounds generated values x <- pmax(minVal, x) x <- pmin(maxVal, x)
Niedawno napotkałem ten sam problem, próbując wygenerować losowe oceny uczniów dla danych testowych. W powyższym kodzie użyłem pmax
i pmin
, aby zastąpić wartości spoza zakresu minimalnymi lub maksymalnymi wartościami wewnątrz wartość.Działa to w moim celu, ponieważ generuję dość małe ilości danych, ale przy większych ilościach spowoduje to zauważalne zmiany przy wartościach minimalnej i maksymalnej. Więc w zależności od twoich celów może być lepiej odrzucić te wartości i zastąpić je z NA
s lub „przerzucaj” je, aż znajdą się w granicach.
Komentarze
- Po co to robić? Generowanie normalnych liczb losowych i usuwanie tych, które wymagają obcinania, jest tak proste, że nie ' nie trzeba się tym skomplikować, chyba że żądane obcięcie jest bliskie 100% obszaru gęstości.
- Być może ' źle interpretuję pierwotne pytanie. Natknąłem się na to pytanie, próbując dowiedzieć się, jak wykonać zadanie programistyczne niezwiązane bezpośrednio ze statystykami w języku R, i ' dopiero teraz zauważyłem, że ta strona to zbiór statystyk , a nie programową wymianę stosów. 🙂 W moim przypadku chciałem wygenerować określoną liczbę losowych liczb całkowitych z wartościami od 0 do 100 i chciałem, aby wygenerowane wartości wypadały na ładnej krzywej dzwonowej w tym zakresie. Od kiedy to napisałem, ' zdałem sobie sprawę, że
sample(x=min:max, prob=dnorm(...))
jest prawdopodobnie łatwiejszym sposobem na zrobienie tego. - @Glen_b Aaron Wells wspomina
sample(x=min:max, prob=dnorm(...))
, który wydaje się nieco krótszy niż twoja odpowiedź. - Pamiętaj jednak, że sztuczka
sample()
jest przydatna tylko jeśli ' próbujesz wybrać losowe liczby całkowite lub inny zestaw dyskretnych, wstępnie zdefiniowanych wartości.
Odpowiedź
Żadna z odpowiedzi tutaj nie daje skutecznej metody generowania obciętych zmiennych normalnych, które nie obejmują odrzucenia dowolnie dużych liczba generowanych wartości. Jeśli chcesz wygenerować wartości z obciętego rozkładu normalnego, z określonymi dolnymi i górnymi granicami $ a < b $ , to można zrobić — bez odrzucania — generując jednorodne kwantyle w zakresie kwantyli dozwolonym przez obcięcie i używając próbkowania transformacji odwrotnej , aby uzyskać odpowiednie wartości normalne .
Niech $ \ Phi $ oznacza CDF standardowej dystrybucji normalnej. Chcemy wygenerować $ X_1, …, X_N $ z obciętej dystrybucji normalnej (ze średnim parametrem $ \ mu $ i parametr wariancji $ \ sigma ^ 2 $ ) $ ^ \ dagger $ z dolną i górne granice obcięcia $ a < b $ . Można to zrobić w następujący sposób:
$$ X_i = \ mu + \ sigma \ cdot \ Phi ^ {- 1} (U_i) \ quad \ quad \ quad U_1, …, U_N \ sim \ text {IID U} \ Big [\ Phi \ Big (\ frac {a- \ mu} {\ sigma} \ Big), \ Phi \ Big (\ frac {b- \ mu} {\ sigma} \ Big) \ Big]. $$
Nie ma wbudowanej funkcji dla wygenerowanych wartości z obciętej dystrybucji, ale programowanie tej metody przy użyciu zwykłe funkcje do generowania zmiennych losowych. Oto prosta R
funkcja rtruncnorm
, która implementuje tę metodę w kilku wierszach kodu.
rtruncnorm <- function(N, mean = 0, sd = 1, a = -Inf, b = Inf) { if (a > b) stop("Error: Truncation range is empty"); U <- runif(N, pnorm(a, mean, sd), pnorm(b, mean, sd)); qnorm(U, mean, sd); }
Jest to funkcja wektoryzowana, która generuje N
zmienne losowe IID z obciętego rozkładu normalnego. Byłoby łatwo zaprogramować funkcje dla innych okrojonych dystrybucji za pomocą tej samej metody. Nie byłoby też zbyt trudne zaprogramowanie powiązanych funkcji gęstości i kwantyli dla obciętej dystrybucji.
$ ^ \ dagger $ Zauważ, że obcięcie zmienia średnią i wariancję rozkładu, więc $ \ mu $ i $ \ sigma ^ 2 $ są nie średnią i wariancją obciętego rozkładu.
Odpowiedź
Pomogły mi trzy sposoby:
-
użycie sample () z rnorm ():
sample(x=min:max, replace= TRUE, rnorm(n, mean))
-
używając pakietu msm i funkcji rtnorm:
rtnorm(n, mean, lower=min, upper=max)
-
używając rnorm () i określając dolną i górną granicę, tak jak Hugh napisał powyżej:
sample <- rnorm(n, mean=mean); sample <- sample[x > min & x < max]
x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]