임의의 이산 분포를 기반으로 숫자를 생성하는 방법은 무엇입니까?


28

임의의 이산 분포를 기반으로 숫자를 생성하려면 어떻게합니까?

예를 들어, 생성하려는 숫자 세트가 있습니다. 다음과 같이 1-3에서 레이블이 지정되어 있다고 가정하십시오.

1 : 4 %, 2 : 50 %, 3 : 46 %

기본적으로 백분율은 난수 생성기의 출력에 나타날 확률입니다. 간격 [0, 1]에서 균일 분포를 생성하는 의사 난수 생성기가 있습니다. 이 작업을 수행하는 방법이 있습니까?

내가 가질 수있는 요소 수에는 제한이 없지만 %는 최대 100 %가됩니다.


2
질문에 "... 임의 이산 형 분포"를 지정하는 것이 좋습니다. 연속적인 경우가 다릅니다.
David M Kaplan

3
일반적인 방법은 누적 확률 목록 내에서 이진 검색을 수행하는 것입니다.이 예에서는 입니다. 평균적으로 이것은 생성 이벤트 당 프로브를 사용합니다. 확률이 매우 작지 않은 경우 에서 동일한 간격 값으로 구성된 벡터를 생성 하고 (사전 계산 단계에서) 각 값에 결과를 할당하여 성능을 얻을 수 있습니다 . 예를 들어,이 예에서는 벡터 ( 2 및 3)를 만들 수 있습니다. 유니폼에 100을 곱한 다음이 벡터에 색인을 생성하십시오. log ( n ) / 2 O ( 1 ) [ 0 , 1 ] ( 1 , 1 , 1 , 1 , 2 , , 2 , 3 , , 3 ) 50 46(0,0.04,0.54,1.0)log(n)/2O(1)[0,1](1,1,1,1,2,,2,3,,3)5046
우버


그 "여기"링크는 실제로 @Glen_b ... copy-n-paste 오류와 같은 바로이 질문에 연결됩니다.
buruzaemon 2016 년

@buruzaemon 감사합니다. 실수였습니다. 나는 그것을 고쳤다.
Glen_b-복지 주 모니카

답변:


26

불연속 분포에서 샘플링하기위한 최상의 알고리즘 중 하나는 별칭 방법 입니다.

앨리어스 방법은 (효율적으로) 2 차원 데이터 구조를 사전 계산하여 확률에 비례하는 영역으로 사각형을 분할합니다.

그림

참조 된 사이트 의이 회로도에서 단위 높이의 사각형은 색상으로 구분하여 , , 및 비율로 4 가지 영역으로 분할되었습니다 . 이러한 확률을 가진 불연속 분포에서 반복적으로 샘플링합니다. 수직 스트립의 폭은 일정합니다. 각각 하나 또는 두 조각으로 나뉩니다. 피스의 ID와 수직 분할의 위치는 열 인덱스를 통해 액세스 가능한 테이블에 저장됩니다.1 / 3 1 / 12 1 / 121/21/31/121/12

테이블은 두 개의 독립적 인 균일 값과 계산을 요구하는 두 개의 간단한 단계 (각 좌표에 대해 하나씩)로 샘플링 할 수 있습니다 . 이것은 다른 회신에 설명 된 것처럼 이산 CDF를 반전시키는 데 필요한 계산을 향상시킵니다 .O ( 로그 ( n ) )O(1)O(log(n))


2
이 알고리즘은 확률이 계산하기에 저렴한 경우에만 최상입니다. 예를 들어, 이 크면 전체 트리를 구성하지 않는 것이 좋습니다. n
chanceislogic

3
+1 지금까지 이것은 효율적인 알고리즘을 제안하고 설명하는 유일한 답변입니다.
whuber

19

R에서 쉽게 수행 할 수 있습니다. 필요한 크기를 지정하십시오.

sample(x=c(1,2,3), size=1000, replace=TRUE, prob=c(.04,.50,.46))

3
개인적으로, 나는 내가 구축하고있는 앱에 이것을 통합하려고하기 때문에 알고리즘 (또는 필요한 지식을 배우는 곳)을 선호합니다 :) 비록 당신의 대답에 감사드립니다 :)
FurtiveFelon

흠 .. 당신이하고 싶은 것에 대해 조금 더 아는 것은 우리를 안내하는 데 도움이 될 것입니다. 그것에 대해 더 자세히 말씀해 주시겠습니까? (목적, 상황 등)
Dominic Comtois

투표 용입니다. 예를 들어, 나는 많은 사진을 가지고 있으며, 한 번에 6 명만 보여줄 수 있고, 한 번에 "최고"를 사용자에게 통합하고, 사용자는 각 사진에 대해 위 또는 아래로 투표 할 수 있습니다 . 지금 가장 효과적인 해결책은 내가 설명한 체계입니다 (각 숫자는 사진을 나타냅니다. 모든 투표는 그 사진에 대한 확률을 줄이고 다른 모든 것을 증가시킵니다)
FurtiveFelon

1
@ furtivefelon, 항상 R에서 코드를 이식 할 수 있습니다 .o 코드에서 알고리즘을 파악하고 다시 구현하십시오.
mpiktas

이 특정 목적을 위해 잘 알려진 솔루션이있을 수 있기 때문에 Stack Overflow에 대해 좋은 조언을 얻을 수 있다고 생각합니다. 마지막 의견의 정보를 질문에 직접 포함시키는 것이 좋습니다.
Dominic Comtois

19

귀하의 예에서, 의사 난수 균일 [0,1] 값을 그리고 U라고 부르십시오.

U <0.04 인 경우 1

U> = 0.04이고 U <0.54 인 경우 2

U> = 0.54 인 경우 3

지정된 %가 a, b, ... 인 경우 간단히 출력

U이면 값 1

U> = a이고 U <(a + b) 인 경우 값 2

기타

본질적으로, 우리는 %를 [0,1]의 부분 집합으로 매핑하고 있으며 균일 한 임의의 값이 임의의 범위에 속할 확률은 단순히 해당 범위의 길이라는 것을 알고 있습니다. 범위를 순서대로 배치하는 것이 고유하지는 않지만 가장 간단한 방법입니다. 이것은 당신이 이산 분포에 대해서만 묻는다고 가정합니다. 연속적으로 "거부 샘플링"( Wikipedia entry ) 과 같은 작업을 수행 할 수 있습니다 .


8
범주를 확률의 내림차순으로 정렬하면 알고리즘이 더 빠릅니다. 이렇게하면 생성 된 난 수당 테스트 횟수가 줄어 듭니다 (평균).
jbowman

1
정렬에 대한 간단한 메모를 추가하기 만하면됩니다. 이는 샘플링 체계를 시작할 때 한 번만 수행하는 경우에만 유효하므로 확률이 전체적으로 큰 체계의 일부로 샘플링 된 경우에는 적합하지 않습니다 ( 예 : 및 ). 이 경우 정렬하면 모든 샘플링 반복에 정렬 작업을 추가합니다. 각 반복에 시간이 추가됩니다. 그러나이 경우 시작시 확률의 크기를 대략적으로 추측하여 정렬하는 것이 유용 할 수 있습니다. P의 R ( Y = J ) = P J O ( N 로그 ( N ) )pjDistPr(Y=j)=pjO(nlog(n))
probabilityislogic

4

존재한다고 가정 가능한 이산 결과가. 누적 확률 질량 함수 에 따라 간격 을 하위 간격으로 나누면 분할 된 간격이됩니다.[ 0 , 1 ] F ( 0 , 1 )m[0,1]F(0,1)

I1I2Im

여기서 및 입니다. 귀하의 예에서 및Ij=(F(j1),F(j))F(0)0m=3

I1=(0,.04),     I2=(.04,.54),     I3=(.54,1)

및 및 이기 때문 입니다.F(1)=.04F(2)=.54F(3)=1

그런 다음 다음 알고리즘을 사용하여 분포 사용하여 를 생성 할 수 있습니다 .XF

(1)UUniform(0,1)

(2) 인 경우 입니다.UIjX=j

  • 이 단계는 가 각 누적 확률 보다 작은 지 여부를 확인 하고 변경 지점 (에서 ~까지 )을 확인하여 사용하는 프로그래밍 언어에서 부울 연산자를 사용하여 벡터에서 처음 발생 하는 위치 찾기UTRUEFALSEFALSE

참고 정확히 하나의 간격의에있을 것입니다 가 해체 및 파티션이기 때문에 .UIj[0,1]


그 간격이 모두 반 닫혀서는 안됩니까? 그렇지 않으면 간격 사이의 경계는 포함되지 않습니다. {[0,0.04), [0.04,0.54), [0.54,1]}
naught101

1
P(U=u)=0임의의 포인트 대해 (즉, 반 개방 간격의 Lebesgue 측정 값이 개방 간격의 측정 값과 동일 함) 그래서 그것이 중요하지 않다고 생각합니다. u
매크로

1
그러나 유한 정밀도 디지털 머신에서는 아마도 우주가 끝나기 전에 언젠가는 중요 할 것입니다.
jbowman

1
충분히 @whuber, 내 편집 내용을 참조하십시오.
매크로

1
자, 그것은 알고리즘입니다. BTW, 왜 그냥 같은 것을 반환하지 min(which(u < cp))않습니까? 각 호출에서 누적 합계를 다시 계산하지 않는 것이 좋습니다. 사전 계산을 통해 전체 알고리즘이로 줄어 듭니다 min(which(runif(1) < cp)). 또는 OP가 숫자 ( 복수 ) 를 생성하도록 요청하기 때문에로 벡터화하십시오 n<-10; apply(matrix(runif(n),1), 2, function(u) min(which(u < cp))).
whuber

2

하나의 간단한 알고리즘은 균일 한 난수로 시작하고 루프에서 첫 번째 확률을 먼저 뺍니다. 결과가 음수이면 첫 번째 값을 반환하고 여전히 긍정적이면 다음 반복으로 이동하여 다음 확률을 뺍니다. , 부정인지 확인하십시오.

이것은 값 / 확률의 수가 무한 할 수 있다는 점에서 좋지만 (포아송 또는 음의 이항 분포에서 생성하는 것과 같은) 숫자에 가까울 때만 확률을 계산하면됩니다.

유한 확률 집합이 있지만 그로부터 많은 수를 생성하는 경우 확률을 정렬하는 것이 더 효율적이어서 가장 큰 값을 먼저 빼고 다음으로 두 번째로 큰 값을 뺄 수 있습니다.


2

우선, 임의의 분포를 따르는 정수 또는 부동 소수점 난수 생성을 위해 즉시 사용 가능한 클래스가 있는 파이썬 라이브러리에 주의를 기울 이십시오.

일반적으로이 문제에는 몇 가지 접근 방식이 있습니다. 일부는 시간이 선형이지만 큰 메모리 저장 공간이 필요하고 일부는 O (n log (n)) 시간에 실행됩니다. 일부는 정수에 최적화되어 있고 일부는 순환 히스토그램에 대해 정의되어 있습니다 (예 : 하루 동안 임의의 시간대를 생성). 위에서 언급 한 라이브러리 에서이 문서 는 정수의 경우와 부동 소수점의 경우에 대한 레시피 를 사용했습니다. 원형 히스토그램 지원이 부족하고 일반적으로 지저분하지만 잘 작동합니다.


2

나는 같은 문제가 있었다. 각 항목에 확률이 있고 항목의 확률이 최대 하나 인 집합을 감안할 때, 효율적으로 샘플을 그리고 싶었습니다. 즉, 어떤 것도 정렬하지 않고 반복적으로 반복하지 않습니다 .

다음 함수는 간격 내에서 균일하게 분포 된 난수 중 가장 낮은 값을 그립니다 . 하자 에서 임의의 숫자 .N[a,1)r[0,1)

next(N,a)=1(1a)rN

이 함수를 사용하여 [0,1) 에 균일하게 분포 된 난수 의 오름차순 시리즈 를 그릴 수 있습니다 . 다음은 인 예입니다 .(ai)NN=10

a0=next(10,0)
a1=next(9,a0)
a2=next(8,a1)

a9=next(1,a8)

균일하게 분포 된 숫자의 오름차순 시리즈 를 그리면서 임의 (아직 유한) 분포를 나타내는 확률 세트 를 반복 합니다. 하자이터레이터이고 입니다. 그린 후 까지 0 번 이상 증가시킵니다 . 그런 다음 샘플 에 를 추가 하고 도면으로 갑니다 .(ai)P0k<|P|pkPaikp0pk>aipkai+1


op의 세트가 이고 샘플 크기 :{(1,0.04),(2,0.5),(3,0.46)}N=10

나는 a_i k Sum Draw
0 0.031 0 0.04 1
1 0.200 1 0.54 2
2 0.236 1 0.54 2
3 0.402 1 0.54 2
4 0.488 1 0.54 2
5 0.589 2 1.0 3
6 0.625 2 1.0 3
7 0.638 2 1.0 3
8 0.738 2 1.0 3
9 0.942 2 1.0 3

샘플 :(1,2,2,2,2,3,3,3,3,3)


함수가 궁금하다면 : 균일하게 분포 된 난수 중 하나 가 의 간격 내에있을 확률의 반대입니다 .nextN[a,x)x1


두 번째 단락에서 해결하려는 문제가 임의의 이산 분포에서 균일 분포의 표본으로 샘플링되는 문제로 나타납니다 . 그 해결책은 여기에서 제기 된 질문과 관련이없는 것으로 보입니다.
whuber

나는 마지막 부분을 명확히했다.
casi

귀하의 답변은 여전히 ​​질문과 관련이없는 것 같습니다. 작지만 사소하지 않은 알고리즘 예제를 제공 할 수 있습니까? 질문에 주어진 확률에 따라 세트 에서 단일 드로우를 생성하는 방법을 보여주십시오 . {1,2,3}
whuber

예를 추가했습니다. 내 대답은 David M Kaplan의 답변 ( stats.stackexchange.com/a/26860/93386 )과 공통점이 있지만 N N- 뿌리. 나는 두 절차를 모두 프로파일 링했고, 훨씬 빨랐다.
casi

설명에 감사드립니다 (+1). 결과가 미리 정해진 고정 된 순서로 나타나기 때문에 이것이 단순한 랜덤 샘플이 아니라는 것이 많은 독자들에게 흥미로울 수 있습니다. 간단한 랜덤 샘플을 생성하기 위해서는 랜덤 순열이 결과에 적용되어야합니다. 인이 알고리즘의 병렬화 가능한 버전에 관심이있을 수도 있습니다. 여기서, 은 Uniform (0,1] 변수의 단순한 랜덤 샘플입니다. u1,,uN+1
aj=i=1jlog(ui)i=1N+1log(ui)
u1,,uN+1
whuber
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.