16

単純なトレンド/ランキングアルゴリズムを実装する必要があるDjangoアプリケーションがあります。私は:として非常に失われています

私は2つのモデルを持っています、BookそしてReader。毎晩、新しい本が私のデータベースに追加されます。各本の読者数も毎晩更新されます。つまり、1冊の本には複数の読者統計レコードがあります(1日につき1レコード)。

特定の期間(過去1週間、過去1か月、または過去1年間)で、最も人気のある本をリストしたいのですが、これにはどのアルゴリズムを使用すればよいですか?

各本の読者数は毎日更新されるだけなので、人気はリアルタイムである必要はありません。

トレンドのウィキペディアの記事をどのように計算したかを示す別のSO投稿で参照されている記事を見つけましたが、その投稿は現在のトレンドの計算方法のみを示していました。

SOについて誰かが指摘したように、これは非常に単純なベースライントレンドアルゴリズムであり、2つのデータポイント間の勾配のみを計算するため、昨日と今日の間のトレンドを示していると思います。

Hacker News、Redditなどで使用されているような非常に複雑なトレンドアルゴリズムを探していません。

リーダー数と日付の2つのデータ軸しかありません。

何をどのように実装すべきかについてのアイデア。統計/アルゴリズムに関連するものを一度も扱ったことがない人にとって、これは非常に困難な作業のようです。

みなさん、よろしくお願いします。

4

4 に答える 4

8

おそらく、私が考えることができる最も単純なトレンドの「アルゴリズム」は、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

これらのシンプルなツールを使用すると、過去の傾向をどれだけ強調するか、スパイクをどれだけ滑らかにしたい(または滑らかにしたくない)かについて、かなりの柔軟性があります。

于 2012-02-14T21:01:41.953 に答える
0

人気は簡単です。読者を数えて、それで注文するだけです。

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

これは人気のデルタであるため、トレンド分析はより困難です。つまり、最近どの本が最も多くの読者を獲得しているのかということです。このようなものが必要な場合は、日付ごとの読者数の記録を保持するために、舞台裏で何かを実行する必要があります。

于 2012-02-14T20:59:42.947 に答える
0

例として、 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')
于 2012-02-14T21:00:34.183 に答える
0

私はそれを次のように体系的に行います:

  1. ユーザーが興味を持つ最も一般的な質問またはデータポイントのリストを作成します。たとえば、次のようにします。1.1今週最も人気のある本のトップ1001.2今月の最も人気のある本のトップ100

  2. あなたの毎日の読者/本の情報の後。が更新されたら、この情報のテーブルを更新するために(おそらく毎晩)ジョブを実行します。テーブルにはおそらくBookフィールドとReaderDeltaフィールドがあり、ReaderDeltaは1週間、1か月、または1年にわたるreaderCountの変化です。

  3. また、毎日のReaderDeltaを保存するだけで、1か月分のデータを検索するときに、過去30日間を日付ごとに動的に集計することもできます。

于 2012-02-14T21:22:51.520 に答える