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:
- http://amix.dk/blog/post/19588 (reddits algo)
- http://www.evanmiller.org/rank-hotness-with-newtons-law-of-cooling.html
Każda pomoc jest doceniana!
Paweł
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:
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.
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:
To powinno Ci wystarczyć.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