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

  • Dlaczego chcesz to zrobić? Jeśli ' jest ograniczony, to może ' nie być naprawdę normalne. Co próbujesz osiągnąć?
  • x <- rnorm(n, mean, sd); x <- x[x > lower.limit & x < upper.limit]
  • @Hugh that ' jest świetne … o ile nie ' nie obchodzi Cię, ile losowych wartości otrzymasz.

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.

  1. 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

    tutaj wprowadź opis obrazu

    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.

  2. 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.

    tutaj wprowadź opis obrazu

  3. Jeśli masz wystarczająco wydajne pliki cdf i odwrotne cdf (takie jak pnorm i qnorm 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]

    tutaj wprowadź opis obrazu

  4. 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. Pakiet truncnorm 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 $ nie średnią i wariancją obciętego rozkładu.

Odpowiedź

Pomogły mi trzy sposoby:

  1. użycie sample () z rnorm ():

    sample(x=min:max, replace= TRUE, rnorm(n, mean))

  2. używając pakietu msm i funkcji rtnorm:

    rtnorm(n, mean, lower=min, upper=max)

  3. 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]

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *