균등 분포를 정규 분포로 변환
균등 분포 (대부분의 난수 생성기가 생성하는 0.0과 1.0 사이)를 정규 분포로 어떻게 변환 할 수 있습니까? 내가 선택한 평균 및 표준 편차를 원하면 어떻게합니까?
지구라트 알고리즘은 있지만,이 꽤 효율적이다 박스 뮬러 변환 처음부터 쉽게 구현 (느린 미친되지 않음)입니다.
많은 방법이 있습니다.
- 마십시오 하지 상자 뮬러를 사용합니다. 특히 많은 가우스 숫자를 그리는 경우. Box Muller는 -6과 6 사이에 고정 된 결과를 산출합니다 (배정 밀도 가정. 수레로 인해 상황이 악화됩니다.). 그리고 다른 사용 가능한 방법보다 효율성이 떨어집니다.
- Ziggurat는 괜찮지 만 테이블 조회가 필요합니다 (캐시 크기 문제로 인해 일부 플랫폼 별 조정).
- 균일 비율은 내가 가장 좋아하는 것인데, 몇 번의 덧셈 / 곱셈과 로그의 1/50 정도입니다 (예 : 저기보세요 ).
- CDF를 반전하는 것은 효율적이며 (그리고 간과 된 이유는 무엇입니까?) Google을 검색하면 사용할 수있는 빠른 구현이 있습니다. 준 난수에는 필수입니다.
함수의 분포를 다른 함수로 변경하려면 원하는 함수의 역함수를 사용해야합니다.
즉, 특정 확률 함수 p (x)를 목표로하는 경우이를 적분하여 분포를 얻고-> d (x) = 적분 (p (x))을 역으로 사용합니다. Inv (d (x)) . 이제 무작위 확률 함수 (균일 분포를 가짐)를 사용하고 Inv (d (x)) 함수를 통해 결과 값을 캐스팅합니다. 선택한 함수에 따라 분포와 함께 무작위 값이 캐스팅되어야합니다.
이것은 일반적인 수학 접근 방식입니다. 이제이를 사용하여 역 근사 또는 좋은 역 근사를 가지고있는 한 모든 확률 또는 분포 함수를 선택할 수 있습니다.
이것이 도움이 되었기를 바라며 확률 자체가 아닌 분포 사용에 대한 작은 언급에 감사드립니다.
다음은 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 */
}
중앙 한계 정리 위키피디아 항목 mathworld 항목 을 유리하게 사용하십시오.
균등하게 분포 된 n 개의 숫자를 생성하고 합계하고 n * 0.5를 빼면 평균이 0이고 분산이 다음과 같은 대략적인 정규 분포의 결과가 나타납니다 (마지막 항목에 대한 균등 분포에 대한 위키피디아(1/12) * (1/sqrt(N))
참조 ).
n = 10은 반쯤 괜찮은 속도를 제공합니다. 반 이상 괜찮은 것을 원한다면 tylers 솔루션으로 가십시오 ( 정규 분포에 대한 위키피디아 항목에 언급 됨 )
Box-Muller를 사용합니다. 이것에 대해 두 가지 :
- 반복 당 두 개의 값으로 끝납니다.
일반적으로 한 값을 캐시하고 다른 값을 반환합니다. 다음 샘플 호출에서 캐시 된 값을 반환합니다. - Box-Muller는 Z- 점수를 제공합니다.
그런 다음 표준 편차로 Z- 점수를 스케일링하고 평균을 더하여 정규 분포의 전체 값을 얻어야합니다.
여기서 R1, R2는 임의의 균일 한 숫자입니다.
표준 분포, SD 1 : sqrt (-2 * log (R1)) * cos (2 * pi * R2)
이것은 정확합니다 ... 모든 느린 루프를 수행 할 필요가 없습니다!
임의 의 표준 Python 라이브러리 모듈 에는 원하는 것이 있습니다.
normalvariate (mu, sigma)
정규 분포. mu는 평균이고 sigma는 표준 편차입니다.
알고리즘 자체의 경우 Python 라이브러리의 random.py에있는 함수를 살펴보십시오.
8 년 후에 여기에 무언가를 추가 할 수 있다는 것이 놀랍게 느껴지지만 Java의 경우 독자들에게 Random.nextGaussian () 메서드를 알려 드리고 싶습니다.이 메서드는 평균 0.0 및 표준 편차 1.0의 가우시안 분포를 생성합니다.
간단한 더하기 및 / 또는 곱하기는 평균 및 표준 편차를 필요에 따라 변경합니다.
EXCEL에서 이것을 시도해야 할 것 =norminv(rand();0;1)
입니다. 이것은 제로 평균과 단위 분산으로 정규 분포되어야하는 난수를 생성 할 것입니다. "0"은 임의의 값과 함께 제공 될 수 있으므로 숫자는 원하는 평균이되고 "1"을 변경하면 입력의 제곱과 동일한 분산을 얻을 수 있습니다.
예 : =norminv(rand();50;3)
MEAN = 50 VARIANCE = 9 인 정규 분포 된 숫자를 산출합니다.
Q 균등 분포 (대부분의 난수 생성기가 생성하는 0.0과 1.0 사이)를 정규 분포로 변환하려면 어떻게해야합니까?
소프트웨어 구현을 위해 [0,1] (Mersenne Twister, Linear Congruate Generator)에서 의사 균일 임의 시퀀스를 제공하는 몇 가지 임의 생성기 이름을 알고 있습니다. U (x)라고 부르 자
확률론이라고 불리는 수학적 영역이 존재합니다. 첫 번째 : 적분 분포 F로 rv를 모델링하려면 F ^ -1 (U (x))를 평가 해 볼 수 있습니다. 실제 이론에서 그러한 rv는 적분 분포 F를 가질 것이라는 것이 입증되었습니다.
2 단계는 F ^ -1이 문제없이 분석적으로 도출 될 수있는 경우 계수 방법을 사용하지 않고 rv ~ F를 생성하는 데 적용 할 수 있습니다. (예 : exp. 배포)
정규 분포를 모델링하기 위해 y1 * cos (y2)를 계산할 수 있습니다. 여기서 y1 ~은 [0,2pi]에서 균일합니다. y2는 relei 분포입니다.
Q : 선택한 평균 및 표준 편차를 원하면 어떻게합니까?
sigma * N (0,1) + m을 계산할 수 있습니다.
이러한 이동 및 스케일링이 N (m, sigma)로 이어진다는 것을 알 수 있습니다.
이것은 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);
이것을 호출 하면 결과는 다음과 같습니다.
분명히 Matlab 내장 randn 과 비교할 때 정말 비효율적 입니다.
도움이 될 수있는 다음 코드가 있습니다.
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)]
또한 정규 분포를 위해 난수 생성기를 작성하는 것보다 빠르기 때문에 구현 된 함수 rnorm ()을 사용하는 것이 더 쉽습니다. 증명으로 다음 코드를 참조하십시오.
n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
function distRandom(){
do{
x=random(DISTRIBUTION_DOMAIN);
}while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
return x;
}
근사:
function rnd_snd() {
return (Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1);
}
See http://www.protonfish.com/random.shtml
참고URL : https://stackoverflow.com/questions/75677/converting-a-uniform-distribution-to-a-normal-distribution
'Programing' 카테고리의 다른 글
자원의 이름을 지정하는 방법에 대한 규칙이 있습니까? (0) | 2020.08.24 |
---|---|
더 효율적인 방법 : 여러 MySQL 테이블 또는 하나의 큰 테이블? (0) | 2020.08.24 |
루프에서 StringBuilder를 재사용하는 것이 더 낫습니까? (0) | 2020.08.24 |
iOS Safari – 오버 스크롤을 비활성화하고 스크롤 가능한 div가 정상적으로 스크롤되도록 허용하는 방법은 무엇입니까? (0) | 2020.08.24 |
React Native의 iOS 시작 화면 (0) | 2020.08.24 |