轉:基於用戶投票的排名算法系列

互聯網的出現,意味着"信息大爆炸"。php

用戶擔憂的,再也不是信息太少,而是信息太多。如何從大量信息之中,快速有效地找出最重要的內容,成了互聯網的一大核心問題。html

各類各樣的排名算法,是目前過濾信息的主要手段之一。對信息進行排名,意味着將信息按照重要性依次排列,而且及時進行更新。排列的依據,能夠基於信息自己的特徵,也能夠基於用戶的投票,即讓用戶決定,什麼樣的信息能夠排在第一位。git

下面,我將整理和分析一些基於用戶投票的排名算法,打算分紅六個部分連載,今天是第一篇。程序員

1、Deliciousgithub

最直覺、最簡單的算法,莫過於按照單位時間內用戶的投票數進行排名。得票最多的項目,天然就排在第一位。算法

舊版的Delicious,有一個"熱門書籤排行榜",就是這樣統計出來的。數據庫

它按照"過去60分鐘內被收藏的次數"進行排名。每過60分鐘,就統計一次。編程

這個算法的優勢是比較簡單、容易部署、內容更新至關快;缺點是,一方面,排名變化不夠平滑,前一個小時還排名靠前的內容,每每第二個小時就一落千丈,另外一方面,缺少自動淘汰舊項目的機制,某些熱門內容可能會長期佔據排行榜前列。api

2、Hacker News網絡

Hacker News是一個網絡社區,能夠張貼連接,或者討論某個主題。

每一個帖子前面有一個向上的三角形,若是你以爲這個內容很好,就點擊一下,投上一票。根據得票數,系統自動統計出熱門文章排行榜。可是,並不是得票最多的文章排在第一位,還要考慮時間因素,新文章應該比舊文章更容易獲得好的排名。

Hacker News使用Paul Graham開發的Arc語言編寫,源碼能夠從arclanguage.org下載。它的排名算法是這樣實現的:

將上面的代碼還原爲數學公式:

其中,

  P表示帖子的得票數,減去1是爲了忽略發帖人的投票。

  T表示距離發帖的時間(單位爲小時),加上2是爲了防止最新的帖子致使分母太小(之因此選擇2,多是由於從原始文章出如今其餘網站,到轉貼至Hacker News,平均須要兩個小時)。

  G表示"重力因子"(gravityth power),即將帖子排名往下拉的力量,默認值爲1.8,後文會詳細討論這個值。

從這個公式來看,決定帖子排名有三個因素:

第一個因素是得票數P。

在其餘條件不變的狀況下,得票越多,排名越高。

上圖能夠看到,有三個同時發表的帖子,得票分別爲200票、60票和30票(減1後爲19九、59和29),分別以黃色、紫色和藍色表示。在任一個時間點上,都是黃色曲線在最上方,藍色曲線在最下方。

若是你不想讓"高票帖子"與"低票帖子"的差距過大,能夠在得票數上加一個小於1的指數,好比(P-1)^0.8。

第二個因素是距離發帖的時間T。

在其餘條件不變的狀況下,越是新發表的帖子,排名越高。或者說,一個帖子的排名,會隨着時間不斷降低。

從前一張圖能夠看到,通過24小時以後,全部帖子的得分基本上都小於1,這意味着它們都將跌到排行榜的末尾,保證了排名前列的都將是較新的內容。

第三個因素是重力因子G。

它的數值大小決定了排名隨時間降低的速度。

上圖能夠看到,三根曲線的其餘參數都同樣,G的值分別爲1.五、1.8和2.0。G值越大,曲線越陡峭,排名降低得越快,意味着排行榜的更新速度越快。

知道了算法的構成,就能夠調整參數的值,以適用你本身的應用程序。

[參考文獻]

  * How Hacker News ranking algorithm works

  * How to Build a Popularity Algorithm You can be Proud of

 

基於用戶投票的排名算法(二):Reddit

上一次,我介紹了Hacker News的排名算法。它的特色是用戶只能投同意票,可是不少網站還容許用戶投反對票。就是說,除了好評之外,你還能夠給某篇文章差評。

Reddit是美國最大的網上社區,它的每一個帖子前面都有向上和向下的箭頭,分別表示"同意"和"反對"。用戶點擊進行投票,Reddit根據投票結果,計算出最新的"熱點文章排行榜"。

怎樣才能將同意票和反對票結合起來,計算出一段時間內最受歡迎的文章呢?若是文章A有100張同意票、5張反對票,文章B有1000張同意票、950張反對票,誰應該排在前面呢?

Reddit的程序是開源的,使用Python語言編寫。排名算法的代碼大體以下:

這段代碼考慮了這樣幾個因素:

(1)帖子的新舊程度t

  t = 發貼時間 - 2005年12月8日7:46:43

t的單位爲秒,用unix時間戳計算。不難看出,一旦帖子發表,t就是固定值,不會隨時間改變,並且帖子越新,t值越大。至於2005年12月8日,應該是Reddit成立的時間。

(2)同意票與反對票的差x

  x = 同意票 - 反對票

(3)投票方向y

  

y是一個符號變量,表示對文章的整體見解。若是同意票居多,y就是+1;若是反對票居多,y就是-1;若是同意票和反對票相等,y就是0。

(4)帖子的受確定(否認)的程度z

  

z表示同意票與反對票之間差額的絕對值。若是對某個帖子的評價,越是一邊倒,z就越大。若是同意票等於反對票,z就等於1。

結合以上幾個變量,Reddit的最終得分計算公式以下:

  

這個公式能夠分紅兩個部分來討論:

(一)

  

這個部分表示,同意票與反對票的差額z越大,得分越高。

須要注意的是,這裏用的是以10爲底的對數,意味着z=10能夠獲得1分,z=100能夠獲得2分。也就是說,前10個投票人與後90個投票人(乃至再後面900個投票人)的權重是同樣的,即若是一個帖子特別受到歡迎,那麼越到後面投同意票,對得分越不會產生影響。

當同意票等於反對票,z=1,所以這個部分等於0,也就是不產生得分。

(二)

  

這個部分表示,t越大,得分越高,即新帖子的得分會高於老帖子。它起到自動將老帖子的排名往下拉的做用。

分母的45000秒,等於12.5個小時,也就是說,後一天的帖子會比前一天的帖子多得2分。結合前一部分,能夠獲得結論,若是前一天的帖子在次日還想保持原先的排名,在這一天裏面,它的z值必須增長100倍(淨同意票增長100倍)。

y的做用是產生加分或減分。當同意票超過反對票時,這一部分爲正,起到加分做用;當同意票少於反對票時,這一部分爲負,起到減分做用;當二者相等,這一部分爲0。這就保證了獲得大量淨同意票的文章,會排在前列;同意票與反對票接近或相等的文章,會排在後面;獲得淨反對票的文章,會排在最後(由於得分是負值)。

(三)

這種算法的一個問題是,對於那些有爭議的文章(同意票和反對票很是接近),它們不可能排到前列。假定同一時間有兩個帖子發表,文章A有1張同意票(發帖人投的)、0張反對票,文章B有1000張同意票、1000張反對票,那麼A的排名會高於B,這顯然不合理。

結論就是,Reddit的排名,基本上由發帖時間決定,超級受歡迎的文章會排在最前面,通常性受歡迎的文章、有爭議的文章都不會很靠前。這決定了Reddit是一個符合大衆口味的社區,不是一個很激進、能夠展現少數派想法的地方。

[參考資料]

  * How Reddit ranking algorithms work

基於用戶投票的排名算法(三):Stack 

上一篇文章,我介紹了Reddit的排名算法。

它的特色是,用戶能夠投同意票,也能夠投反對票。也就是說,除了時間因素之外,只要考慮兩個變量就夠了。

可是,還有一些特定用途的網站,必須考慮更多的因素。世界排名第一的程序員問答社區Stack Overflow,就是這樣一個網站。

你在上面提出各類關於編程的問題,等待別人回答。訪問者能夠對你的問題進行投票(同意票或反對票),表示這個問題是否是有價值。

一旦有人回答了你的問題,其餘人也能夠對這個回答投票(同意票或反對票)。

排名算法的做用是,找出某段時間內的熱點問題,即哪些問題最被關注、獲得了最多的討論。

在Stack Overflow的頁面上,每一個問題前面有三個數字,分別表示問題的得分、回答的數目和該問題的瀏覽次數。以這些變量爲基礎,就能夠設計算法了。

創始人之一的Jeff Atwood,曾經在幾年前,公佈過排名得分的計算公式。

寫成php代碼,就是下面這樣:

各個算法變量的含義以下:

(1)Qviews(問題的瀏覽次數)

  

某個問題的瀏覽次數越多,就表明越受關注,得分也就越高。這裏使用了以10爲底的對數,用意是當訪問量愈來愈大,它對得分的影響將不斷變小。

(2)Qscore(問題得分)和Qanswers(回答的數量)

  

首先,Qscore(問題得分)= 同意票-反對票。若是某個問題越受到好評,排名天然應該越靠前。

Qanswers表示回答的數量,表明有多少人蔘與這個問題。這個值越大,得分將成倍放大。這裏須要注意的是,若是無人回答,Qanswers就等於0,這時Qscore再高也沒用,意味着再好的問題,也必須有人回答,不然進不了熱點問題排行榜。

(3)Ascores(回答得分)

  

通常來講,"回答"比"問題"更有意義。這一項的得分越高,就表明回答的質量越高。

可是我感受,簡單加總的設計還不夠全面。這裏有兩個問題。首先,一個正確的回答賽過一百個無用的回答,可是,簡單加總會致使,1個得分爲100的回答與100個得分爲1的回答,總得分相同。其次,因爲得分會出現負值,所以那些特別差的回答,會拉低正確回答的得分。

(4)Qage(距離問題發表的時間)和Qupdated(距離最後一個回答的時間)

  

改寫一下,能夠看得更清楚:

  

Qage和Qupdated的單位都是秒。若是一個問題的存在時間越久,或者距離上一次回答的時間越久,Qage和Qupdated的值就相應增大。

也就是說,隨着時間流逝,這兩個值都會越變越大,致使分母增大,所以總得分會愈來愈小。

(5)總結

Stack Overflow熱點問題的排名,與參與度(Qviews和Qanswers)和質量(Qscore和Ascores)成正比,與時間(Qage和Qupdated)成反比。

基於用戶投票的排名算法(四):牛頓冷卻定律

這個系列的前三篇,介紹了Hacker NewsRedditStack Overflow的排名算法。

今天,討論一個更通常的數學模型。

這個系列的每篇文章,都是能夠分開讀的。可是,爲了保證全部人都在同一頁上,我再說一下,到目前爲止,咱們用不一樣方法,企圖解決的都是同一個問題:根據用戶的投票,決定最近一段時間內的"熱文排名"。

你可能會以爲,這是一個全新的課題,伴隨着互聯網而產生,須要全新的方法來解決。可是,實際上不是。咱們能夠把"熱文排名"想象成一個"天然冷卻"的過程:

  (1)任一時刻,網站中全部的文章,都有一個"當前溫度",溫度最高的文章就排在第一位。

  (2)若是一個用戶對某篇文章投了同意票,該文章的溫度就上升一度。

  (3)隨着時間流逝,全部文章的溫度都逐漸"冷卻"。

  

這樣假設的意義,在於咱們能夠照搬物理學的冷卻定律,使用現成的公式,創建"溫度"與"時間"之間的函數關係,輕鬆構建一個"指數式衰減"(Exponential decay)的過程。

偉大的物理學家牛頓,早在17世紀就提出了溫度冷卻的數學公式,被後人稱做"牛頓冷卻定律"(Newton's Law of Cooling)。咱們就用這個定律構建排名算法。

"牛頓冷卻定律"很是簡單,用一句話就能夠概況:

物體的冷卻速度,與其當前溫度與室溫之間的溫差成正比。

寫成數學公式就是:

  

其中,

  - T(t)是溫度(T)的時間(t)函數。微積分知識告訴咱們,溫度變化(冷卻)的速率就是溫度函數的導數T'(t)。

  - H表明室溫,T(t)-H就是當前溫度與室溫之間的溫差。因爲當前溫度高於室溫,因此這是一個正值。

  - 常數α(α>0)表示室溫與降溫速率之間的比例關係。前面的負號表示降溫。不一樣的物質有不一樣的α值。

這是一個微分方程,爲了計算當前溫度,須要求出T(t)的函數表達式。

第一步,改寫方程,而後等式兩邊取積分。

  

  


第二步,求出這個積分的解(c爲常數項)。

  

  

  

第三步,假定在時刻t0,該物體的溫度是T(t0),簡寫爲T0。代入上面的方程,獲得

  

  

第四步,將上一步的C代入第二步的方程。

  

假定室溫H爲0度,即全部物體最終都會"冷寂",方程就能夠簡化爲

  

上面這個方程,就是咱們想要的最終結果:

  本期溫度 = 上一期溫度 x exp(-(冷卻係數) x 間隔的小時數)

將這個公式用在"排名算法",就至關於(假定本期沒有增長淨同意票)

  本期得分 = 上一期得分 x exp(-(冷卻係數) x 間隔的小時數)

其中,"冷卻係數"是一個你本身決定的值。若是假定一篇新文章的初始分數是100分,24小時以後"冷卻"爲1分,那麼能夠計算獲得"冷卻係數"約等於0.192。若是你想放慢"熱文排名"的更新率,"冷卻係數"就取一個較小的值,不然就取一個較大的值。

[參考文獻]

  * Rank Hotness With Newton's Law of Cooling

基於用戶投票的排名算法(五):威爾遜區間

迄今爲止,這個系列都在討論,如何給出"某個時段"的排名,好比"過去24小時最熱門的文章"。

可是,不少場合須要的是"全部時段"的排名,好比"最受用戶好評的產品"。

這時,時間因素就不須要考慮了。這個系列的最後兩篇,就研究不考慮時間因素的狀況下,如何給出排名。

一種常見的錯誤算法是:

  得分 = 同意票 - 反對票

假定有兩個項目,項目A是60張同意票,40張反對票,項目B是550張同意票,450張反對票。請問,誰應該排在前面?按照上面的公式,B會排在前面,由於它的得分(550 - 450 = 100)高於A(60 - 40 = 20)。可是實際上,B的好評率只有55%(550 / 1000),而A爲60%(60 / 100),因此正確的結果應該是A排在前面。

Urban Dictionary就是這種錯誤算法的實例。

  

另外一種常見的錯誤算法是

  得分 = 同意票 / 總票數

若是"總票數"很大,這種算法實際上是對的。問題出在若是"總票數"不多,這時就會出錯。假定A有2張同意票、0張反對票,B有100張同意票、1張反對票。這種算法會使得A排在B前面。這顯然錯誤。

Amazon就是這種錯誤算法的實例。

  

那麼,正確的算法是什麼呢?

咱們先作以下設定:

  (1)每一個用戶的投票都是獨立事件。

  (2)用戶只有兩個選擇,要麼投同意票,要麼投反對票。

  (3)若是投票總人數爲n,其中同意票爲k,那麼同意票的比例p就等於k/n。

若是你熟悉統計學,可能已經看出來了,這是一種統計分佈,叫作"二項分佈"(binomial distribution)。這很重要,下面立刻要用到。

咱們的思路是,p越大,就表明這個項目的好評比例越高,越應該排在前面。可是,p的可信性,取決於有多少人投票,若是樣本過小,p就不可信。好在咱們已經知道,p是"二項分佈"中某個事件的發生機率,所以咱們能夠計算出p的置信區間。所謂"置信區間",就是說,以某個機率而言,p會落在的那個區間。好比,某個產品的好評率是80%,可是這個值不必定可信。根據統計學,咱們只能說,有95%的把握能夠判定,好評率在75%到85%之間,即置信區間是[75%, 85%]。

這樣一來,排名算法就比較清晰了:

  第一步,計算每一個項目的"好評率"(即同意票的比例)。

  第二步,計算每一個"好評率"的置信區間(以95%的機率)。

  第三步,根據置信區間的下限值,進行排名。這個值越大,排名就越高。

這樣作的原理是,置信區間的寬窄與樣本的數量有關。好比,A有8張同意票,2張反對票;B有80張同意票,20張反對票。這兩個項目的同意票比例都是80%,可是B的置信區間(假定[75%, 85%])會比A的置信區間(假定[70%, 90%])窄得多,所以B的置信區間的下限值(75%)會比A(70%)大,因此B應該排在A前面。

置信區間的實質,就是進行可信度的修正,彌補樣本量太小的影響。若是樣本多,就說明比較可信,不須要很大的修正,因此置信區間會比較窄,下限值會比較大;若是樣本少,就說明不必定可信,必須進行較大的修正,因此置信區間會比較寬,下限值會比較小。

二項分佈的置信區間有多種計算公式,最多見的是"正態區間"(Normal approximation interval),教科書裏幾乎都是這種方法。可是,它只適用於樣本較多的狀況(np > 5 且 n(1 − p) > 5),對於小樣本,它的準確性不好。

1927年,美國數學家 Edwin Bidwell Wilson提出了一個修正公式,被稱爲"威爾遜區間",很好地解決了小樣本的準確性問題。

  

在上面的公式中,表示樣本的"同意票比例",n表示樣本的大小,表示對應某個置信水平的z統計量,這是一個常數,能夠經過查表或統計軟件包獲得。通常狀況下,在95%的置信水平下,z統計量的值爲1.96。

威爾遜置信區間的均值爲

  

它的下限值爲

  

能夠看到,當n的值足夠大時,這個下限值會趨向。若是n很是小(投票人不多),這個下限值會大大小於。實際上,起到了下降"同意票比例"的做用,使得該項目的得分變小、排名降低。

Reddit的評論排名,目前就使用這個算法。

  

[參考文獻]

  * How Not To Sort By Average Rating

基於用戶投票的排名算法(六):貝葉斯平均

上一篇介紹了"威爾遜區間",它解決了投票人數過少、致使結果不可信的問題。

舉例來講,若是隻有2我的投票,"威爾遜區間"的下限值會將同意票的比例大幅拉低。這樣作當然保證了排名的可信性,但也帶來了另外一個問題:排行榜前列老是那些票數最多的項目,新項目或者冷門的項目,很難有出頭機會,排名可能會長期靠後。

IMDB爲例,它是世界最大的電影數據庫,觀衆能夠對每部電影投票,最低爲1分,最高爲10分。

系統根據投票結果,計算出每部電影的平均得分。而後,再根據平均得分,排出最受歡迎的前250名的電影。

這裏就有一個問題:熱門電影與冷門電影的平均得分,是否真的可比?舉例來講,一部好萊塢大片有10000個觀衆投票,一部小成本的文藝片只有100個觀衆投票。這二者的投票結果,怎麼比較?若是使用"威爾遜區間",後者的得分將被大幅拉低,這樣處理是否公平,能不能反映它們真正的質量?

一個合理的思路是,若是要比較兩部電影的好壞,至少應該請一樣多的觀衆觀看和評分。既然文藝片的觀衆人數偏少,那麼應該設法爲它增長一些觀衆。

排名頁面的底部,IMDB給出了它的計算方法。

  

  - WR, 加權得分(weighted rating)。
  - R,該電影的用戶投票的平均得分(Rating)。
  - v,該電影的投票人數(votes)。
  - m,排名前250名的電影的最低投票數(如今爲3000)。
  - C, 全部電影的平均得分(如今爲6.9)。

仔細研究這個公式,你會發現,IMDB爲每部電影增長了3000張選票,而且這些選票的評分都爲6.9。這樣作的緣由是,假設全部電影都至少有3000張選票,那麼就都具有了進入前250名的評選條件;而後假設這3000張選票的評分是全部電影的平均得分(即假設這部電影具備平均水準);最後,用現有的觀衆投票進行修正,長期來看,v/(v+m)這部分的權重將愈來愈大,得分將慢慢接近真實狀況。

這樣作拉近了不一樣電影之間投票人數的差別,使得投票人數較少的電影也有可能排名前列。

把這個公式寫成更通常的形式:

  

  - C,投票人數擴展的規模,是一個自行設定的常數,與整個網站的整體用戶人數有關,能夠等於每一個項目的平均投票數。
  - n,該項目的現有投票人數。
  - x,該項目的每張選票的值。
  - m,整體平均分,即整個網站全部選票的算術平均值。

這種算法被稱爲"貝葉斯平均"(Bayesian average)。由於某種程度上,它借鑑了"貝葉斯推斷"(Bayesian inference)的思想:既然不知道投票結果,那就先估計一個值,而後不斷用新的信息修正,使得它愈來愈接近正確的值。

在這個公式中,m(整體平均分)是"先驗機率",每一次新的投票都是一個調整因子,使整體平均分不斷向該項目的真實投票結果靠近。投票人數越多,該項目的"貝葉斯平均"就越接近算術平均,對排名的影響就越小。

所以,這種方法能夠給一些投票人數較少的項目,以相對公平的排名。

=================================================

"貝葉斯平均"也有缺點,主要問題是它假設用戶的投票是正態分佈。好比,電影A有10個觀衆評分,5個爲五星,5個爲一星;電影B也有10個觀衆評分,都給了三星。這兩部電影的平均得分(不管是算術平均,仍是貝葉斯平均)都是三星,可是電影A可能比電影B更值得看。

解決這個問題的思路是,假定每一個用戶的投票都是獨立事件,每次投票只有n個選項能夠選擇,那麼這就服從"多項分佈"(Multinomial distribution),就能夠結合貝葉斯定理,計算該分佈的指望值。因爲這涉及複雜的統計學知識,這裏就不深刻了,感興趣的朋友能夠繼續閱讀William Morgan的How to rank products based on user input

 

(完)轉載自http://www.ruanyifeng.com/

 

 

參考文獻:

How to Build a Popularity Algorithm You can be Proud of

How Hacker News ranking algorithm works

How Reddit ranking algorithms work

 

 

 

How Not To Sort By Average Rating

 

 

 

 

 

 

 

威爾遜區間下限來排名:

  * How Not To Sort By Average Rating

相關文章
相關標籤/搜索