균등 분포를 정규 분포로 변환


106

균등 분포 (대부분의 난수 생성기가 생성하는 0.0과 1.0 사이)를 정규 분포로 어떻게 변환 할 수 있습니까? 내가 선택한 평균 및 표준 편차를 원하면 어떻게합니까?


3
언어 사양이 있습니까, 아니면 일반적인 알고리즘 질문입니까?
Bill the Lizard

3
일반적인 알고리즘 질문. 어떤 언어는 상관 없습니다. 그러나 그 대답이 해당 언어 만 제공하는 특정 기능에 의존하지 않는 것이 좋습니다.
Terhorst

답변:



47

많은 방법이 있습니다.

  • 마십시오 하지 상자 뮬러를 사용합니다. 특히 많은 가우스 숫자를 그리는 경우. Box Muller는 -6과 6 사이에 고정 된 결과를 산출합니다 (배정 밀도 가정. 수레로 인해 상황이 악화됩니다.). 그리고 다른 사용 가능한 방법보다 효율성이 떨어집니다.
  • Ziggurat는 괜찮지 만 테이블 조회가 필요합니다 (캐시 크기 문제로 인해 일부 플랫폼 별 조정).
  • 균일 비율은 내가 가장 좋아하는 것인데, 몇 번의 덧셈 / 곱셈과 로그의 1/50 정도입니다 (예 : 저기보세요 ).
  • CDF를 반전하는 것은 효율적이며 (그리고 간과 된 이유는 무엇입니까?) Google을 검색하면 사용할 수있는 빠른 구현이 있습니다. 준 난수에는 필수입니다.

2
[-6,6] 클램핑에 대해 확신하십니까? 사실이라면 이것은 꽤 중요한 점입니다 (그리고 위키피디아 페이지에 메모 할 가치가 있습니다).
redcalx

1
@locster : 이것은 내 선생님이 나에게 말한 것입니다 (그는 그러한 발전기를 연구했으며 그의 말을 신뢰합니다). 참조를 찾을 수 있습니다.
Alexandre C.

7
@locster :이 바람직하지 않은 속성은 역 CDF 메서드에서도 공유됩니다. cimat.mx/~src/prope08/randomgauss.pdf를 참조하십시오 . 이것은 0이 아닌 확률을 가진 균일 한 RNG를 사용하여 0에 매우 가까운 부동 소수점 숫자를 생성함으로써 완화 될 수 있습니다. 대부분의 RNG는 그렇지 않습니다. (일반적으로 64 비트) 정수를 생성하고 [0,1]에 매핑되기 때문입니다. 이로 인해 이러한 방법은 가우스 변수의 꼬리를 샘플링하는 데 적합하지 않습니다 (전산 금융에서 저가 / 고가 옵션 가격 책정 고려).
Alexandre C.

6
@AlexandreC. 두 점을 명확히하기 위해 64 비트 숫자를 사용하여 꼬리는 8.57 또는 9.41 (로그를 취하기 전에 [0,1)로 변환하는 것에 해당하는 낮은 값)으로 나갑니다. [-6, 6]으로 고정 되더라도이 범위를 벗어날 가능성은 약 1.98e-9로, 과학 분야에서도 대부분의 사람들에게 충분합니다. 8.57 및 9.41 수치의 경우 1.04e-17 및 4.97e-21이됩니다. 이 숫자는 너무 작아서 상자 뮐러 샘플링과 실제 가우시안 샘플링의 차이는 거의 순수하게 학문적입니다. 당신이 더 필요한 경우, 단지 2로 그들과 분열의 네 가지를 추가
CrazyCasta

6
Box Muller 변환을 사용하지 말라는 제안은 많은 사용자에게 오해의 소지가 있다고 생각합니다. 제한 사항에 대해 아는 것은 좋지만 CrazyCasta가 지적했듯이 이상치에 크게 의존하지 않는 대부분의 응용 프로그램에서는 이에 대해 걱정할 필요가 없습니다. 예를 들어, numpy를 사용하여 법선에서 샘플링에 의존 한 적이 있다면 Box Muller 변환 (극좌표 형식) github.com/numpy/numpy/blob/…에 의존했습니다 .
안드레아스 Grivas

30

함수의 분포를 다른 함수로 변경하려면 원하는 함수의 역함수를 사용해야합니다.

즉, 특정 확률 함수 p (x)를 목표로하는 경우이를 적분하여 분포를 얻고-> d (x) = 적분 (p (x))을 역으로 사용합니다. Inv (d (x)) . 이제 무작위 확률 함수 (균일 분포를 가짐)를 사용하고 Inv (d (x)) 함수를 통해 결과 값을 캐스팅합니다. 선택한 함수에 따라 분포와 함께 무작위 값이 캐스팅되어야합니다.

이것은 일반적인 수학 접근 방식입니다. 이제이를 사용하여 역 근사 또는 좋은 역 근사를 가지고있는 한 모든 확률 또는 분포 함수를 선택할 수 있습니다.

이것이 도움이 되었기를 바라며 확률 자체가 아닌 분포 사용에 대한 작은 언급에 감사드립니다.


4
+1 이것은 매우 잘 작동하는 가우스 변수를 생성하는 간과 된 방법입니다. 역 CDF는이 경우 Newton 방법으로 효율적으로 계산할 수 있으며 (미분은 e ^ {-t ^ 2}), 초기 근사는 유리수로 쉽게 얻을 수 있으므로 erf 및 exp에 대한 3-4 개의 평가가 필요합니다. 준 난수를 사용하는 경우 필수이며, 가우스를 얻기 위해 정확히 하나의 균일 한 숫자를 사용해야하는 경우입니다.
Alexandre C.

9
확률 분포 함수가 아니라 누적 분포 함수를 반전해야합니다. Alexandre는 이것을 암시하지만 더 명시 적으로 언급하는 것이
나쁘지

평균에 상대적인 방향을 무작위로 선택할 준비가 되었으면 PDF를 사용할 수 있습니다. 나는 그 권리를 이해합니까?
Mark McKenna


1
여기 에 SE의 관련 질문이 있으며 좋은 설명과 함께 더 일반적인 답변이 있습니다.
dashesy

23

다음은 Box-Muller 변환의 극지 형식을 사용하는 자바 스크립트 구현입니다.

/*
 * Returns member of set with a given mean and standard deviation
 * mean: mean
 * standard deviation: std_dev 
 */
function createMemberInNormalDistribution(mean,std_dev){
    return mean + (gaussRandom()*std_dev);
}

/*
 * Returns random number in normal distribution centering on 0.
 * ~95% of numbers returned should fall between -2 and 2
 * ie within two standard deviations
 */
function gaussRandom() {
    var u = 2*Math.random()-1;
    var v = 2*Math.random()-1;
    var r = u*u + v*v;
    /*if outside interval [0,1] start over*/
    if(r == 0 || r >= 1) return gaussRandom();

    var c = Math.sqrt(-2*Math.log(r)/r);
    return u*c;

    /* todo: optimize this algorithm by caching (v*c) 
     * and returning next time gaussRandom() is called.
     * left out for simplicity */
}

5

중앙 한계 정리 위키피디아 항목 mathworld 항목 을 유리하게 사용하십시오.

균등하게 분포 된 n 개의 숫자를 생성하고 합계하고 n * 0.5를 빼면 평균이 0이고 분산이 다음과 같은 대략적인 정규 분포의 결과가 나타납니다 (마지막 항목에 대한 균등 분포에 대한 위키피디아(1/12) * (1/sqrt(N)) 참조 ).

n = 10은 반쯤 괜찮은 속도를 제공합니다. 반 이상 괜찮은 것을 원한다면 tylers 솔루션으로 가십시오 ( 정규 분포에 대한 위키피디아 항목에서 언급했듯이 )


1
이것은 특히 가까운 정규 분포를 제공하지 않습니다 ( "꼬리"또는 끝 점이 실제 정규 분포에 가깝지 않음). 다른 사람들이 제안했듯이 Box-Muller가 더 좋습니다.
Peter K.

1
Box Muller에도 잘못된 꼬리가 있습니다 (배정 밀도로 -6과 6 사이의 숫자를 반환)
Alexandre C.

n = 12 (0에서 1 범위의 난수 12 개를 더하고 6을 뺀 값)은 stddev = 1 및 mean = 0이됩니다. 그런 다음 모든 정규 분포를 생성하는 데 사용할 수 있습니다. 결과에 원하는 stddev를 곱하고 평균을 더하면됩니다.
JerryM

3

Box-Muller를 사용합니다. 이것에 대해 두 가지 :

  1. 반복 당 두 개의 값으로 끝납니다.
    일반적으로 한 값을 캐시하고 다른 값을 반환합니다. 다음 샘플 호출에서 캐시 된 값을 반환합니다.
  2. Box-Muller는 Z- 점수를 제공합니다.
    그런 다음 표준 편차로 Z- 점수를 스케일링하고 평균을 더하여 정규 분포의 전체 값을 얻어야합니다.

Z 점수는 어떻게 조정합니까?
Terhorst

3
scaled = mean + stdDev * zScore // normal (mean, stdDev ^ 2)
yoyoyoyosef

2

여기서 R1, R2는 임의의 균일 한 숫자입니다.

표준 분포, SD 1 : sqrt (-2 * log (R1)) * cos (2 * pi * R2)

이것은 정확합니다 ... 모든 느린 루프를 수행 할 필요가 없습니다!


누군가 나를 고치기 전에 ... 여기에 내가 생각 해낸 근사치가 있습니다 : (1.5- (R1 + R2 + R3)) * 1.88. 나도 좋아해.
Erik Aronesty 2011 년

2

8 년 후에 여기에 뭔가를 추가 할 수 있다는 것이 놀랍게 느껴지지만, Java의 경우 독자들에게 Random.nextGaussian () 메서드를 알려 드리고 싶습니다.이 메서드는 평균 0.0과 표준 편차 1.0의 가우시안 분포를 생성합니다.

간단한 더하기 및 / 또는 곱하기는 평균 및 표준 편차를 필요에 따라 변경합니다.


1

임의 의 표준 Python 라이브러리 모듈 에는 원하는 것이 있습니다.

normalvariate (mu, sigma)
정규 분포. mu는 평균이고 sigma는 표준 편차입니다.

알고리즘 자체의 경우 Python 라이브러리의 random.py에있는 함수를 살펴보십시오.

수동 입력은 여기


2
불행히도 python의 라이브러리는 Kinderman, AJ 및 Monahan, JF, "균일 편차 비율을 사용한 랜덤 변수의 컴퓨터 생성", ACM Trans Math Software, 3, (1977), pp257-260을 사용합니다. 이것은 단일 변수가 아닌 두 개의 균일 랜덤 변수를 사용하여 정규 값을 생성하므로 OP가 원하는 매핑으로 사용하는 방법이 명확하지 않습니다.
Ian

1

이것은 Donald Knuth의 책 The Art of Computer Programming 의 섹션 3.4.1에서 Algorithm P ( 일반 편차에 대한 Polar 메서드) 의 JavaScript 구현입니다 .

function normal_random(mean,stddev)
{
    var V1
    var V2
    var S
    do{
        var U1 = Math.random() // return uniform distributed in [0,1[
        var U2 = Math.random()
        V1 = 2*U1-1
        V2 = 2*U2-1
        S = V1*V1+V2*V2
    }while(S >= 1)
    if(S===0) return 0
    return mean+stddev*(V1*Math.sqrt(-2*Math.log(S)/S))
}

0

EXCEL에서 이것을 시도해야 할 것 =norminv(rand();0;1)입니다. 이것은 제로 평균과 단위 분산으로 정규 분포되어야하는 난수를 생성 할 것입니다. "0"은 임의의 값으로 제공 될 수 있으므로 숫자는 원하는 평균이되고 "1"을 변경하면 입력의 제곱과 동일한 분산을 얻을 수 있습니다.

예 : =norminv(rand();50;3)MEAN = 50 VARIANCE = 9 인 정규 분포 된 숫자를 산출합니다.


0

Q 균등 분포 (대부분의 난수 생성기가 생성하는 0.0과 1.0 사이)를 정규 분포로 변환하려면 어떻게해야합니까?

  1. 소프트웨어 구현을 위해 [0,1] (Mersenne Twister, Linear Congruate Generator)에서 의사 균일 임의 시퀀스를 제공하는 몇 가지 임의 생성기 이름을 알고 있습니다. U (x)라고 부르 자

  2. 확률론이라고 불리는 수학적 영역이 존재합니다. 첫 번째 : 적분 분포 F로 rv를 모델링하려면 F ^ -1 (U (x))를 평가 해 볼 수 있습니다. 실제 이론에서 그러한 rv는 적분 분포 F를 가질 것이라는 것이 입증되었습니다.

  3. 2 단계는 F ^ -1이 문제없이 분석적으로 도출 될 수있는 경우 계수 방법을 사용하지 않고 rv ~ F를 생성하는 데 적용 할 수 있습니다. (예 : exp. 배포)

  4. 정규 분포를 모델링하기 위해 y1 * cos (y2)를 계산할 수 있습니다. 여기서 y1 ~은 [0,2pi]에서 균일합니다. y2는 relei 분포입니다.

Q : 선택한 평균 및 표준 편차를 원하면 어떻게합니까?

sigma * N (0,1) + m을 계산할 수 있습니다.

이러한 이동 및 스케일링이 N (m, sigma)로 이어진다는 것을 알 수 있습니다.


0

이것은 Box-Muller 변환 의 극지 형식을 사용하는 Matlab 구현입니다 .

기능 randn_box_muller.m:

function [values] = randn_box_muller(n, mean, std_dev)
    if nargin == 1
       mean = 0;
       std_dev = 1;
    end

    r = gaussRandomN(n);
    values = r.*std_dev - mean;
end

function [values] = gaussRandomN(n)
    [u, v, r] = gaussRandomNValid(n);

    c = sqrt(-2*log(r)./r);
    values = u.*c;
end

function [u, v, r] = gaussRandomNValid(n)
    r = zeros(n, 1);
    u = zeros(n, 1);
    v = zeros(n, 1);

    filter = r==0 | r>=1;

    % if outside interval [0,1] start over
    while n ~= 0
        u(filter) = 2*rand(n, 1)-1;
        v(filter) = 2*rand(n, 1)-1;
        r(filter) = u(filter).*u(filter) + v(filter).*v(filter);

        filter = r==0 | r>=1;
        n = size(r(filter),1);
    end
end

그리고 histfit(randn_box_muller(10000000),100);이것을 호출 하면 결과는 다음과 같습니다. Box-Muller Matlab Histfit

분명히 Matlab 내장 randn 과 비교할 때 정말 비효율적 입니다.


0

도움이 될 수있는 다음 코드가 있습니다.

set.seed(123)
n <- 1000
u <- runif(n) #creates U
x <- -log(u)
y <- runif(n, max=u*sqrt((2*exp(1))/pi)) #create Y
z <- ifelse (y < dnorm(x)/2, -x, NA)
z <- ifelse ((y > dnorm(x)/2) & (y < dnorm(x)), x, z)
z <- z[!is.na(z)]

0

또한 정규 분포를 위해 난수 생성기를 작성하는 것보다 빠르기 때문에 구현 된 함수 rnorm ()을 사용하는 것이 더 쉽습니다. 증명으로 다음 코드를 참조하십시오.

n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0

-2
function distRandom(){
  do{
    x=random(DISTRIBUTION_DOMAIN);
  }while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
  return x;
}

하지만 돌아올 것이라는 보장은 없습니까? ;-)
Peter K.

5
난수는 우연에 맡기기에는 너무 중요합니다.
Drew Noakes 2011 년

질문에 답하지 않습니다. 정규 분포에는 무한 영역이 있습니다.
Matt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.