Решение и реализация алгоритма трендов в Джанго

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

У меня есть две модели, Book а также Reader, Каждую ночь новые книги добавляются в мою базу данных. Количество читателей для каждой книги также обновляется каждую ночь, т. Е. Одна книга будет иметь несколько статистических записей читателей (по одной записи на каждый день).

За определенный период (прошедшая неделя, прошедший месяц или прошедший год) я хотел бы перечислить наиболее популярные книги, какой алгоритм мне использовать для этого?

Популярность не должна быть в реальном времени, потому что количество читателей для каждой книги обновляется только ежедневно.

Я нашел одну статью, на которую ссылалась другая публикация SO, в которой было показано, как они рассчитывали трендовые статьи Википедии, но в посте было только то, как рассчитывался текущий тренд.

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

Я не ищу сверхсложный алгоритм трендов, такой как те, что используются в Hacker News, Reddit и т. Д.

У меня есть только две оси данных, число читателей и дата.

Любые идеи о том, что и как я должен реализовать. Для кого-то, кто никогда не работал со статистикой / алгоритмом, это очень сложное занятие.

Спасибо всем заранее.

4 ответа

Решение

Вероятно, самый простой возможный "алгоритм" трендов, который я могу придумать, - это скользящее среднее за n дней. Я не уверен, как структурированы ваши данные, но говорю, что у вас есть что-то вроде этого:

books = {'Twilight': [500, 555, 580, 577, 523, 533, 556, 593],
         'Harry Potter': [650, 647, 653, 642, 633, 621, 625, 613],
         'Structure and Interpretation of Computer Programs': [1, 4, 15, 12, 7, 3, 8, 19]
        }

Простое скользящее среднее просто занимает последнее n оценивает и усредняет их:

def moving_av(l, n):
    """Take a list, l, and return the average of its last n elements.
    """
    observations = len(l[-n:])
    return sum(l[-n:]) / float(observations)

Обозначение фрагмента просто захватывает конец списка, начиная с n-й до последней переменной. Скользящее среднее является довольно стандартным способом сглаживания любого шума, который может внести один шип или провал. Функцию можно использовать так:

book_scores = {}
for book, reader_list in books.iteritems():
    book_scores[book] = moving_av(reader_list, 5)

Вам захочется поиграть с тем количеством дней, которое вы в среднем прошли. И если вы хотите подчеркнуть последние тенденции, вы также можете использовать что-то вроде взвешенного скользящего среднего.

Если вы хотите сосредоточиться на чем-то, что меньше смотрит на абсолютную аудиторию и вместо этого сосредоточено на увеличении читательской аудитории, просто найдите процентное изменение 30-дневной скользящей средней и 5-дневной скользящей средней:

d5_moving_av = moving_av(reader_list, 5)
d30_moving_av = moving_av(reader_list, 30)
book_score = (d5_moving_av - d30_moving_av) / d30_moving_av

С помощью этих простых инструментов вы получаете достаточную гибкость в том, насколько вы подчеркиваете прошлые тенденции и сколько вы хотите сгладить (или не сгладить) всплески.

Я бы сделал это системно так:

  1. Составьте список наиболее распространенных вопросов или точек данных, которые могут заинтересовать пользователя, например: 1.1 Топ 100 самых популярных книг на этой неделе 1.2 Топ 100 самых популярных книг этого месяца

  2. После вашего ежедневного читателя / информация о книге. обновлен, я бы запустил задание (возможно, ночью), чтобы обновить таблицу с этой информацией. Таблица, вероятно, будет иметь поля Book и ReaderDelta, где ReaderDelta - это изменение в readerCount за неделю, месяц или год.

  3. Вы также можете просто хранить ежедневную ReaderDelta, а при поиске данных за месяц просто динамически агрегировать последние 30 дней по дате.

Вы можете взять рейтинг репутации stackru в качестве примера.

Пользователь может изменить вид: по месяцам, годам, ....

В вашем случае: самая читаемая книга по месяцам, годам.

Чтобы достичь этого, вы должны ежедневно экономить количество читателей для каждой книги.

reader( date, book, total )

Тогда это так просто, как:

   Book.objects.filter(  
                   boor__reader__date__gte = some_date
                      ).annotate(
                            num_readers=Sum('book__reader__total')
                                ).order_by('-num_readers')

Популярность легка; Вы просто рассчитываете на читателей и заказываете так:

Book.objects.annotate(reader_count=Count('readers')).order_by('-reader_count')

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

Другие вопросы по тегам