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);