Подтвердить что ты не робот

Алгоритм горячего контента/оценка с расходом времени

Я читал + изучал алгоритмы и формулы, чтобы рассчитать баллы для контента, представленного моим пользователем, чтобы отображать горячие/трендовые элементы выше по списку, однако я признаю, что здесь я немного над головой.

Я расскажу немного о том, что мне нужно... пользователи загружают аудио на мой сайт, у аудио есть несколько действий:

  • Сыграл
  • загруженный
  • Понравилось
  • Избранные

В идеале мне нужен алгоритм, в котором я мог бы обновлять партитуры каждый раз, когда регистрируется новое действие (воспроизведено, загружено и т.д.), Также действие загрузки стоит больше, чем игра, например, больше, чем загрузка, а избранное больше, чем как

Если возможно, я бы хотел, чтобы аудиозаписи старше 1 недели довольно резко уходили из списка, чтобы дать более новому контенту больше шансов на изменение тенденций.

Я читал об алгоритме reddits, который выглядел неплохо, но я думаю о том, как его настроить, чтобы использовать мои множественные переменные и отбросить старые статьи примерно через 7 дней.

Некоторые статьи, которые нам интересны:

Любая помощь приветствуется!

Павел

4b9b3361

Ответ 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) даст вам желаемое снижение:

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

Это должно быть достаточно для вас.