5

短縮版:

StackOverflowと同様の設定があります。ユーザーは実績を取得します。私はSOよりもはるかに多くの実績を持っています。たとえば10kのオーダーで、各ユーザーは数百の実績を持っています。さて、ユーザーが試すべき次の成果をどのように推奨しますか(推奨しますか)?

ロングバージョン:

オブジェクトはdjangoでこのようにモデル化されています(重要な部分のみを表示しています):

class User(models.Model):
    alias = models.ForeignKey(Alias)

class Alias(models.Model):
    achievements = models.ManyToManyField('Achievement', through='Achiever')

class Achievement(models.Model):
    points = models.IntegerField()

class Achiever(models.Model):
    achievement = models.ForeignKey(Achievement)
    alias = models.ForeignKey(Alias)
    count = models.IntegerField(default=1)

私のアルゴリズムは、ログインしたユーザーと実績を共有している他のすべてのユーザーを見つけて、すべての実績を調べ、発生回数で並べ替えるだけです。

def recommended(request) :
    user = request.user.get_profile()

    // The final response
    r = {}

    // Get all the achievements the user's aliases have received 
    // in a set so they aren't double counted
    achievements = set()
    for alias in user.alias_set.select_related('achievements').all() :
        achievements.update(alias.achievements.all())

    // Find all other aliases that have gotten at least one of the same
    // same achievements as the user
    otherAliases = set()
    for ach in achievements :
        otherAliases.update(ach.alias_set.all())

    // Find other achievements the other users have gotten in addition to
    // the shared ones.
    // And count the number of times each achievement appears
    for otherAlias in otherAliases :
        for otherAch in otherAlias.achievements.all() :
            r[otherAch] = r.get(otherAch, 0) + 1

    // Remove all the achievements that the user has already gotten
    for ach in achievements :
        r.pop(ach)

    // Sort by number of times the achievements have been received
    r = sorted(r.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)

    // Put in the template for showing on the screen
    template_values = {}
    template_values['achievements'] = r

ただし、実行にはFOREVERが必要であり、常にリスト全体が返されますが、これは不要です。ユーザーは、上位のいくつかの実績のみを追跡する必要があります。

したがって、他のアルゴリズムやコードの改善に関する推奨事項を歓迎します。レコメンデーションアルゴリズムを考え出すための私のシステムでの成果をお伝えします:)

4

2 に答える 2

3

どのアチーブメントを推奨するかを推奨する方法の 1 つは、それらのアチーブメントを既に持っているユーザーの数を確認し、人気のあるアチーブメントを推奨することです。それらが達成されたら、リストを下に移動し、あまり人気のないものを推奨します。ただし、これには、誰もが人気のある実績を求めているという単純な仮定があります。人気のある実績がさらに人気が高くなり、人気が低くなる可能性があります... 慰めは、これが多くのリソースを消費せず、非常に高速に実行される可能性が高いことです. (達成リスト+達成回数を記録するだけ)

もう 1 つの方法 (ユーザーが既に達成した実績に基づいて、ユーザーがどの実績を追求する可能性が高いかを推測しようとする) は、機械学習アルゴリズムを使用することです。ここでは、 k 最近傍アルゴリズムが非常にうまく機能すると思います。しきい値を選択し、このしきい値を超えるものをすべて出力します。さて、これがあなたがすでに持っているものよりも速く実行されるかどうかはわかりませんが、ユーザーが新しい成果を達成するたびにレコメンデーション エンジンを 1 回実行し、上位 (たとえば) 5 つを保存し、それを出力するだけです。推奨事項が必要なときはいつでもユーザーに戻します。

これが役立つことを願っています。=)

于 2009-07-04T08:52:03.660 に答える
2

最初の 3 つのステップ (achievements、otherAliases、count) を 1 つの SQL ステートメントとして実行することをお勧めします。現在、Python で多数のクエリを発行し、何千もの行を要約していますが、これは DB に委任する必要があるタスクです。たとえば、コード

for otherAlias in otherAliases : #For every single other user
    for otherAch in otherAlias.achievements.all() : #execute a query
        r[otherAch] = r.get(otherAch, 0) + 1

何千もの巨大なクエリを実行します。

代わりに、SQL を使用して、エイリアス ID が異なり、アチーブメント ID が同じであることに基づいて、アチーバー自体に参加することにより、これを行うことができます。次に、アチーブメント ID でグループ化し、カウントを実行します。

以下のクエリでは、テーブル "B" は他のユーザーの実績で、"Achiever" は私たちの実績です。他のユーザーが実績を共有している場合、共有する実績ごとに "B" に 1 回表示されます。次に、それらを alias_id でグループ化し、それらが出現した回数をカウントして、適切な ID を取得します。テーブルをカウントします。

非常に大雑把なコード (ここでは SQL は使用できません)

SELECT B.Alias_id, COUNT(B.achievement_id) 
  FROM Achiever, Achiever as B 
  WHERE Achiever.achievement_id == B.achievement_id 
     AND Achiever.Alias_id == <insert current user alias here>;
  GROUP BY B.Alias_id

それが私が思うように機能する場合、現在のユーザーと共有している実績の数とともに、他のユーザー エイリアスのテーブルが表示されます。

次に行うことは、上記のものを「内部選択」として使用する SQL ステートメントです。これを users と呼びます。これを、現在のユーザーの実績テーブルと達成者テーブルに結合します。現在のユーザーに似ている上位 10 人のユーザーを除くすべてを無視したい場合があります。

現在、適切なクエリを作成する時間はありませんが、指定された 10 人のユーザーと現在のユーザーの間で achievement_id に参加する DB の JOIN ステートメントを見てください。存在しない場合はその ID を NULL に設定します。NULL (未達成の実績) になった行のみをフィルターします。

于 2009-07-06T04:18:10.047 に答える