Normal dağılımların bir karışımından rasgele değişkenler üretilmesi


20

Bir karışım dağılımından ve özellikle Normal dağılımların bir karışımından nasıl numune alabilirim R? Örneğin, örnek almak istersem:

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

bunu nasıl yapabilirim?


3
Gerçekten bir karışımı ifade etmeyi sevmiyorum. Geleneksel olarak böyle yapıldığını biliyorum ama yanıltıcı buluyorum. Gösterim, örneklemek için, üç normalin hepsini örneklemenizi ve sonuçları doğru olmayacak bu katsayılarla tartmanız gerektiğini gösteriyor. Daha iyi bir gösterim bilen var mı?
StijnDeVuyst

Hiç böyle bir izlenim edinmedim. Dağılımları (bu durumda üç normal dağılım) fonksiyon olarak düşünüyorum ve sonuç başka bir fonksiyon.
roundsquare

@StijnDeVuyst Bu soruyu ziyaret etmek isteyebilirsiniz yorumundan kaynak: stats.stackexchange.com/questions/431171/…
ankii

@ankii: Bunu belirttiğin için teşekkürler!
StijnDeVuyst

Yanıtlar:


32

Performans nedeniyle fordöngülerden kaçınmak iyi bir uygulamadır R. Bu gerçeği kullanan alternatif bir çözüm rnormvektörleştirilmiştir:

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
Alternatif olarak, son satırın yerini almak için normal dağılımın özelliklerini kullanabilirsiniz samples <- rnorm(N)*sds[components]+mus[components]. Okumayı daha kolay buluyorum :)
Elvis

Çok zarif (cc @Elvis)!
Itamar

18

Genel olarak, bir karışım dağılımından numune almanın en kolay yollarından biri şudur:

Algoritma Adımları

1) Rastgele değişken U~üniforma(0,1)

2) aralığı ise, burada p k karışım modelinin k t h bileşeninin olasılığına karşılık gelirse , k t h bileşeninin dağılımıU[Σben=1kpk,Σben=1k+1pk+1)pkkthkth

3) Karışım dağılımından istediğiniz miktarda numune alana kadar 1) ve 2) adımlarını tekrarlayın.

Şimdi yukarıda verilen genel algoritmayı kullanarak, aşağıdaki normal Rkodu kullanarak örnek normal karışımınızdan örnek alabilirsiniz :

#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)

Hangi üretir:

resim açıklamasını buraya girin

ve akıl sağlığı kontrolü olarak:

resim açıklamasını buraya girin


Selam! Çok teşekkürler! Bu cevap bana çok yardımcı oldu. Bunu bir araştırma projesinde kullanıyorum. Yukarıdakilere referans vermek istiyorum. Bir araştırma makalesi alıntı önerebilir misiniz?
Abhishek Bhatia

7

kR

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))

resim açıklamasını buraya girin


Güzel cevap, beni göndererek beni yendi: P

1
Bahşiş için teşekkürler, @BabakP. Ne olduğundan emin değilim. İfadede bir şey vardı ifelse(), ama daha sonra çözmem gerekecek. Bu kodu bir döngü olmadan değiştirdim.
gung - Monica'yı eski durumuna getirin

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
@Macro, çok doğru ve çok güzel bir kod! findInterval()Komutu daha önce görmedim , ancak burada olabildiğince basit bir şekilde kod yazmayı seviyorum çünkü verimlilikten ziyade bir anlama aracı olmasını istiyorum.

1
Bunların iyi cevaplar olduğunu söyledim. Amacım sizi eleştirmek değil, herhangi bir kodu değil, yalnızca tek bir argümanı değiştirerek üçten fazla boyuta kolayca genelleştiren bir yaklaşım sunmaktı. Yazdıklarınızın neden yazdıklarımdan daha şeffaf olduğu net değil ama kesinlikle bunun hakkında tartışmak istemiyorum. Şerefe.
Makro

0

Zaten mükemmel cevaplar verildi, bu yüzden Python'da bunu başarmak isteyenler için işte benim çözümüm:

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)

resim açıklamasını buraya girin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.