2008-09-16 51 views
85

Làm cách nào để chuyển đổi phân phối đồng đều (như hầu hết các trình tạo số ngẫu nhiên tạo ra, ví dụ từ 0,0 đến 1,0) thành phân phối bình thường? Điều gì sẽ xảy ra nếu tôi muốn có độ lệch trung bình và tiêu chuẩn mà tôi chọn?Chuyển đổi phân phối đồng đều thành phân phối chuẩn

+3

Bạn có đặc điểm ngôn ngữ hay đây chỉ là câu hỏi về thuật toán chung? –

+2

Câu hỏi thuật toán chung. Tôi không quan tâm ngôn ngữ nào. Nhưng tôi thích rằng câu trả lời không dựa vào chức năng cụ thể mà chỉ có ngôn ngữ đó cung cấp. – Terhorst

Trả lời

44

Ziggurat algorithm là khá hiệu quả cho việc này, mặc dù Box-Muller transform dễ thực hiện hơn từ đầu (và không chậm).

+7

Các cảnh báo thông thường về máy phát điện tuyến tính đồng bộ áp dụng cho cả hai phương pháp này, vì vậy hãy sử dụng máy phát điện thích hợp. Chúc mừng. – dmckee

+3

Chẳng hạn như Mersenee Twister, hoặc bạn có đề xuất nào khác không? –

1

Tôi sẽ sử dụng Box-Muller. Hai điều về điều này:

  1. Bạn kết thúc với hai giá trị mỗi lần lặp
    Thông thường, bạn nhớ cache một giá trị và trả lại khác. Trong lần gọi mẫu tiếp theo, bạn trả về giá trị được lưu trong bộ nhớ cache.
  2. Box-Muller cung cấp số Z-
    Bạn phải chia tỷ lệ Z theo độ lệch chuẩn và thêm giá trị trung bình để có được giá trị đầy đủ trong phân phối bình thường.
+0

Bạn quy mô điểm Z như thế nào? – Terhorst

+2

được chia tỷ lệ = trung bình + stdDev * zScore // cung cấp cho bạn bình thường (có nghĩa là, stdDev^2) – yoyoyoyosef

1

Tiêu chuẩn Python thư viện mô-đun ngẫu nhiên có những gì bạn muốn:

normalvariate (mu, sigma)
phân phối bình thường. mu là trung bình, và sigma là độ lệch chuẩn.

Đối với chính thuật toán, hãy xem hàm trong random.py trong thư viện Python.

Các manual entry is here

+1

Thật không may, thư viện của python sử dụng Kinderman, A.J. và Monahan, J.F., "Tạo ra các biến ngẫu nhiên bằng máy tính bằng cách sử dụng tỷ lệ các deviates thống nhất", Phần mềm Toán ACM, 3, (1977), tr257-260. Điều này sử dụng hai biến ngẫu nhiên đồng nhất để tạo ra giá trị bình thường, chứ không phải là một giá trị đơn, vì vậy không rõ ràng cách sử dụng nó như là ánh xạ mà OP muốn. – Ian

-1
function distRandom(){ 
    do{ 
    x=random(DISTRIBUTION_DOMAIN); 
    }while(random(DISTRIBUTION_RANGE)>=distributionFunction(x)); 
    return x; 
} 
+0

Không được đảm bảo trả lại, phải không? ;-) –

+0

nó trở lại gần như chắc chắn. –

+4

Số ngẫu nhiên quá quan trọng để được để lại cơ hội. –

23

Thay đổi sự phân bố của bất kỳ chức năng khác liên quan đến việc sử dụng nghịch đảo của hàm mà bạn muốn.

Nói cách khác, nếu bạn nhắm đến hàm xác suất cụ thể p (x) bạn nhận phân phối bằng cách tích hợp nó -> d (x) = tích phân (p (x)) và sử dụng nghịch đảo của nó: Inv (d (x)). Bây giờ sử dụng hàm xác suất ngẫu nhiên (có phân phối đồng đều) và đúc giá trị kết quả thông qua hàm Inv (d (x)). Bạn sẽ nhận được các giá trị ngẫu nhiên được phân phối theo phân phối theo chức năng bạn đã chọn.

Đây là phương pháp toán học chung - bằng cách sử dụng nó, bây giờ bạn có thể chọn bất kỳ xác suất hoặc hàm phân phối nào mà bạn có miễn là nó có nghịch đảo hoặc xấp xỉ nghịch đảo tốt.

Hy vọng điều này đã giúp và cảm ơn nhận xét nhỏ về việc sử dụng phân phối chứ không phải chính xác xác suất.

+4

+1 Đây là phương pháp bị bỏ qua để tạo các biến gaussian hoạt động rất tốt. CDF nghịch đảo có thể được tính toán hiệu quả với phương pháp Newton trong trường hợp này (đạo hàm là e^{- t^2}), xấp xỉ ban đầu là dễ dàng để có được như là một phần hợp lý, vì vậy bạn cần 3-4 đánh giá của erf và exp. Nó là bắt buộc nếu bạn sử dụng các số bán ngẫu nhiên, một trường hợp mà bạn phải sử dụng chính xác một số thống nhất để lấy một số gaussian. –

+7

Lưu ý rằng bạn cần đảo ngược hàm phân phối tích lũy, không phải hàm phân phối xác suất. Alexandre ngụ ý điều này, nhưng tôi nghĩ đề cập đến nó rõ ràng hơn có thể không đau - vì câu trả lời dường như gợi ý PDF – ltjax

+0

Bạn có thể sử dụng PDF nếu bạn chuẩn bị chọn ngẫu nhiên một hướng tương đối so với trung bình; Tôi có hiểu điều đó không? –

4

Sử dụng định lý giới hạn trung tâm wikipedia entrymathworld entry cho lợi thế của bạn.

Tạo n của số phân bố đều, tổng hợp, trừ n * 0,5 và bạn có đầu ra của một phân phối xấp xỉ chuẩn với trung bình bằng 0 và phương sai bằng (1/12) * (1/sqrt(N)) (xem wikipedia on uniform distributions cho rằng người cuối cùng)

n = 10 cung cấp cho bạn một cái gì đó một nửa khá nhanh.Nếu bạn muốn một cái gì đó hơn một nửa phong nha đi cho giải pháp tylers (như đã nêu trong wikipedia entry on normal distributions)

+1

Điều này sẽ không đưa ra một kết quả bình thường đặc biệt ("đuôi" hoặc điểm cuối sẽ không gần với phân bố thực bình thường). Box-Muller là tốt hơn, như những người khác đã gợi ý. –

+1

Hộp Muller cũng có đuôi sai (nó trả về một số giữa -6 và 6 với độ chính xác gấp đôi) –

+0

n = 12 (tổng 12 số ngẫu nhiên trong khoảng 0 đến 1 và trừ 6) kết quả trong stddev = 1 và mean = 0 . Điều này sau đó có thể được sử dụng để tạo ra bất kỳ phân phối bình thường nào. Đơn giản chỉ cần nhân kết quả của stddev mong muốn và thêm giá trị trung bình. – JerryM

20

Dưới đây là một triển khai javascript bằng cách sử dụng hình thức cực của chuyển đổi Box-Muller.

/* 
* Returns member of set with a given mean and standard deviation 
* mean: mean 
* standard deviation: std_dev 
*/ 
function createMemberInNormalDistribution(mean,std_dev){ 
    return mean + (gaussRandom()*std_dev); 
} 

/* 
* Returns random number in normal distribution centering on 0. 
* ~95% of numbers returned should fall between -2 and 2 
* ie within two standard deviations 
*/ 
function gaussRandom() { 
    var u = 2*Math.random()-1; 
    var v = 2*Math.random()-1; 
    var r = u*u + v*v; 
    /*if outside interval [0,1] start over*/ 
    if(r == 0 || r >= 1) return gaussRandom(); 

    var c = Math.sqrt(-2*Math.log(r)/r); 
    return u*c; 

    /* todo: optimize this algorithm by caching (v*c) 
    * and returning next time gaussRandom() is called. 
    * left out for simplicity */ 
} 
38

Có rất nhiều phương pháp:

  • Do không sử dụng Box Muller. Đặc biệt là nếu bạn vẽ nhiều số gaussian. Hộp Muller cho kết quả được kẹp giữa -6 và 6 (giả sử độ chính xác gấp đôi. Những điều tồi tệ hơn với phao.). Và nó thực sự kém hiệu quả hơn các phương pháp có sẵn khác.
  • Ziggurat là tốt, nhưng cần tra cứu bảng (và một số chỉnh sửa nền tảng cụ thể do các vấn đề kích thước bộ nhớ cache)
  • Tỷ lệ đồng phục là yêu thích của tôi, chỉ một vài phép cộng/phép nhân và log 1/50 thời gian (ví dụ: look there).
  • Đảo ngược CDF hiệu quả (và bị bỏ qua, tại sao?), Bạn có triển khai nhanh ứng dụng này nếu bạn tìm kiếm trên google. Nó là bắt buộc đối với các số Quasi-Random.
+1

Bạn có chắc chắn về kẹp [-6,6] không? Đây là một điểm khá quan trọng nếu đúng (và xứng đáng với một lưu ý trên trang wikipedia). – redcalx

+1

@locster: đây là những gì một giáo viên của tôi đã nói với tôi (ông đã nghiên cứu những máy phát điện như vậy, và tôi tin tưởng từ của ông). Tôi có thể tìm thấy bạn một tài liệu tham khảo. –

+7

@locster: thuộc tính không mong muốn này cũng được chia sẻ theo phương pháp nghịch đảo CDF. Xem http://www.cimat.mx/~src/prope08/randomgauss.pdf. Điều này có thể được giảm bớt bằng cách sử dụng một RNG thống nhất có xác suất không 0 để mang lại một số dấu phẩy động rất gần bằng không. Hầu hết RNG không, vì chúng tạo ra một số nguyên (thường là 64 bit), sau đó được ánh xạ tới [0,1]. Điều này làm cho những phương pháp này không phù hợp để lấy mẫu đuôi biến gaussian (suy nghĩ về các tùy chọn giá thấp/cao trong tài chính tính toán). –

1

đâu R1, R2 là ngẫu nhiên số thống nhất:

PHÂN PHỐI NORMAL, với SD 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)

Điều này là chính xác ... không cần phải làm tất cả những vòng lặp chậm!

+0

Trước khi ai đó sửa chữa tôi ... đây là xấp xỉ tôi đã đưa ra: (1.5- (R1 + R2 + R3)) * 1.88. Tôi thích nó quá. –

0

Tôi điều bạn nên thử điều này trong EXCEL: =norminv(rand();0;1). Điều này sẽ tạo ra các số ngẫu nhiên cần được phân phối bình thường với giá trị trung bình bằng 0 và phương sai hợp nhất. "0" có thể được cung cấp với bất kỳ giá trị nào, sao cho các số sẽ có giá trị mong muốn và bằng cách thay đổi "1", bạn sẽ nhận được phương sai bằng bình phương của đầu vào của bạn.

Ví dụ: =norminv(rand();50;3) sẽ chịu khuất phục trước những con số có phân phối chuẩn với trung bình = 50 sai = 9.

-3

xấp xỉ:

function rnd_snd() { 
    return (Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1); 
} 

Xem http://www.protonfish.com/random.shtml

+0

Điều này chỉ đơn giản là sai. Tổng các biến ngẫu nhiên đồng nhất chỉ là 1-d [random walk] (http://en.wikipedia.org/wiki/Random_walk) sử dụng phân phối ngẫu nhiên đồng đều. –

0

Q Làm thế nào tôi có thể chuyển đổi một phân bố đều (như hầu hết các trình tạo số ngẫu nhiên tạo ra, ví dụ từ 0,0 đến 1,0) vào một phân bố chuẩn?

  1. Để triển khai phần mềm, tôi biết vài tên máy phát ngẫu nhiên cung cấp cho bạn chuỗi giả ngẫu nhiên thống nhất trong [0,1] (Mersenne Twister, Linear Congruate Generator). Hãy gọi nó là U (x)

  2. Nó tồn tại khu vực toán học gọi là lý thuyết xác suất. Điều đầu tiên: Nếu bạn muốn lập mô hình r.v. với phân bố tích phân F thì bạn có thể thử chỉ để đánh giá F^-1 (U (x)). Trong pr.theory nó đã được chứng minh rằng r.v. sẽ có phân phối không tách rời F.

  3. Bước 2 có thể dễ dàng tạo ra r.v. ~ F mà không sử dụng bất kỳ phương pháp đếm nào khi F^-1 có thể được phân tích mà không gặp vấn đề gì. (ví dụ: exp.phân phối)

  4. Để mô hình phân phối chuẩn, bạn có thể tính toán y1 * cos (y2), trong đó y1 ~ đồng đều trong [0,2pi]. và y2 là phân phối relei.

Q: Điều gì sẽ xảy ra nếu tôi muốn độ lệch trung bình và độ lệch chuẩn?

Bạn có thể tính sigma * N (0,1) + m.

Nó có thể được hiển thị mà chuyển dịch như thế và mở rộng quy mô dẫn đến N (m, sigma)

1

Dường như không thể tin rằng tôi có thể thêm một cái gì đó để này sau tám năm, nhưng đối với trường hợp của Java Tôi muốn chỉ người đọc phương pháp Random.nextGaussian(), tạo ra phân phối Gaussian với giá trị trung bình 0.0 và độ lệch chuẩn 1.0 cho bạn.

Việc bổ sung và/hoặc phép nhân đơn giản sẽ thay đổi độ lệch trung bình và tiêu chuẩn theo nhu cầu của bạn.

0

Đây là một thực hiện Matlab bằng cách sử dụng hình thức cực của Box-Muller chuyển đổi:

Chức năng randn_box_muller.m:

function [values] = randn_box_muller(n, mean, std_dev) 
    if nargin == 1 
     mean = 0; 
     std_dev = 1; 
    end 

    r = gaussRandomN(n); 
    values = r.*std_dev - mean; 
end 

function [values] = gaussRandomN(n) 
    [u, v, r] = gaussRandomNValid(n); 

    c = sqrt(-2*log(r)./r); 
    values = u.*c; 
end 

function [u, v, r] = gaussRandomNValid(n) 
    r = zeros(n, 1); 
    u = zeros(n, 1); 
    v = zeros(n, 1); 

    filter = r==0 | r>=1; 

    % if outside interval [0,1] start over 
    while n ~= 0 
     u(filter) = 2*rand(n, 1)-1; 
     v(filter) = 2*rand(n, 1)-1; 
     r(filter) = u(filter).*u(filter) + v(filter).*v(filter); 

     filter = r==0 | r>=1; 
     n = size(r(filter),1); 
    end 
end 

Và cách gọi histfit(randn_box_muller(10000000),100); đây là kết quả: Box-Muller Matlab Histfit

Rõ ràng nó thực sự là không hiệu quả so với Matlab được xây dựng trong randn.

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