2012-02-24 28 views
5

我有一臺高斯隨機分佈假設250個網址:在PostgreSQL

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

這些URL對應每一個網站。每個網站都有不同的受歡迎程度。比方說,在id=125(一箇中心高斯)是最流行的,那些在id=1id=250是最流行的。

我要填充像下面這樣一個與在「URL」表中提供的那些中的URL的值的「日誌」表,但考慮到不同的URL可能會更頻繁地出現。(對於爲例URL,其ID是125將是最受歡迎的)。

create table log (
    id serial, 
    url_id integer 
) 

我想避免使用random(),因爲它是統一的,不是很「真實」。

怎麼可以這樣PostgreSQL的實現?

+2

爲什麼你認爲知名度和排名有高斯分佈的? – wildplasser 2012-02-24 13:59:20

+2

可以計算使用利用RAND該分佈的PDF任何分佈(其產生在0和1之間的值,是嗎?)。對於高斯發行版,這將是1/2(1 + erf(x-mu)/ sqrt(2sigma^2)) - 見http://en.wikipedia.org/wiki/Normal_distribution – 2012-02-24 14:05:46

+0

@wildplasser:因爲該法似乎對我嘗試建模的東西非常有用。我承認它可能是其他的! – SCO 2012-02-24 15:18:22

回答

6

12個均勻分佈在範圍[0之和,1)是一個良好的近似高斯分佈在範圍[0,12)爲界。這可以通過乘以一個常數然後加/減一個常數來容易地重新縮放。

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

我接受這一點,因爲我發現它最簡單,最優雅的方式,無論使用何種語言。感謝所有其他貢獻者。 – SCO 2014-08-21 12:47:33

1

簡單的事實是,你想創建自己的功能,在那些能提供高斯分佈或隱或顯式包裝蘭特()。

我沒有統計後臺來告訴你如何改造均勻分佈到高斯的,但你必須寫一個轉換器。截至http://www.perlmonks.org/?node_id=26889提供喜歡的東西(如果你不喜歡的Perl你很可能在改寫這個PL/pgSQL裏,甚至普通的SQL)。

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

我正在尋找一種方法來根據高斯分佈生成數字,並首先找到這篇文章。這就是爲什麼我分享我所發現的只是後:

,有至少從PostgreSQL的8.4,額外的模塊調用tablefunc(http://www.postgresql.org/docs/9.2/static/tablefunc.html)。

它提出了一個函數normal_rand(N,平均值,STDDEV)生成使用高斯分佈N的僞隨機數(因此該函數返回的一組值,通常在所使用的FROM子句)。但是,如果將n設置爲1,則可以將其用作返回值而不是一組值的函數。

考慮含有10條記錄的表NB10,以下兩個查詢返回的一組10的僞隨機數的下列標準高斯分佈(平均值= 0,STDDEV = 1)

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

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

我希望這將有助於在未來的人...... :-)

具體回答你的問題,你可以使用類似:

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

不幸的是,有可能在使用此查詢範圍[0,249]不能獲得一個答案。例如,您可以:

  • 使用遞歸查詢,我覺得這有點大材小用,對於不在範圍[0,249]丟棄值,或
  • 做你的選擇進入一個循環到你的主機語言,接受的值僅當其在範圍[0,249],或
  • 使用模運算符保持在[0,250範圍內,我認爲這是最好的解決辦法,儘管它稍微alterates高斯曲線。這裏是最終的查詢我建議你使用(模/ + /模數的招數是因爲-x模y隨XA正數給出了PostgreSQL中負數,這是不是一件壞事:P):

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

tablefunc模塊提供具有正態分佈的隨機函數。如果它使用安裝,你可以測試:

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

上述查詢應該產生一個正態分佈

如果你沒有它安裝在一個單一的值,試試這個:

CREATE EXTENSION "tablefunc"; 

否則,您將需要登錄爲a super user and install the module

+0

哦,這是非常有趣的歡迎,並會立即打開眼界轉動例如表。非常感謝你 ! – SCO 2017-11-26 16:33:10