2012-02-24 60 views
5

Tôi có một bảng giả sử 250 URL:phân phối ngẫu nhiên Gaussian trong PostgreSQL

create table url (
    id serial, 
    url varchar(64) 
) 

Các URL tương ứng với từng đến một trang web. Mỗi trang web có mức độ phổ biến khác nhau. Giả sử rằng id=125 (cái được đặt chính giữa gaussian) là phổ biến nhất, những cái ở số id=1 hoặc id=250 là ít phổ biến nhất.

Tôi muốn điền bảng "nhật ký" như bảng dưới đây với giá trị url trong bảng "url", nhưng có tính đến các URL khác nhau có thể xuất hiện thường xuyên hơn (với url exemple có id 125 sẽ là phổ biến nhất).

create table log (
    id serial, 
    url_id integer 
) 

Tôi muốn tránh sử dụng random() vì nó là đồng nhất và không phải là "thực".

Làm cách nào để đạt được điều này với Postgresql?

+2

Tại sao bạn cho rằng mức độ phổ biến hoặc xếp hạng có phân phối Gaussion? – wildplasser

+2

Bạn có thể tính toán bất kỳ phân phối nào bằng cách sử dụng tệp PDF của phân phối đó bằng cách sử dụng RAND (tạo giá trị giữa 0 và 1, phải không?). Đối với distro gaussian, đó sẽ là 1/2 (1 + erf (x-mu)/sqrt (2sigma^2)) - xem http://en.wikipedia.org/wiki/Normal_distribution –

+0

@ wildplasser: vì luật đó có vẻ khá tốt cho những gì tôi cố gắng để mô hình. Tôi thừa nhận nó có thể đã được bất kỳ khác! – SCO

Trả lời

6

Tổng của 12 bản phân phối đồng nhất trên phạm vi [0, 1) là một xấp xỉ tốt đối với phân bố Gaussian được bao quanh trong phạm vi [0, 12). Điều này sau đó có thể dễ dàng được tái tỷ lệ bằng cách nhân với một hằng số và sau đó cộng/trừ một hằng số.

select 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random() + 
    random(); 

http://books.google.com/books?id=EKA-yeX2GVgC&pg=PA185&lpg=PA185&dq=%22sum+of+12+uniform+random+variables%22&source=bl&ots=YfwwE0fBB3&sig=HX9J9Oe6x316kVL8uamDU_GOsn4&hl=en&sa=X&ei=bJLZUur1GozaqwGHm4DQDQ&ved=0CEUQ6AEwAw#v=onepage&q=%22sum%20of%2012%20uniform%20random%20variables%22&f=false

+0

Tôi chấp nhận điều này vì tôi thấy nó là cách dễ nhất và thanh lịch nhất, bất kể ngôn ngữ nào được sử dụng. Cảm ơn tất cả những người đóng góp khác. – SCO

1

Thực tế đơn giản là bạn muốn tạo hàm của riêng bạn, bao bọc rand() trong một cái gì đó cung cấp phân phối gaussian ngầm hoặc rõ ràng.

Tôi không có nền thống kê để cho bạn biết cách chuyển đổi phân phối đồng đều thành một phân phối gaussian, nhưng bạn phải viết trình chuyển đổi. Một cái gì đó như được cung cấp tại http://www.perlmonks.org/?node_id=26889 (nếu bạn không thích Perl bạn có thể có thể viết lại điều này trong pl/pgsql hoặc thậm chí SQL đơn giản).

CREATE OR REPLACE FUNCTION gaussian_rand() RETURNS numeric LANGUAGE PLPERL VOLATILE AS 
$$ 
    my ($u1, $u2); # uniformly distributed random numbers 
    my $w;   # variance, then a weight 
    my ($g1, $g2); # gaussian-distributed numbers 

    do { 
     $u1 = 2 * rand() - 1; 
     $u2 = 2 * rand() - 1; 
     $w = $u1*$u1 + $u2*$u2; 
    } while ($w >= 1); 

    $w = sqrt((-2 * log($w))/$w); 
    $g2 = $u1 * $w; 
    $g1 = $u2 * $w; 
    # return both if wanted, else just one 
    return $g1; 

$$; 
7

Tôi đang tìm cách tạo số theo phân phối gaussian và lần đầu tiên tìm thấy bài đăng này. Đây là lý do tôi chia sẻ những gì tôi đã tìm thấy ngay sau:

Có, vì ít nhất PostGreSQL 8.4, một mô-đun bổ sung được gọi là tablefunc (http://www.postgresql.org/docs/9.2/static/tablefunc.html).

Nó đề xuất một hàm normal_rand (n, mean, stddev) tạo ra các số giả ngẫu nhiên bằng cách sử dụng phân phối gaussian (do đó hàm này trả về một tập các giá trị, thường được sử dụng trong mệnh đề FROM). Tuy nhiên, nếu bạn đặt n là 1, nó có thể được sử dụng như một hàm trả về một giá trị chứ không phải một tập hợp các giá trị.

Xét một nb10 bảng chứa 10 hồ sơ, hai truy vấn sau đây trả về một tập hợp của 10 số giả ngẫu nhiên sau một phân bố gaussian chuẩn (trung bình = 0, stddev = 1)

SELECT normal_rand(1, 0, 1) FROM nb10; 

SELECT * from normal_rand(10, 0, 1); 

tôi hy vọng điều này có thể giúp bất cứ ai trong tương lai ... :-)

Để trả lời câu hỏi của bạn đặc biệt, bạn có thể sử dụng một cái gì đó như:

SELECT floor(random_rand(1, 0, 1) * 250 + 125); 

Thật không may, có thể nhận được câu trả lời không nằm trong khoảng [0, 249] khi sử dụng truy vấn này.Bạn có thể ví dụ:

  • sử dụng một truy vấn đệ quy, mà tôi tìm thấy một overkill bit, cho loại bỏ giá trị không nằm trong khoảng [0, 249], hoặc
  • làm chọn của bạn thành một vòng sang ngôn ngữ máy chủ của bạn , chỉ chấp nhận giá trị nếu trong phạm vi [0, 249] hoặc
  • sử dụng toán tử modulo để duy trì trong khoảng [0, 250 [, tôi nghĩ đây là giải pháp tốt nhất, mặc dù nó thay đổi một chút gaussian đường cong. Đây là truy vấn cuối cùng tôi đề nghị bạn sử dụng (thủ thuật modulo/+/modulo là vì -x modulo y với số dương xa cho số âm trong PostGreSQL, không phải là điều xấu: p):

    SELECT ((floor(normal_rand(1,0,1)*250 + 125)::int % 250) + 250) % 250 as v; 
    
1

Module tablefunc cung cấp một hàm ngẫu nhiên với phân phối chuẩn. Bạn có thể kiểm tra nếu nó được cài đặt sử dụng:

SELECT normal_rand(1, 0, 1); -- generates 1 single value with mean 0 and a standard deviation of 1 

Các truy vấn trên sẽ tạo ra một giá trị duy nhất trong một phân phối chuẩn

Nếu bạn không có nó được cài đặt, hãy thử này:

CREATE EXTENSION "tablefunc"; 

Nếu không, bạn sẽ cần phải đăng nhập với tên a super user and install the module.

+0

Ồ, điều này cực kỳ thú vị, và giờ đây mở ra chân trời cho các bảng tổng hợp. Cảm ơn nhiều ! – SCO

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