2016-11-17 3 views
1

Ich entwickle ein item-based collaborative filter mit einem adjusted cosine similarity zwischen Restaurants, um Empfehlungen zu generieren. Ich habe alles eingerichtet und es funktioniert gut, aber wenn ich versuche, mögliche Testszenarien zu simulieren, habe ich einige interessante Ergebnisse erhalten.Angepasste Kosinusähnlichkeit funktioniert nicht richtig

Ich beginne mit meinen Testdaten. Ich habe 2 Restaurants, in denen ich eine Ähnlichkeit zwischen, und 3 Benutzer berechnen möchte, die alle die 2 Restaurants gleich bewertet haben. Ich werde erklären es die folgende Matrix:

   User 1 | User 2 | User 3 
Restaurant 1 | 1 | 2 | 1 
Restaurant 2 | 1 | 2 | 1 

Ich versuche, die Ähnlichkeit mit der folgenden Funktion zu berechnen:
Restaurants Subject in meinem Code aufgerufen werden.

public double ComputeSimilarity(Guid subject1, Guid subject2, IEnumerable<Review> allReviews) 
{ 
    //This will create an IEnumerable of reviews from the same user on the 2 restaurants. 
    var matches = (from R1 in allReviews.Where(x => x.SubjectId == subject1) 
        from R2 in allReviews.Where(x => x.SubjectId == subject2) 
        where R1.UserId == R2.UserId 
        select new { R1, R2 });    
    double num = 0.0f; 
    double dem1 = 0.0f; 
    double dem2 = 0.0f; 
    //For the similarity between subjects, we use an adjusted cosine similarity. 
    //More information on this can be found here: http://www10.org/cdrom/papers/519/node14.html 
    foreach (var item in matches) 
    { 
     //First get the average of all reviews the user has given. This is used in the adjusted cosine similarity, read the article from the link for further explanation 
     double avg = allReviews.Where(x => x.UserId == item.R1.UserId) 
           .Average(x => x.rating); 
     num += ((item.R1.rating - avg) * (item.R2.rating - avg)); 
     dem1 += Math.Pow((item.R1.rating - avg), 2); 
     dem2 += Math.Pow((item.R2.rating - avg), 2); 
    } 
    return (num/(Math.Sqrt(dem1) * Math.Sqrt(dem2))); 
} 

Meine Bewertung sieht wie folgt aus:

public class Review 
{ 
    public Guid Id { get; set; } 
    public int rating { get; set; } //This can be an integer between 1-5 
    public Guid SubjectId { get; set; } //This is the guid of the subject the review has been left on 
    public Guid UserId { get; set; } //This is the guid of the user who left the review 
} 

In allen anderen Szenarien wird die Funktion eine korrekte Ähnlichkeit zwischen den Fächern berechnen. Aber wenn ich die obigen Testdaten verwende (wo ich eine perfekte Ähnlichkeit erwartet habe), ergibt sich ein NaN.

Ist dies ein Fehler in meinem Code oder ist das ein Fehler in der angepassten Kosinusähnlichkeit? Und wenn es NaN ergibt, ist es gut, dies zu fangen und einen 1 für Ähnlichkeit einzufügen?

Edit: Ich habe auch mit anderen Matrizen versucht, und ich habe noch interessantere Ergebnisse.

   User 1 | User 2 | User 3 | User 4 | User 5 
Restaurant 1 | 1 | 2 | 1 | 1 | 2 
Restaurant 2 | 1 | 2 | 1 | 1 | 2 

Dies führt immer noch zu NaN.

   User 1 | User 2 | User 3 | User 4 | User 5 
Restaurant 1 | 2 | 2 | 1 | 1 | 2 
Restaurant 2 | 1 | 2 | 1 | 1 | 2 

Dies führt zu -1 für Ähnlichkeit

+0

Nun, das ist nur eine Eigenschaft der Formel, die Sie verwenden: Wenn alle Benutzer die gleiche Bewertung für alle Filme haben (also identische Zeilen in Ihrer Tabelle oben) - Nenner ist Null und das Ergebnis ist undefiniert (dargestellt von NaN in .NET). – Evk

+0

Ist das vermeidbar? Ich nehme an, dass dieses Szenario sehr klein ist, aber es ist möglich. – RandomStranger

+0

Ich denke, da Sie die Situation wissen, wenn es entsteht, können Sie es nur auf eine besondere Weise behandeln, nicht verhindern. – Evk

Antwort

1

Es scheint, Ihr Algorithmus korrekt implementiert ist. Sache ist, dass diese Formel in einigen Punkten für vollkommen vernünftige Sätze tatsächlich undefiniert sein kann. Sie können diesen Fall als "dieses Maß (angepasste Kosinusähnlichkeit) hat nichts zu den bereitgestellten Mengen zu sagen", so ist es nicht richtig, einen beliebigen Wert (0, 1, -1) zuzuweisen. Verwenden Sie stattdessen in diesem Fall ein anderes Maß. Zum Beispiel ergibt die einfache (nicht angepasste) Kosinusähnlichkeit "1" als Ergebnis, was Sie erwarten könnten.