정규 분포의 혼합에서 랜덤 변수 생성


20

혼합 분포, 특히 정규 분포의 혼합에서 표본을 추출하려면 어떻게 R해야합니까? 예를 들어 다음에서 샘플링하려는 경우 :

0.3×N(0,1)+0.5×N(10,1)+0.2×N(3,.1)

내가 어떻게 할 수 있습니까?


3
나는 혼합물을 나타내는이 방법을 정말로 좋아하지 않습니다. 나는 이것이 일반적으로 이런 식으로 행해졌다는 것을 알고 있지만 오해의 소지가 있음을 발견합니다. 표본은 세 가지 법선을 모두 샘플링하고 그 결과가 분명히 정확하지 않은 계수로 결과를 측정해야 함을 나타냅니다. 더 나은 표기법을 아는 사람이 있습니까?
StijnDeVuyst

나는 그런 인상을받지 못했다. 분포 (이 경우에는 세 개의 정규 분포)를 함수로 생각한 다음 결과는 다른 함수입니다.
roundsquare

@StijnDeVuyst 당신은 당신의 코멘트에서 유래 한이 질문을 방문하고 싶을 것입니다 : stats.stackexchange.com/questions/431171/…
ankii

@ankii : 지적 해 주셔서 감사합니다!
StijnDeVuyst

답변:


32

성능상의 이유로 for루프 를 피하는 것이 좋습니다 R. 사실을 이용하는 대체 솔루션 rnorm은 벡터화됩니다.

N <- 100000

components <- sample(1:3,prob=c(0.3,0.5,0.2),size=N,replace=TRUE)
mus <- c(0,10,3)
sds <- sqrt(c(1,1,0.1))

samples <- rnorm(n=N,mean=mus[components],sd=sds[components])

3
또는 정규 분포의 속성을 사용하여 마지막 줄을로 바꿀 수 있습니다 samples <- rnorm(N)*sds[components]+mus[components]. 읽기가 더 쉽다는 것을 알았습니다 :)
Elvis

매우 우아한 (cc @Elvis)!
Itamar

18

일반적으로 혼합 분포에서 샘플링하는 가장 쉬운 방법 중 하나는 다음과 같습니다.

알고리즘 단계

1) 랜덤 변수 제복(0,1)

2) 구간 (여기서 p k 는 혼합 모형 의 k t h 성분 확률에 해당) k t h 성분 의 분포[나는=1케이케이,나는=1케이+1케이+1)케이케이h케이h

3) 혼합물 분포에서 원하는 양의 샘플이 나올 때까지 1) 및 2) 단계를 반복하십시오.

이제 위의 일반적인 알고리즘을 사용하여 다음 R코드 를 사용하여 예제 혼합 법선에서 샘플링 할 수 있습니다.

#The number of samples from the mixture distribution
N = 100000                 

#Sample N random uniforms U
U =runif(N)

#Variable to store the samples from the mixture distribution                                             
rand.samples = rep(NA,N)

#Sampling from the mixture
for(i in 1:N){
    if(U[i]<.3){
        rand.samples[i] = rnorm(1,0,1)
    }else if(U[i]<.8){
        rand.samples[i] = rnorm(1,10,1)
    }else{
        rand.samples[i] = rnorm(1,3,.1)
    }
}

#Density plot of the random samples
plot(density(rand.samples),main="Density Estimate of the Mixture Model")

#Plotting the true density as a sanity check
x = seq(-20,20,.1)
truth = .3*dnorm(x,0,1) + .5*dnorm(x,10,1) + .2*dnorm(x,3,.1)
plot(density(rand.samples),main="Density Estimate of the Mixture Model",ylim=c(0,.2),lwd=2)
lines(x,truth,col="red",lwd=2)

legend("topleft",c("True Density","Estimated Density"),col=c("red","black"),lwd=2)

어떤 생성 :

여기에 이미지 설명을 입력하십시오

그리고 위생 검사로 :

여기에 이미지 설명을 입력하십시오


안녕하세요! 정말 고마워! 이 답변은 큰 도움이되었습니다. 나는 이것을 연구 프로젝트에서 사용하고 있습니다. 위의 참조를 인용하고 싶습니다. 연구 논문 인용을 제안 해 주시겠습니까?
Abhishek Bhatia 2016 년

7

케이R

set.seed(8)               # this makes the example reproducible
N     = 1000              # this is how many data you want
probs = c(.3,.8)          # these are *cumulative* probabilities; since they 
                          #   necessarily sum to 1, the last would be redundant
dists = runif(N)          # here I'm generating random variates from a uniform
                          #   to select the relevant distribution

# this is where the actual data are generated, it's just some if->then
#   statements, followed by the normal distributions you were interested in
data = vector(length=N)
for(i in 1:N){
  if(dists[i]<probs[1]){
    data[i] = rnorm(1, mean=0, sd=1)
  } else if(dists[i]<probs[2]){
    data[i] = rnorm(1, mean=10, sd=1)
  } else {
    data[i] = rnorm(1, mean=3, sd=.1)
  }
}

# here are a couple of ways of looking at the results
summary(data)
#    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
# -3.2820  0.8443  3.1910  5.5350 10.0700 13.1600 

plot(density(data))

여기에 이미지 설명을 입력하십시오


좋은 대답, 당신은 게시에 나를 이길 : P

1
팁, @BabakP에 감사드립니다. 그것이 무엇인지 잘 모르겠습니다. ifelse()성명서 에 뭔가 있었지만 나중에 알아 내야합니다. 루프가있는 코드를 바꿨습니다.
gung-모니 티 복원

6
RfindInterval()cumsum()μmuσ2spmix <- function(n,mu,s,p) { ii <- findInterval(runif(n),cumsum(p))+1; x <- rnorm(n,mean=mu[ii],sd=sqrt(s[ii])); return(x); }

1
@ 매크로, 매우 진실되고 멋진 코드! findInterval()그러나 이전 에는 명령을 보지 못했지만 효율성보다는 이해를위한 도구가되기 때문에 가능한 한 간단하게 여기에 코드를 작성하고 싶습니다.

1
나는 이것이 좋은 답변이라고 말했다. 내 목적은 당신을 비판하는 것이 아니라 코드가 아닌 단일 인수 만 변경하여 3 차원 이상으로 쉽게 일반화하는 접근법을 제공하는 것이 었습니다. 왜 당신이 쓴 것이 내가 쓴 것보다 더 투명한지 분명하지 않지만 분명히 그것에 대해 논쟁하고 싶지 않습니다. 건배.
매크로

0

이미 완벽한 대답이 주어 졌으므로 파이썬에서 이것을 달성하려는 사람들을 위해 내 해결책은 다음과 같습니다.

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

mu = [0, 10, 3]
sigma = [1, 1, 1]
p_i = [0.3, 0.5, 0.2]
n = 10000

x = []
for i in range(n):
    z_i = np.argmax(np.random.multinomial(1, p_i))
    x_i = np.random.normal(mu[z_i], sigma[z_i])
    x.append(x_i)

def univariate_normal(x, mean, variance):
    """pdf of the univariate normal distribution."""
    return ((1. / np.sqrt(2 * np.pi * variance)) * 
            np.exp(-(x - mean)**2 / (2 * variance)))

a = np.arange(-7, 18, 0.01)
y = p_i[0] * univariate_normal(a, mean=mu[0], variance=sigma[0]**2) + p_i[1] * univariate_normal(a, mean=mu[1], variance=sigma[0]**2)+ p_i[2] * univariate_normal(a, mean=mu[2], variance=sigma[0]**2)

fig, ax = plt.subplots(figsize=(8, 4))

ax.hist(x, bins=100, density=True)
ax.plot(a, y)

여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.