热内容算法/得分随时间衰减

Pau*_*ett 30 sorting algorithm ranking

我一直在阅读+研究算法和公式,为我的用户提交的内容计算得分,以显示列表上方的当前热门/趋势项目,但是我承认我在这里有点过头了.

我将介绍一下我在追求的内容......用户将音频上传到我的网站,音频有几个动作:

  • 玩过
  • 下载
  • 喜欢
  • 被收藏

理想情况下,我想一个算法,我可以更新音频新活动被记录一次得分(出场,下载等),也有下载行为的价值超过一打多了,像多了下载和多喜爱一样.

如果可能的话,我希望1周以上的音频从列表中大幅下降,以便为更新的内容提供更多的趋势.

我已经读过看起来很好的reddits算法了,但是我对如何调整它以利用我的多个变量以及在大约7天后丢弃旧文章感到满意.

一些我们感兴趣的文章:

任何帮助表示赞赏!

保罗

Zet*_*eta 60

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
Run Code Online (Sandbox Code Playgroud)

该因素exp(-8*x*x)将为您提供所需的下降:

指数下降

背后的基础知识

你可以使用任何比你的分数上升更快的功能.由于我们log在我们的分数上使用,即使线性函数也可以成倍增加(只要您的分数不会呈指数级增长).

所以你需要的只是一个函数,1只要你不想修改分数就会返回,之后会丢失.上面的例子形成了这个功能:

multiplier(x) = x > 1 ? exp(-8*x*x) : 1
Run Code Online (Sandbox Code Playgroud)

如果您想要较少的陡峭曲线,可以改变乘数. 变化的乘数

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;
}
Run Code Online (Sandbox Code Playgroud)

结果:

衰变

这应该足够你了.

  • 回答可能有点迟的@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 (3认同)
  • 感谢您花时间清楚地解释这一点......今晚会用我的数据测试一下. (2认同)