Як я можу взяти вибірку з розподілу суміші, зокрема суміші звичайних розподілів R
? Наприклад, якщо я хотів зробити вибірку з:
як я міг це зробити?
Як я можу взяти вибірку з розподілу суміші, зокрема суміші звичайних розподілів R
? Наприклад, якщо я хотів зробити вибірку з:
як я міг це зробити?
Відповіді:
Доцільно уникати 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])
samples <- rnorm(N)*sds[components]+mus[components]
. Мені легше читати :)
Загалом, одним із найпростіших способів вибірки з розподілу суміші є наступний:
Кроки алгоритму
1) Створити випадкову змінну
2) Якщо інтервал, де p k відповідає ймовірності k t h компонента моделі суміші, то генеруємо з розподіл k t 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)
Що породжує:
і як перевірка здорового стану:
Концептуально ви вибираєте лише один розподіл (від можливості) з деякою ймовірністю, а потім генерувати псевдовипадкові змінні з цього розподілу. В 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()
заяві, але мені доведеться це з'ясувати пізніше. Я замінив цей код без циклу.
R
фокус програмування: ви також можете використовувати findInterval()
іcumsum()
команди команди для спрощення коду і, що ще важливіше, полегшити узагальнення до різної кількості вимірів. Наприклад, для вхідного вектора засобів( mu
) та дисперсії( s
) та ймовірності суміші ( p
), простою функцією для генерування n зразків з цієї суміші буде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()
команди, однак мені подобається писати код настільки спрощено, наскільки я можу, бо хочу, щоб це був інструмент для розуміння, а не ефективності.
Вже дано ідеальні відповіді, тому для тих, хто хоче досягти цього в Python, ось моє рішення:
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)