Tạo các biến ngẫu nhiên từ hỗn hợp các bản phân phối bình thường


20

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ừ:

0,3×N(0,1)+0,5×N(10,1)+0,2×N(3,.1)

Làm thế nào tôi có thể làm điều đó?


3
Tôi thực sự không thích cách biểu thị hỗn hợp này. Tôi biết nó thường được thực hiện như thế này nhưng tôi thấy nó sai lệch. Ký hiệu cho thấy rằng để lấy mẫu, bạn cần lấy mẫu cả ba quy tắc và cân nhắc kết quả theo các hệ số đó rõ ràng là không chính xác. Bất cứ ai biết một ký hiệu tốt hơn?
StijnDeVuyst

Tôi không bao giờ có ấn tượng đó. Tôi nghĩ về các phân phối (trong trường hợp này là ba phân phối bình thường) là các hàm và sau đó kết quả là một hàm khác.
roundsapes

@StijnDeVuyst bạn có thể muốn truy cập câu hỏi này bắt nguồn từ nhận xét của bạn: stats.stackexchange.com/questions/431171/ phỏng
ankii

@ankii: cảm ơn vì đã chỉ ra điều đó!
StijnDeVuyst

Câu trả lời:


32

Đó là thực hành tốt để tránh forcác vòng lặp Rvì lý do hiệu suất. Một giải pháp thay thế khai thác thực tế rnormlà 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])

3
Ngoài ra, bạn có thể sử dụng các thuộc tính của phân phối bình thường để thay thế dòng cuối cùng bằng cách samples <- rnorm(N)*sds[components]+mus[components]. Tôi thấy dễ đọc hơn :)
Elvis

Rất thanh lịch (cc @Elvis)!
Itamar

18

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 Bạn~Đồng phục(0,1)

Bạn[Σtôi= =1kpk,Σtôi= =1k+1pk+1)pkkthkth

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 Rmã 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:

nhập mô tả hình ảnh ở đây

và như một kiểm tra vệ sinh:

nhập mô tả hình ảnh ở đây


Chào! Cám ơn rất nhiều! Câu trả lời này đã giúp tôi rất nhiều. Tôi đang sử dụng điều này trong một dự án nghiên cứu. Tôi muốn trích dẫn một tài liệu tham khảo cho ở trên. Bạn có thể vui lòng đề nghị một trích dẫn bài viết nghiên cứu.
Abhishek Bhatia

7

Về mặt khái niệm, bạn chỉ chọn một bản phân phối (từ 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))

nhập mô tả hình ảnh ở đây


Câu trả lời hay, bạn đánh tôi để đăng: P

1
Cảm ơn vì tiền boa, @BabakP. Tôi không chắc nó là cái gì Đó là một cái gì đó trong 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.
gung - Phục hồi Monica

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, mã rất đúng và rất đẹp! Tôi chưa thấy 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ả.

1
Tôi nói đây là những câu trả lời tốt. Mục đích của tôi không phải là chỉ trích bạn mà là đưa ra một cách tiếp cận dễ dàng khái quát hóa hơn ba chiều bằng cách chỉ thay đổi một đối số duy nhất, không phải bất kỳ mã nào. Tôi không rõ tại sao những gì bạn viết lại minh bạch hơn những gì tôi đã viết nhưng tôi chắc chắn không muốn tranh luận về điều đó. Chúc mừng.
Macro

0

Đã đư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)

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.