Решение и реализация алгоритма трендов в Джанго - PullRequest
10 голосов
/ 15 февраля 2012

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

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

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

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

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

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

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

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

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

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

Ответы [ 4 ]

7 голосов
/ 15 февраля 2012

Вероятно, самый простой из возможных «алгоритмов» трендов - это скользящее среднее 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

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

0 голосов
/ 15 февраля 2012

Я бы сделал это системно следующим образом:

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

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

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

0 голосов
/ 15 февраля 2012

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

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

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

Для этогоВы должны день за днем ​​сохранять число читателей для каждой книги.

reader( date, book, total )

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

   Book.objects.filter(  
                   boor__reader__date__gte = some_date
                      ).annotate(
                            num_readers=Sum('book__reader__total')
                                ).order_by('-num_readers')
0 голосов
/ 15 февраля 2012

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

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

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

...