Author: ssc
Date: Sun Dec  5 19:40:08 2010
New Revision: 1042429

URL: http://svn.apache.org/viewvc?rev=1042429&view=rev
Log:
MAHOUT-558 Extend ItembasedRecommender to offer different exclusion modes when 
computing most similar items

Modified:
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/ItemBasedRecommender.java
    
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java

Modified: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java?rev=1042429&r1=1042428&r2=1042429&view=diff
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
 (original)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
 Sun Dec  5 19:40:08 2010
@@ -73,6 +73,8 @@ public class GenericItemBasedRecommender
   private final RefreshHelper refreshHelper;
   private EstimatedPreferenceCapper capper;
 
+  private static final boolean EXCLUDE_ITEM_IF_NOT_SIMILAR_TO_ALL_BY_DEFAULT = 
true;
+
   public GenericItemBasedRecommender(DataModel dataModel,
                                      ItemSimilarity similarity,
                                      CandidateItemsStrategy 
candidateItemsStrategy) {
@@ -144,16 +146,36 @@ public class GenericItemBasedRecommender
   
   @Override
   public List<RecommendedItem> mostSimilarItems(long[] itemIDs, int howMany) 
throws TasteException {
-    return mostSimilarItems(itemIDs, howMany, null);
+    TopItems.Estimator<Long> estimator = new 
MultiMostSimilarEstimator(itemIDs, similarity, null,
+        EXCLUDE_ITEM_IF_NOT_SIMILAR_TO_ALL_BY_DEFAULT);
+    return doMostSimilarItems(itemIDs, howMany, estimator);
   }
   
   @Override
   public List<RecommendedItem> mostSimilarItems(long[] itemIDs, int howMany,
                                                 Rescorer<LongPair> rescorer) 
throws TasteException {
-    TopItems.Estimator<Long> estimator = new 
MultiMostSimilarEstimator(itemIDs, similarity, rescorer);
+    TopItems.Estimator<Long> estimator = new 
MultiMostSimilarEstimator(itemIDs, similarity, rescorer,
+        EXCLUDE_ITEM_IF_NOT_SIMILAR_TO_ALL_BY_DEFAULT);
     return doMostSimilarItems(itemIDs, howMany, estimator);
   }
-  
+
+  public List<RecommendedItem> mostSimilarItems(long[] itemIDs,
+                                         int howMany,
+                                         boolean excludeItemIfNotSimilarToAll) 
throws TasteException {
+    TopItems.Estimator<Long> estimator = new 
MultiMostSimilarEstimator(itemIDs, similarity, null,
+        excludeItemIfNotSimilarToAll);
+    return doMostSimilarItems(itemIDs, howMany, estimator);
+  }
+
+  @Override
+  public List<RecommendedItem> mostSimilarItems(long[] itemIDs, int howMany,
+                                                Rescorer<LongPair> rescorer,
+                                                boolean 
excludeItemIfNotSimilarToAll) throws TasteException {
+    TopItems.Estimator<Long> estimator = new 
MultiMostSimilarEstimator(itemIDs, similarity, rescorer,
+        excludeItemIfNotSimilarToAll);
+    return doMostSimilarItems(itemIDs, howMany, estimator);
+  }
+
   @Override
   public List<RecommendedItem> recommendedBecause(long userID, long itemID, 
int howMany) throws TasteException {
     Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1");
@@ -284,11 +306,14 @@ public class GenericItemBasedRecommender
     private final long[] toItemIDs;
     private final ItemSimilarity similarity;
     private final Rescorer<LongPair> rescorer;
+    private final boolean excludeItemIfNotSimilarToAll;
     
-    private MultiMostSimilarEstimator(long[] toItemIDs, ItemSimilarity 
similarity, Rescorer<LongPair> rescorer) {
+    private MultiMostSimilarEstimator(long[] toItemIDs, ItemSimilarity 
similarity, Rescorer<LongPair> rescorer,
+        boolean excludeItemIfNotSimilarToAll) {
       this.toItemIDs = toItemIDs;
       this.similarity = similarity;
       this.rescorer = rescorer;
+      this.excludeItemIfNotSimilarToAll = excludeItemIfNotSimilarToAll;
     }
     
     @Override
@@ -305,9 +330,12 @@ public class GenericItemBasedRecommender
         if (rescorer != null) {
           estimate = rescorer.rescore(pair, estimate);
         }
-        average.addDatum(estimate);
+        if (excludeItemIfNotSimilarToAll || !Double.isNaN(estimate)) {
+          average.addDatum(estimate);
+        }
       }
-      return average.getAverage();
+      double averageEstimate = average.getAverage();
+      return averageEstimate == 0 ? Double.NaN : averageEstimate;
     }
   }
   

Modified: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/ItemBasedRecommender.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/ItemBasedRecommender.java?rev=1042429&r1=1042428&r2=1042429&view=diff
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/ItemBasedRecommender.java
 (original)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/ItemBasedRecommender.java
 Sun Dec  5 19:40:08 2010
@@ -80,7 +80,41 @@ public interface ItemBasedRecommender ex
   List<RecommendedItem> mostSimilarItems(long[] itemIDs,
                                          int howMany,
                                          Rescorer<LongPair> rescorer) throws 
TasteException;
-  
+
+  /**
+   * @param itemIDs
+   *          IDs of item for which to find most similar other items
+   * @param howMany
+   *          desired number of most similar items to find
+   * @param excludeItemIfNotSimilarToAll
+   *          exclude an item if it is not similar to each of the input items
+   * @return items most similar to the given items, ordered from most similar 
to least
+   * @throws TasteException
+   *           if an error occurs while accessing the {...@link 
org.apache.mahout.cf.taste.model.DataModel}
+   */
+  List<RecommendedItem> mostSimilarItems(long[] itemIDs,
+                                         int howMany,
+                                         boolean excludeItemIfNotSimilarToAll) 
throws TasteException;
+
+  /**
+   * @param itemIDs
+   *          IDs of item for which to find most similar other items
+   * @param howMany
+   *          desired number of most similar items to find
+   * @param rescorer
+   *          {...@link Rescorer} which can adjust item-item similarity 
estimates used to determine most similar
+   *          items
+   * @param excludeItemIfNotSimilarToAll
+   *          exclude an item if it is not similar to each of the input items
+   * @return items most similar to the given items, ordered from most similar 
to least
+   * @throws TasteException
+   *           if an error occurs while accessing the {...@link 
org.apache.mahout.cf.taste.model.DataModel}
+   */
+  List<RecommendedItem> mostSimilarItems(long[] itemIDs,
+                                         int howMany,
+                                         Rescorer<LongPair> rescorer,
+                                         boolean excludeItemIfNotSimilarToAll) 
throws TasteException;
+
   /**
    * <p>
    * Lists the items that were most influential in recommending a given item 
to a given user. Exactly how this

Modified: 
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java?rev=1042429&r1=1042428&r2=1042429&view=diff
==============================================================================
--- 
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java
 (original)
+++ 
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java
 Sun Dec  5 19:40:08 2010
@@ -167,6 +167,32 @@ public final class GenericItemBasedRecom
   }
 
   @Test
+  public void testMostSimilarToMultipleExcludeIfNotSimilarToAll() throws 
Exception {
+    ItemBasedRecommender recommender = buildRecommender2();
+    List<RecommendedItem> similar = recommender.mostSimilarItems(new long[] 
{3, 4}, 2);
+    assertNotNull(similar);
+    assertEquals(1, similar.size());
+    RecommendedItem first = similar.get(0);
+    assertEquals(0, first.getItemID());
+    assertEquals(0.2f, first.getValue(), EPSILON);
+  }
+
+  @Test
+  public void testMostSimilarToMultipleDontExcludeIfNotSimilarToAll() throws 
Exception {
+    ItemBasedRecommender recommender = buildRecommender2();
+    List<RecommendedItem> similar = recommender.mostSimilarItems(new long[] 
{1, 2, 4}, 10, false);
+    assertNotNull(similar);
+    assertEquals(2, similar.size());
+    RecommendedItem first = similar.get(0);
+    RecommendedItem second = similar.get(1);
+    assertEquals(0, first.getItemID());
+    assertEquals(0.933333333f, first.getValue(), EPSILON);
+    assertEquals(3, second.getItemID());
+    assertEquals(-0.2f, second.getValue(), EPSILON);
+  }
+
+
+  @Test
   public void testRecommendedBecause() throws Exception {
     ItemBasedRecommender recommender = buildRecommender2();
     List<RecommendedItem> recommendedBecause = 
recommender.recommendedBecause(1, 4, 3);


Reply via email to