Làm cách nào tôi có thể lấy mẫu từ phân phối hỗn hợp và đặc biệt là hỗn hợp phân phối Bình thường trong R
? Ví dụ: nếu tôi muốn lấy mẫu từ:
Làm thế nào tôi có thể làm điều đó?
Làm cách nào tôi có thể lấy mẫu từ phân phối hỗn hợp và đặc biệt là hỗn hợp phân phối Bình thường trong R
? Ví dụ: nếu tôi muốn lấy mẫu từ:
Làm thế nào tôi có thể làm điều đó?
Câu trả lời:
Đó là thực hành tốt để tránh for
các vòng lặp R
vì lý do hiệu suất. Một giải pháp thay thế khai thác thực tế rnorm
là véc tơ hóa:
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])
samples <- rnorm(N)*sds[components]+mus[components]
. Tôi thấy dễ đọc hơn :)
Nói chung, một trong những cách dễ nhất để lấy mẫu từ phân phối hỗn hợp là như sau:
Các bước thuật toán
1) Tạo biến ngẫu nhiên
3) Lặp lại các bước 1) và 2) cho đến khi bạn có lượng mẫu mong muốn từ phân phối hỗn hợp
Bây giờ bằng cách sử dụng thuật toán chung được đưa ra ở trên, bạn có thể lấy mẫu từ hỗn hợp quy tắc mẫu của mình bằng cách sử dụng R
mã sau :
#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)
Tạo ra:
và như một kiểm tra vệ sinh:
Về mặt khái niệm, bạn chỉ chọn một bản phân phối (từ 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))
ifelse()
tuyên bố, nhưng tôi sẽ phải tìm ra nó sau. Tôi đã thay thế mã đó với một vòng lặp.
R
findInterval()
cumsum()
mu
s
p
mix <- function(n,mu,s,p) { ii <- findInterval(runif(n),cumsum(p))+1; x <- rnorm(n,mean=mu[ii],sd=sqrt(s[ii])); return(x); }
findInterval()
lệnh trước đây, tuy nhiên, tôi thích viết mã ở đây một cách đơn giản nhất có thể vì tôi muốn nó là một công cụ để hiểu hơn là hiệu quả.
Đã đưa ra câu trả lời hoàn hảo, vì vậy đối với những người muốn đạt được điều này trong Python, đây là giải pháp của tôi:
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)