web-dev-qa-db-ja.com

ホットコンテンツアルゴリズム/時間減衰のあるスコア

私は、ユーザーが送信したコンテンツのスコアを計算して、リストの上位にある現在人気のある/トレンドのアイテムを表示するためのアルゴリズムと数式を読んで調査していますが、ここでは少し頭がおかしいと認めます。

私が何を求めているのかについていくつかの背景を説明します...ユーザーが私のサイトにオーディオをアップロードします。オーディオにはいくつかのアクションがあります。

  • プレイした
  • ダウンロード済み
  • いいね
  • お気に入り

理想的には、新しいアクティビティがログに記録されるたびにオーディオスコアを更新できるアルゴリズム(再生、ダウンロードなど)が必要です。また、ダウンロードアクションは、ダウンロード以上の価値があり、お気に入り以上の価値があります。のような。

可能であれば、1週間より古いオーディオをリストから大幅に削除して、新しいコンテンツがトレンドになる可能性を高めたいと思います。

見栄えの良いredditsアルゴリズムについて読んだことがありますが、複数の変数を利用するために微調整する方法と、約7日後に古い記事を削除する方法について頭を悩ませています。

私たちが興味を持っているいくつかの記事:

どんな助けでも大歓迎です!

ポール

31
Paul Hinett

古い式をRedditsし、少しドロップオフ

基本的に、Redditの式を使用できます。システムは賛成票のみをサポートしているため、賛成票に重みを付けることができ、次のようになります。

_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

これで十分です。

58
Zeta