Algorytm Hot content / score with time decay

Czytałem + badania nad algorytmami i formułami, aby wypracować wynik dla mojej treści przesłanej przez użytkownika, aby wyświetlić aktualnie gorące / trendy pozycje wyżej na liście, jednak przyznam, że jestem trochę ponad moją głową.

Podam trochę informacji o tym, czego szukam... użytkownicy przesyłają dźwięk na moją stronę, audio mają kilka działań:

  • Zagrano
  • Pobrano
  • lubiane
  • ulubione

Idealnie chcę algorytm, w którym mogę zaktualizować wyniki audio za każdym razem, gdy nowa aktywność jest rejestrowana(odtwarzana, pobierana itp...), również akcja pobierania jest warta więcej niż gra, jak więcej niż pobieranie i ulubione więcej niż podobne.

Jeśli to możliwe, chciałbym, aby audio starsze niż 1 tydzień spadały dość gwałtownie z listy, aby dać nowszym treściom większą szansę na trendy.

Czytałem o algorytmie reddits, który wyglądał dobrze, ale jestem ponad moją głową, jak go dostosować, aby wykorzystać moje wiele zmiennych, a do wysyłaj starsze artykuły po około 7 dniach.

Kilka ciekawych artykułów:

Każda pomoc jest doceniana!

Paweł

Author: Paul Hinett, 2012-07-25

1 answers

Reddits old formula and a little drop off

Zasadniczo możesz użyć formuły Reddita. Ponieważ Twój system obsługuje tylko upvoty, możesz je obciążać, co skutkuje czymś takim:

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

Czynnik exp(-8*x*x) da ci upragniony spadek:

Wykładniczy spadek

Podstawy za

Możesz użyć dowolnej funkcji, która osiągnie zero szybciej niż twój wynik wzrośnie. Ponieważ używamy log na naszym wyniku, nawet funkcja liniowa może zostać pomnożona (tak długo, jak wynik nie rośnie wykładniczo).

Więc wszystko, czego potrzebujesz, to funkcja, która zwraca 1 tak długo, jak nie chcesz modyfikować wyniku, a następnie spada. Nasz przykład powyżej tworzy tę funkcję:

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

Możesz zmieniać mnożnik, jeśli chcesz mniej stromych zakrętów. różny mnożnik

Przykład w C++

Powiedzmy, że prawdopodobieństwo zagrania danego utworu w danej godzinie wynosi 50%, pobranie 10%, np. 1% i ulubione 0.1%. Następnie następujący program C++ będzie podaj szacunkowe wyniki:

#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;
}

Wynik:

Rozpad

To powinno Ci wystarczyć.
 52
Author: Zeta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-02 07:04:39