2013-08-26 34 views
15

IOK vì vậy tôi muốn có thể chọn các giá trị từ phân phối bình thường chỉ rơi từ 0 đến 1. Trong một số trường hợp, tôi muốn có thể chỉ trả lại một phân phối hoàn toàn ngẫu nhiên và trong các trường hợp khác, tôi muốn trả về các giá trị nằm trong hình dạng của một gaussian.Làm thế nào để xác định giới hạn trên và dưới khi sử dụng numpy.random.normal

Hiện nay tôi đang sử dụng các chức năng sau:

def blockedgauss(mu,sigma): 
    while True: 
     numb = random.gauss(mu,sigma) 
     if (numb > 0 and numb < 1): 
      break 
    return numb 

Nó chọn một giá trị từ một phân phối chuẩn, sau đó loại bỏ nó nếu nó nằm ngoài phạm vi 0-1, nhưng tôi cảm thấy như có phải là một cách tốt hơn để làm điều này.

+0

Nếu bạn "khối" giá trị < 0 and > 1, nó vẫn sẽ là một phân bố gaussian? –

+0

nó sẽ không phải là phân phối gaussian, nhưng trong một số trường hợp, tôi không muốn phân phối gaussian. tôi muốn trả lại một bản phân phối có thể điều chỉnh giữa việc phân phối ngẫu nhiên (chọn từ một gaussian rất rộng), đến một cái gì đó rất gần với hàm delta (nơi gaussian trở nên rất hẹp) –

Trả lời

21

Có vẻ như bạn muốn có một truncated normal distribution. Sử dụng scipy, bạn có thể sử dụng scipy.stats.truncnorm để tạo variates ngẫu nhiên từ một phân phối như:

import matplotlib.pyplot as plt 
import scipy.stats as stats 

lower, upper = 3.5, 6 
mu, sigma = 5, 0.7 
X = stats.truncnorm(
    (lower - mu)/sigma, (upper - mu)/sigma, loc=mu, scale=sigma) 
N = stats.norm(loc=mu, scale=sigma) 

fig, ax = plt.subplots(2, sharex=True) 
ax[0].hist(X.rvs(10000), normed=True) 
ax[1].hist(N.rvs(10000), normed=True) 
plt.show() 

enter image description here

Con số trên cho thấy sự phân bố bình thường cắt ngắn, con số thấp hơn cho thấy sự phân bố bình thường với giá trị trung bình cùng mu và độ lệch chuẩn sigma.

+0

thankyou hoàn hảo. –

5

Tôi đã xem qua bài đăng này trong khi tìm kiếm cách trả về một chuỗi giá trị được lấy mẫu từ phân phối bình thường được cắt ngắn giữa 0 và 1 (nghĩa là xác suất). Để giúp bất kỳ ai khác có cùng vấn đề, tôi chỉ muốn lưu ý rằng scipy.stats.truncnorm có khả năng tích hợp ".rvs".

Vì vậy, nếu bạn muốn 100.000 mẫu với trung bình là 0,5 và độ lệch chuẩn là 0,1:

import scipy.stats 
lower = 0 
upper = 1 
mu = 0.5 
sigma = 0.1 
N = 100000 

samples = scipy.stats.truncnorm.rvs(
      (lower-mu)/sigma,(upper-mu)/sigma,loc=mu,scale=sigma,size=N) 

Điều này cho phép một hành vi rất giống với numpy.random.normal, nhưng trong phạm vi mong muốn. Sử dụng tích hợp sẽ nhanh hơn đáng kể so với vòng lặp để thu thập mẫu, đặc biệt là đối với các giá trị lớn của N.

3

Tôi đã thực hiện một kịch bản ví dụ bằng cách sau. Nó cho thấy cách sử dụng các API để thực hiện các chức năng chúng ta muốn, chẳng hạn như tạo các mẫu với các tham số đã biết, cách tính CDF, PDF, v.v. Tôi cũng đính kèm một hình ảnh để hiển thị nó.

#load libraries 
import scipy.stats as stats 

#lower, upper, mu, and sigma are four parameters 
lower, upper = 0.5, 1 
mu, sigma = 0.6, 0.1 

#instantiate an object X using the above four parameters, 
X = stats.truncnorm((lower - mu)/sigma, (upper - mu)/sigma, loc=mu, scale=sigma) 

#generate 1000 sample data 
samples = X.rvs(1000) 

#compute the PDF of the sample data 
pdf_probs = stats.truncnorm.pdf(samples, (lower-mu)/sigma, (upper-mu)/sigma, mu, sigma) 

#compute the CDF of the sample data 
cdf_probs = stas.truncnorm.cdf(samples, (lower-mu)/sigma, (upper-mu)/sigma, mu, sigma) 

#make a histogram for the samples 
plt.hist(samples, bins= 50,normed=True,alpha=0.3,label='histogram'); 

#plot the PDF curves 
plt.plot(samples[samples.argsort()],pdf_probs[samples.argsort()],linewidth=2.3,label='PDF curve') 

#plot CDF curve   
plt.plot(samples[samples.argsort()],cdf_probs[samples.argsort()],linewidth=2.3,label='CDF curve') 


#legend 
plt.legend(loc='best') 

enter image description here

4

Trong trường hợp bất cứ ai muốn có một giải pháp sử dụng NumPy chỉ, đây là một thực hiện đơn giản bằng cách sử dụng chức năng normal và (cách tiếp cận của MacGyver) clip:

import numpy as np 
    def truncated_normal(mean, stddev, minval, maxval): 
     return np.clip(np.random.normal(mean, stddev), minval, maxval) 

EDIT: KHÔNG sử dụng cái này !! đây là cách bạn không nên làm điều đó !! ví dụ,
a = truncated_normal(np.zeros(10000), 1, -10, 10)
thể trông giống như nó hoạt động, nhưng
b = truncated_normal(np.zeros(10000), 100, -1, 1)
sẽ chắc chắn không phải vẽ một cắt ngắn bình thường, như bạn có thể thấy trong biểu đồ sau:

enter image description here

Xin lỗi vì điều đó, hy vọng không ai bị thương!Tôi đoán bài học là, đừng cố gắng bắt chước MacGyver tại mã hóa ... Chúc mừng,
Andres

Các vấn đề liên quan