2012-07-25 116 views
22

我一直在閱讀+研究算法和公式,爲我的用戶提交的內容計算一個分數,以顯示當前熱門/熱門的項目,但是我承認我'這裏有點凌亂。熱門內容算法/得分隨着時間的推移

我給上我後...網友上傳的音頻到我的網站的一些背景,音頻有幾個動作:

  • 玩過
  • 下載
  • 喜歡
  • 收藏

理想情況下,我想要一個算法,我可以在每次記錄新活動(播放,下載等)時更新音頻分數,還有一個下載動作比一個播放更有價值,比下載和喜歡更多。

如果可能的話,我希望超過1周的音頻從列表中非常大幅地下降,讓更新的內容更有可能成爲趨勢。

我已經閱讀了有關reddits算法,看起來不錯,但我在我的頭上如何調整它以利用我的多個變量,並在大約7天后放棄較舊的文章。

一些文章,我們很有趣:

任何幫助表示讚賞!

保羅

+0

那麼問題是什麼? – 2012-07-25 15:47:26

+0

隨着時間衰退的熱點內容?你在談論[熱等式](http://en.wikipedia.org/wiki/Heat_equation)嗎?不管怎麼說,嚴肅地說,你必須自己去思考這個問題 - 儘管熱量方程可以給你一些想法。 – Zeta 2012-07-25 15:50:00

+0

這個問題真的是我正在尋找什麼樣的方程式,我想Zeta回答了這個問題。我在這個級別上的數學和方程不是很熱,我希望有人有過這方面的經驗,並找到一些有用的博客等。 – 2012-07-25 16:26:30

回答

49

Reddits老配方和一個小落客

基本上你可以使用reddit的公式。由於您的系統只支持upvotes你可以進行加權,從而導致這樣的事情:

def hotness(track) 
    s = track.playedCount 
    s = s + 2*track.downloadCount 
    s = s + 3*track.likeCount 
    s = s + 4*track.favCount 
    baseScore = log(max(s,1)) 

    timeDiff = (now - track.uploaded).toWeeks 

    if(timeDiff > 1) 
     x = timeDiff - 1 
     baseScore = baseScore * exp(-8*x*x) 

    return baseScore 

因子exp(-8*x*x)會給你把你想要的下降:

Exponential drop off

基礎知識背後

您可以使用任何比分數增加更快的功能。由於我們對我們的分數使用了log,即使線性函數可以相乘(只要您的分數沒有按指數規律增長)。

所以你只需要一個函數返回1,只要你不想修改分數然後下降。我們上面的例子形成該功能:

multiplier(x) = x > 1 ? exp(-8*x*x) : 1 

如果您想要較不陡的曲線,您可以改變乘數。 varying multiplier

實施例在C++

比方說,對於一個給定的軌道的概率在給定的小時被播放爲50%,10下載%,如1%和最喜愛的0.1%。那麼下面的C++程序會給你一個估計你的分數行爲:

#include <iostream> 
#include <fstream> 
#include <random> 
#include <ctime> 
#include <cmath> 

struct track{ 
    track() : uploadTime(0),playCount(0),downCount(0),likeCount(0),faveCount(0){} 
    std::time_t uploadTime;  
    unsigned int playCount; 
    unsigned int downCount; 
    unsigned int likeCount; 
    unsigned int faveCount;  
    void addPlay(unsigned int n = 1){ playCount += n;} 
    void addDown(unsigned int n = 1){ downCount += n;} 
    void addLike(unsigned int n = 1){ likeCount += n;} 
    void addFave(unsigned int n = 1){ faveCount += n;} 
    unsigned int baseScore(){ 
     return playCount + 
      2 * downCount + 
      3 * likeCount + 
      4 * faveCount; 
    } 
}; 

int main(){ 
    track test; 
    const unsigned int dayLength = 24 * 3600; 
    const unsigned int weekLength = dayLength * 7;  

    std::mt19937 gen(std::time(0)); 
    std::bernoulli_distribution playProb(0.5); 
    std::bernoulli_distribution downProb(0.1); 
    std::bernoulli_distribution likeProb(0.01); 
    std::bernoulli_distribution faveProb(0.001); 

    std::ofstream fakeRecord("fakeRecord.dat"); 
    std::ofstream fakeRecordDecay("fakeRecordDecay.dat"); 
    for(unsigned int i = 0; i < weekLength * 3; i += 3600){ 
     test.addPlay(playProb(gen)); 
     test.addDown(downProb(gen)); 
     test.addLike(likeProb(gen)); 
     test.addFave(faveProb(gen));  

     double baseScore = std::log(std::max<unsigned int>(1,test.baseScore())); 
     double timePoint = static_cast<double>(i)/weekLength;   

     fakeRecord << timePoint << " " << baseScore << std::endl; 
     if(timePoint > 1){ 
      double x = timePoint - 1; 
      fakeRecordDecay << timePoint << " " << (baseScore * std::exp(-8*x*x)) << std::endl; 
     } 
     else 
      fakeRecordDecay << timePoint << " " << baseScore << std::endl; 
    } 
    return 0; 
} 

結果:

Decay

這應該是夠你用的。

+2

謝謝你抽出時間來解釋這個清楚...將測試它晚上與我的數據。 – 2012-07-25 17:34:19

+0

@Zeta你是怎麼想出exp(-8 * x * x)的?我需要將此應用於類似的問題,涉及'created_at'和'updated_at'時間戳,我用'updated_at'進行排序,但是我需要將它與'created_at'區別6小時後丟棄,我不確定如何調整這個公式。 – paulkon 2013-11-28 01:39:00

+3

@paulkon可能有點晚回答...查看Zeta答案中的第一個圖(紅色):這是exp(-8 * x * x)的圖,顯示一次應用於baseScore的下降該賽道已超過一週。 爲了讓你在6小時後下車,你需要做一些像timeDiff =(now - track.created_at).toHours'然後:if timeDiff> 6; x = timeDiff - 6; baseScore * = exp(-8 * x * x)'。調整指數函數中的8:值越高,下降越陡:) 隨着-8:http://fooplot.com/plot/h0nfqukrj8 使用-50:http://fooplot.com/plot/e57bc1osnv – 2014-01-18 11:53:49

相關問題