Ответ 1
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)
даст вам желаемое снижение:
Основы позади
Вы можете использовать любую функцию, которая обнуляется быстрее, чем увеличивается ваш счет. Так как мы используем log
на нашем счете, даже линейная функция может быть умножена (до тех пор, пока ваш счет не будет расти в геометрической прогрессии).
Таким образом, все, что вам нужно, это функция, которая возвращает 1
если вы не хотите изменять счет, и затем падает. Наш пример выше формирует эту функцию:
multiplier(x) = x > 1 ? exp(-8*x*x) : 1
Вы можете изменить множитель, если вы хотите менее крутые кривые.
Пример в 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;
}
Результат:
Это должно быть достаточно для вас.