it-swarm-vi.tech

Chuyển đổi phân phối đồng nhất sang phân phối bình thường

Làm cách nào tôi có thể chuyển đổi phân phối đồng đều (vì 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) thành phân phối bình thường? Điều gì sẽ xảy ra nếu tôi muốn độ lệch chuẩn và trung bình của lựa chọn của mình?

91
Terhorst

Thuật toán Ziggurat khá hiệu quả cho việc này, mặc dù biến đổi Box-Muller dễ thực hiện hơn từ đầu (và không điên chậm).

46
Tyler

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

  • Không không sử dụng Hộp Muller. Đặc biệt nếu bạn vẽ nhiều số gaussian. Box Muller mang lại một kết quả được kẹp giữa -6 và 6 (giả sử độ chính xác gấp đôi. Mọi thứ trở nên 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 vẫn ổn, nhưng cần tra cứu bảng (và một số điều chỉnh dành riêng cho nền tảng do vấn đề kích thước bộ đệm)
  • Tỷ lệ đồng phục là sở thích của tôi, chỉ một vài phép cộng/phép nhân và nhật ký 1/50 của thời gian (ví dụ: nhìn vào đó ).
  • Đảo ngược CDF hiệu quả (và bị bỏ qua, tại sao?), Bạn có triển khai nhanh nó có sẵn nếu bạn tìm kiếm google. Nó là bắt buộc cho các số Quasi-Random.
38
Alexandre C.

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

Nói cách khác, nếu bạn nhắm đến một hàm xác suất cụ thể p(x), bạn có được phân phối bằng cách tích hợp trên nó -> d(x) = integ (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à truyền 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à cách tiếp cận 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ỳ hàm xác suất hoặc phân phối nào bạn có miễn là nó có xấp xỉ 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 cho nhận xét nhỏ về việc sử dụng phân phối và không phải là xác suất.

25
Adi

Đây là một triển khai javascript sử dụng dạng cực của phép 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 */
}
20
user5084

Sử dụng định lý giới hạn trung tâm mục nhập wikipediamục nhập mathworld để lợi thế của bạn.

Tạo n của các số được phân phối đồng đều, cộng chúng, trừ n * 0,5 và bạn có đầu ra của một phân phối bình thường với giá trị trung bình bằng 0 và phương sai bằng (1/12) * (1/sqrt(N)) (xem wikipedia trên các phân phối đồng đều cho số cuối cùng đó) 

n = 10 cung cấp cho bạn một cái gì đó tốt một nửa nhanh chóng. Nếu bạn muốn một cái gì đó tốt hơn một nửa, hãy tìm giải pháp tylers (như đã lưu ý trong mục wikipedia trên các bản phân phối bình thường )

5
jilles de wit

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

Một phép cộng và/hoặc phép nhân đơn giản sẽ thay đổi giá trị trung bình và độ lệch chuẩn cho nhu cầu của bạn.

1
Pepijn Schmitz

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 lưu trữ một giá trị và trả về giá trị khác. Trong cuộc gọi tiếp theo cho một mẫu, bạn trả về giá trị được lưu.
  2. Box-Muller cho điểm Z
    Sau đó, 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 chuẩn.
1
hughdbrown

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

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

Đối với bản thân thuật toán, hãy xem hàm trong Random.py trong thư viện Python.

Nhập thủ công ở đây

1
Brent.Longborough

Trong đó R1, R2 là các số thống nhất ngẫu nhiên:

PHÂN PHỐI BÌNH THƯỜNG, với SD là 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)

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

1
Erik Aronesty

H Làm cách nào tôi có thể chuyển đổi phân phối đồng đều (vì 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) thành phân phối bình thường?

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

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

  3. Bước 2 có thể được chấp nhận để tạo 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 dẫn xuất phân tích mà không gặp vấn đề gì. (ví dụ: exp.distribution)

  4. Để mô hình phân phối bình thường, bạn có thể tính toán y1 * cos (y2), trong đó y1 ~ là đồng nhất 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 chuẩn và trung bình của lựa chọn của mình?

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

Nó có thể được chỉ ra rằng sự dịch chuyển và nhân rộng như vậy dẫn đến N (m, sigma)

0
bruziuz

Đây là một triển khai Matlab sử dụng dạng cực của Box-Muller Transform:

Hàm 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à gọi histfit(randn_box_muller(10000000),100); đây là kết quả:  Box-Muller Matlab Histfit

Rõ ràng là nó thực sự không hiệu quả so với Matlab tích hợp randn .

0
madx

Tôi có đoạn mã sau có thể giúp:

set.seed(123)
n <- 1000
u <- runif(n) #creates U
x <- -log(u)
y <- runif(n, max=u*sqrt((2*exp(1))/pi)) #create Y
z <- ifelse (y < dnorm(x)/2, -x, NA)
z <- ifelse ((y > dnorm(x)/2) & (y < dnorm(x)), x, z)
z <- z[!is.na(z)]
0

Nó cũng dễ sử dụng hàm rnorm () được triển khai hơn vì nó nhanh hơn so với việc viết một trình tạo số ngẫu nhiên cho phân phối bình thường. Xem mã sau đây để chứng minh

n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
0
peterweethetbeter

Tôi nghĩ 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 nên được phân phối bình thường với phương sai trung bình bằng 0 và thống nhất phương sai. "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ị trung bình mong muốn và bằng cách thay đổi "1", bạn sẽ nhận được phương sai bằng với bình phương đầu vào của mình.

Ví dụ: =norminv(Rand();50;3) sẽ mang lại các số được phân phối bình thường với MEAN = 50 VariANCE = 9.

0
Hippo