Làm thế nào để nhanh chóng lấy mẫu X nếu exp (X) ~ Gamma?


12

Tôi có một vấn đề lấy mẫu đơn giản, trong đó vòng lặp bên trong của tôi trông như sau:

v = sample_gamma(k, a)

trong đó sample_gammacác mẫu từ phân phối Gamma để tạo thành mẫu Dirichlet.

Nó hoạt động tốt, nhưng đối với một số giá trị của k / a, một số tính toán xuôi dòng.

Tôi đã điều chỉnh nó để sử dụng các biến không gian nhật ký:

v = log(sample_gamma(k, a))

Sau khi điều chỉnh tất cả các phần còn lại của chương trình, nó hoạt động chính xác (ít nhất là nó cho tôi kết quả chính xác tương tự trên các trường hợp thử nghiệm). Tuy nhiên, nó chậm hơn trước.

Có cách nào để lấy mẫu trực tiếp mà không sử dụng các hàm chậm như không? Tôi đã thử googling cho điều này, nhưng tôi thậm chí không biết bản phân phối này có tên chung không (log-gamma?).log ( )X,exp(X)Gammalog()


Tất cả bạn cần làm là chia mỗi biến thể gamma cho tổng của chúng. Làm thế nào, sau đó, dòng chảy xảy ra? Và làm thế nào để lấy logarit giải quyết vấn đề này (bạn không thể tính tổng mà không tính lại số mũ một lần nữa)?
whuber

@whuber Trong không gian nhật ký, bạn tính tổng và sau đó trừ nó khỏi từng phần tử. Vì vậy, điều này tránh được điểm đầu tiên của dòng chảy. Có một chút xử lý khi các dirichlets này đóng vai trò là thành phần hỗn hợp và được nhân với số lượng nhỏ một lần nữa.
luispedro

Thêm nhật ký là không chính xác về mặt toán học: nó tương ứng với việc nhân các gamma hơn là thêm chúng. Có, bạn có thể nhận được kết quả làm việc, nhưng họ chắc chắn sẽ không có phân phối Dirichlet! Một lần nữa, chính xác bản chất của dòng chảy ban đầu là gì và bạn đang làm gì khi tính toán? Các giá trị thực tế bạn đang làm việc với là gì?
whuber

@whuber Tôi có thể đã đơn giản hóa một chút quá nhiều trong mô tả của tôi. Tôi không quên tôi {t = gamma (a, b); tổng + = t; d [i] = log (t)}; logum = log (tổng); forall i {d [i] - = logum; }. Trước đây, điều này tràn vào nếu a rất nhỏ.
luispedro

Đã nhận nó: cho gần 0 bạn sẽ gặp rắc rối không có vấn đề gì. Vấn đề thú vị! α
whuber

Câu trả lời:


9

Hãy xem xét một tham số hình dạng nhỏ gần 0, chẳng hạn như α = 1 / 100 . Trong phạm vi giữa 0 và α , e - α là khoảng 1 , vì vậy pdf Gamma là khoảng x α - 1 d x / Γ ( α ) . Điều này có thể được tích hợp vào một CDF gần đúng, F α ( x ) = x ααα=1/100αe-α1xα-1dx/Γ(α) . Đảo ngược nó, chúng ta thấy mộtsức mạnh1/α: một số mũ rất lớn. Đối vớiα=1/100điều này gây ra một số cơ hội underflow (một giá trị chính xác kép ít hơn10-300, nhiều hơn hoặc ít hơn). Dưới đây là một âm mưu của khả năng mắc underflow là một hàm của logarit cơ số mườiα:Fα(x)=xααΓ(α)1/αα=1/10010300α

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

Một giải pháp là khai thác xấp xỉ này để tạo ra các biến thiên log (Gamma): thực tế, hãy thử tạo một biến thể Gamma và nếu nó quá nhỏ, hãy tạo logarit của nó từ phân phối công suất gần đúng này (như được hiển thị bên dưới). (Làm điều này nhiều lần cho đến khi nhật ký nằm trong phạm vi dòng chảy, sao cho nó là sự thay thế hợp lệ cho phương sai dòng chảy ban đầu.) Đối với phép tính Dirichlet, hãy trừ tối đa tất cả các logarit từ mỗi giá trị nhật ký: điều này hoàn toàn loại bỏ tất cả Gamma thay đổi để nó không ảnh hưởng đến các giá trị Dirichlet. Hãy coi bất kỳ nhật ký kết quả nào quá nhỏ (giả sử, nhỏ hơn -100) là nhật ký của số 0 thực. Lũy thừa các bản ghi khác. Bây giờ bạn có thể tiến hành mà không có dòng chảy.

Điều này sẽ mất nhiều thời gian hơn trước đây, nhưng ít nhất nó sẽ hoạt động!

Để tạo một nhật ký gần đúng Gamma biến thiên với tham số hình dạng , hãy tính trước C = log ( Γ ( α ) ) + log ( α ) . Điều này là dễ dàng, bởi vì có các thuật toán để tính toán trực tiếp các giá trị của nhật ký Gamma . Tạo một số float ngẫu nhiên đồng nhất trong khoảng từ 0 đến 1, lấy logarit của nó, chia cho α và thêm C vào nó.αC= =đăng nhập(Γ(α))+đăng nhập(α)αC

Bởi vì tham số tỷ lệ chỉ đơn thuần là thay đổi phương sai, nên không có vấn đề gì trong việc cung cấp nó trong các quy trình này. Bạn thậm chí không cần nó nếu tất cả các tham số tỷ lệ là như nhau.

Biên tập

Trong một câu trả lời khác, OP mô tả một phương thức trong đó công suất của một phương sai đồng nhất (một phương sai B ( α ) ) được nhân với một phương sai Γ ( α + 1 ) . Công trình này vì pdf của sự phân bố chung của hai variates bình đẳng ( α x α - 1 ) ( y α e - y d y / Γ ( α + 1 ) ) . Để tìm pdf của z = x y1/αB(α)Γ(α+1)(αxα1)(yαeydy/Γ(α+1))z=xychúng ta thay thế , chia cho Jacobean x và tích hợp x . Phạm vi bắt buộc không thể thiếu từ z đến 0 y 1 , từ đâuyz/xxxz0y1

pdf(z)=αΓ(α+1)z(xα/x)ex(z/x)α1dxdz=1Γ(α)zα1ezdz,

đó là pdf của một phân phối.Γ(α)

Toàn bộ vấn đề là khi , giá trị rút ra từ Γ ( α + 1 ) không có khả năng underflow và bằng cách tổng hợp bản ghi của nó và 1 / α lần so với nhật ký của một variate thống nhất độc lập, chúng tôi sẽ có các bản ghi của một Γ ( α ) variate. Nhật ký có khả năng rất tiêu cực, nhưng chúng ta sẽ bỏ qua việc xây dựng các antimon của nó, nó sẽ trải qua một biểu diễn dấu phẩy động.0<α<1Γ(α+1)1/αΓ(α)


1
Chỉ cần một đối số để làm cho chỉnh sửa của bạn thanh lịch hơn một chút, bạn không thực sự cần phải thu hút sự tích hợp ở đây. Chỉ cần sử dụng thực tế là , cộng với đóΓ(α)+Γ(1)~Γ(α+1). Đây là cả hai thuộc tính tiêu chuẩn của bản phân phối beta và gamma. Ngoài ra, khialpha0chúng ta có khoảngy~expo(1)Γ(α)Γ(α)+Γ(1)Beta(α,1)Γ(α)+Γ(1)Γ(α+1)α0yexpo(1), có thể nhanh hơn để mô phỏng ( ) so với biến ngẫu nhiên Γ ( α + 1 ) chung . log(u)Γ(α+1)
xác suất

7

Tôi đang trả lời câu hỏi của riêng mình, nhưng tôi đã tìm thấy một giải pháp khá tốt, ngay cả khi tôi không hiểu hết về nó. Nhìn vào mã từ Thư viện Khoa học GNU, đây là cách nó lấy mẫu các biến gamma ( rlà trình tạo số ngẫu nhiên, a và là β ):αbβ

  if (a < 1)
    {
      double u = gsl_rng_uniform_pos (r);
      return gsl_ran_gamma (r, 1.0 + a, b) * pow (u, 1.0 / a);
   }

gsl_ran_gammalà hàm trả về một mẫu ngẫu nhiên gamma (vì vậy, ở trên là một cuộc gọi đệ quy), trong khi gsl_rng_uniform_postrả về một số được phân phối đồng đều trong ( được bảo đảm hoàn toàn tích cực vì nó được đảm bảo không trả về 0,0).(0,1)_pos

Do đó, tôi có thể lấy nhật ký của biểu thức cuối cùng và sử dụng

return log(gsl_ran_gamma(r, 1.0 + a, b)) + log(u)/a;

Để có được những gì tôi muốn. Bây giờ tôi có hai log()cuộc gọi (nhưng một cuộc gọi ít hơn pow()), nhưng kết quả có lẽ tốt hơn. Trước đây, như whuber đã chỉ ra, tôi đã có thứ gì đó được nâng lên thành sức mạnh , có khả năng là một con số khổng lồ. Bây giờ, trong logspace, tôi nhân với 1 / a . Vì vậy, nó ít có khả năng tràn vào.1/a1/a


Bạn có thể giải thích gsl_rng_uniform_pose và gsl_ran_gamma làm gì không? Tôi đoán người đầu tiên trả về giá trị ngẫu nhiên thống nhất trong khoảng từ 0 đến r và lần thứ hai có liên quan đến giá trị Gamma (1 + a, b) - có thể đó là một Gamma không hoàn chỉnh? Nhìn chung, điều này có vẻ rất gần với xấp xỉ mà tôi đã đề xuất (ngoại trừ, khi xem xét nó, rõ ràng tôi đã quên chỉ định cách chia cho phần , điều này rất cần thiết!)α
whuber

Tôi chỉnh sửa câu trả lời của tôi để bao gồm chi tiết hơn bây giờ.
luispedro

Cảm ơn bạn: nhưng "r" là gì? (Lưu ý rằng đệ quy bị giới hạn: nhiều nhất một cuộc gọi đệ quy sẽ được thực hiện, bởi vì a> 0 ngụ ý 1.0 + a> 1.)
whuber

r là trình tạo số ngẫu nhiên (nơi bạn nhận được các số ngẫu nhiên từ đó).
luispedro

Γ(α+1)B(α,1)Γ(α)
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.