public override IList <IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { IDataModel dataModel = GetDataModel(); int numItems = dataModel.GetNumItems(); List <IRecommendedItem> result = new List <IRecommendedItem>(howMany); while (result.Count < howMany) { var it = dataModel.GetItemIDs(); it.MoveNext(); var skipNum = random.nextInt(numItems); for (int i = 0; i < skipNum; i++) { if (!it.MoveNext()) { break; } // skip() ?? } long itemID = it.Current; if (dataModel.GetPreferenceValue(userID, itemID) == null) { result.Add(new GenericRecommendedItem(itemID, randomPref())); } } return(result); }
public List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) { lock (this.maxHowMany) { if (howMany > this.maxHowMany[0]) { this.maxHowMany[0] = howMany; } } if (userID == -9223372036854775808L) { return(this.recommendationsRetriever.get(-9223372036854775808L).getItems()); } this.setCurrentRescorer(rescorer); Recommendations recommendations = this.recommendationCache.get(userID); if ((recommendations.getItems().Count < howMany) && !recommendations.isNoMoreRecommendableItems()) { this.clear(userID); recommendations = this.recommendationCache.get(userID); if (recommendations.getItems().Count < howMany) { recommendations.setNoMoreRecommendableItems(true); } } List <RecommendedItem> list = recommendations.getItems(); return((list.Count > howMany) ? list.GetRange(0, howMany) : list); }
public override List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) { DataModel model = this.getDataModel(); int n = model.getNumItems(); List <RecommendedItem> list = new List <RecommendedItem>(howMany); while (list.Count < howMany) { IEnumerator <long> enumerator = model.getItemIDs(); enumerator.MoveNext(); int num2 = this.random.nextInt(n); for (int i = 0; i < num2; i++) { if (!enumerator.MoveNext()) { break; } } long current = enumerator.Current; if (!model.getPreferenceValue(userID, current).HasValue) { list.Add(new GenericRecommendedItem(current, this.randomPref())); } } return(list); }
public IList <IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { //Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); lock (maxHowMany) { if (howMany > maxHowMany[0]) { maxHowMany[0] = howMany; } } // Special case, avoid caching an anonymous user if (userID == PlusAnonymousUserDataModel.TEMP_USER_ID) { return(recommendationsRetriever.Get(PlusAnonymousUserDataModel.TEMP_USER_ID).getItems()); } setCurrentRescorer(rescorer); Recommendations recommendations = recommendationCache.Get(userID); if (recommendations.getItems().Count < howMany && !recommendations.isNoMoreRecommendableItems()) { clear(userID); recommendations = recommendationCache.Get(userID); if (recommendations.getItems().Count < howMany) { recommendations.setNoMoreRecommendableItems(true); } } List <IRecommendedItem> recommendedItems = recommendations.getItems(); return(recommendedItems.Count > howMany?recommendedItems.GetRange(0, howMany) : recommendedItems); }
public CachingRecommender.Recommendations get(long key) { CachingRecommender.log.debug("Retrieving new recommendations for user ID '{}'", new object[] { key }); int howMany = this.p.maxHowMany[0]; IDRescorer currentRescorer = this.p.currentRescorer; List <RecommendedItem> collection = (currentRescorer == null) ? this.p.recommender.recommend(key, howMany) : this.p.recommender.recommend(key, howMany, currentRescorer); return(new CachingRecommender.Recommendations(new List <RecommendedItem>(collection))); }
public override List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) { log.debug("Recommending items for user ID '{}'", new object[] { userID }); PreferenceArray preferencesFromUser = this.getDataModel().getPreferencesFromUser(userID); List <RecommendedItem> list = TopItems.getTopItems(howMany, this.getAllOtherItems(userID, preferencesFromUser).GetEnumerator(), rescorer, new Estimator(this, userID)); log.debug("Recommendations are: {}", new object[] { list }); return(list); }
public void testUserRescorer() { IDRescorer rescorer = NullRescorer.getUserInstance(); Assert.NotNull(rescorer); Assert.AreEqual(1.0, rescorer.rescore(1L, 1.0), EPSILON); Assert.AreEqual(1.0, rescorer.rescore(0L, 1.0), EPSILON); Assert.AreEqual(0.0, rescorer.rescore(1L, 0.0), EPSILON); Assert.True(Double.IsNaN(rescorer.rescore(1L, Double.NaN))); }
public Recommendations Get(long key) { log.Debug("Retrieving new recommendations for user ID '{}'", key); int howMany = p.maxHowMany[0]; IDRescorer rescorer = p.currentRescorer; var recommendations = rescorer == null?p.recommender.Recommend(key, howMany) : p.recommender.Recommend(key, howMany, rescorer); return(new Recommendations(new List <IRecommendedItem>(recommendations))); }
public static List <IRecommendedItem> GetTopItems(int howMany, IEnumerator <long> possibleItemIDs, IDRescorer rescorer, IEstimator <long> estimator) { //Preconditions.checkArgument(possibleItemIDs != null, "possibleItemIDs is null"); //Preconditions.checkArgument(estimator != null, "estimator is null"); var topItems = new SortedSet <IRecommendedItem>(ByValueRecommendedItemComparator.getReverseInstance()); bool full = false; double lowestTopValue = Double.NegativeInfinity; while (possibleItemIDs.MoveNext()) { long itemID = possibleItemIDs.Current; if (rescorer == null || !rescorer.isFiltered(itemID)) { double preference; try { preference = estimator.Estimate(itemID); } catch (NoSuchItemException nsie) { continue; } double rescoredPref = rescorer == null ? preference : rescorer.rescore(itemID, preference); if (!Double.IsNaN(rescoredPref) && (!full || rescoredPref > lowestTopValue)) { topItems.Add(new GenericRecommendedItem(itemID, (float)rescoredPref)); if (full) { topItems.Remove(topItems.Min); } else if (topItems.Count > howMany) { full = true; topItems.Remove(topItems.Min); // topItems.poll(); } lowestTopValue = topItems.Min.GetValue(); } } } int size = topItems.Count; if (size == 0) { return(new List <IRecommendedItem>()); } List <IRecommendedItem> result = new List <IRecommendedItem>(size); result.AddRange(topItems); result.Reverse(); //Collections.sort(result, ByValueRecommendedItemComparator.getInstance()); return(result); }
public void testRecommender() { var mockRecommender = new MockRecommender(0); IRecommender cachingRecommender = new CachingRecommender(mockRecommender); cachingRecommender.Recommend(1, 1); Assert.AreEqual(1, mockRecommender.recommendCount); cachingRecommender.Recommend(2, 1); Assert.AreEqual(2, mockRecommender.recommendCount); cachingRecommender.Recommend(1, 1); Assert.AreEqual(2, mockRecommender.recommendCount); cachingRecommender.Recommend(2, 1); Assert.AreEqual(2, mockRecommender.recommendCount); cachingRecommender.Refresh(null); cachingRecommender.Recommend(1, 1); Assert.AreEqual(3, mockRecommender.recommendCount); cachingRecommender.Recommend(2, 1); Assert.AreEqual(4, mockRecommender.recommendCount); cachingRecommender.Recommend(3, 1); Assert.AreEqual(5, mockRecommender.recommendCount); // Results from this recommend() method can be cached... IDRescorer rescorer = NullRescorer.getItemInstance(); cachingRecommender.Refresh(null); cachingRecommender.Recommend(1, 1, rescorer); Assert.AreEqual(6, mockRecommender.recommendCount); cachingRecommender.Recommend(2, 1, rescorer); Assert.AreEqual(7, mockRecommender.recommendCount); cachingRecommender.Recommend(1, 1, rescorer); Assert.AreEqual(7, mockRecommender.recommendCount); cachingRecommender.Recommend(2, 1, rescorer); Assert.AreEqual(7, mockRecommender.recommendCount); // until you switch Rescorers cachingRecommender.Recommend(1, 1, null); Assert.AreEqual(8, mockRecommender.recommendCount); cachingRecommender.Recommend(2, 1, null); Assert.AreEqual(9, mockRecommender.recommendCount); cachingRecommender.Refresh(null); cachingRecommender.EstimatePreference(1, 1); Assert.AreEqual(10, mockRecommender.recommendCount); cachingRecommender.EstimatePreference(1, 2); Assert.AreEqual(11, mockRecommender.recommendCount); cachingRecommender.EstimatePreference(1, 2); Assert.AreEqual(11, mockRecommender.recommendCount); }
public override IList <IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { //Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); log.Debug("Recommending items for user ID '{}'", userID); IPreferenceArray preferencesFromUser = GetDataModel().GetPreferencesFromUser(userID); FastIDSet possibleItemIDs = GetAllOtherItems(userID, preferencesFromUser); List <IRecommendedItem> topItems = TopItems.GetTopItems(howMany, possibleItemIDs.GetEnumerator(), rescorer, new Estimator(this, userID)); log.Debug("Recommendations are: {}", topItems); return(topItems); }
public static long[] GetTopUsers(int howMany, IEnumerator <long> allUserIDs, IDRescorer rescorer, IEstimator <long> estimator) { var topUsers = new SortedSet <SimilarUser>(); bool full = false; double lowestTopValue = Double.NegativeInfinity; while (allUserIDs.MoveNext()) { long userID = allUserIDs.Current; if (rescorer != null && rescorer.isFiltered(userID)) { continue; } double similarity; try { similarity = estimator.Estimate(userID); } catch (NoSuchUserException nsue) { continue; } double rescoredSimilarity = rescorer == null ? similarity : rescorer.rescore(userID, similarity); if (!Double.IsNaN(rescoredSimilarity) && (!full || rescoredSimilarity > lowestTopValue)) { topUsers.Add(new SimilarUser(userID, rescoredSimilarity)); if (full) { topUsers.Remove(topUsers.Max); // topUsers.poll(); } else if (topUsers.Count > howMany) { full = true; topUsers.Remove(topUsers.Max); // topUsers.poll(); } lowestTopValue = topUsers.Max.getSimilarity(); } } int size = topUsers.Count; if (size == 0) { return(NO_IDS); } List <SimilarUser> sorted = new List <SimilarUser>(size); return(topUsers.Select(s => s.getUserID()).ToArray()); }
private void setCurrentRescorer(IDRescorer rescorer) { if (rescorer == null) { if (this.currentRescorer != null) { this.currentRescorer = null; this.clear(); } } else if (!rescorer.Equals(this.currentRescorer)) { this.currentRescorer = rescorer; this.clear(); } }
public override List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) { log.debug("Recommending items for user ID '{}'", new object[] { userID }); long[] theNeighborhood = this.neighborhood.getUserNeighborhood(userID); if (theNeighborhood.Length == 0) { return(new List <RecommendedItem>()); } FastIDSet set = this.getAllOtherItems(theNeighborhood, userID); TopItems.Estimator <long> estimator = new Estimator(this, userID, theNeighborhood); List <RecommendedItem> list = TopItems.getTopItems(howMany, set.GetEnumerator(), rescorer, estimator); log.debug("Recommendations are: {}", new object[] { list }); return(list); }
public static long[] getTopUsers(int howMany, IEnumerator <long> allUserIDs, IDRescorer rescorer, Estimator <long> estimator) { SortedSet <SimilarUser> set = new SortedSet <SimilarUser>(); bool flag = false; double negativeInfinity = double.NegativeInfinity; while (allUserIDs.MoveNext()) { long current = allUserIDs.Current; if ((rescorer == null) || !rescorer.isFiltered(current)) { double num3; try { num3 = estimator.estimate(current); } catch (NoSuchUserException) { continue; } double d = (rescorer == null) ? num3 : rescorer.rescore(current, num3); if (!double.IsNaN(d) && (!flag || (d > negativeInfinity))) { set.Add(new SimilarUser(current, d)); if (flag) { set.Remove(set.Max); } else if (set.Count > howMany) { flag = true; set.Remove(set.Max); } negativeInfinity = set.Max.getSimilarity(); } } } int count = set.Count; if (count == 0) { return(NO_IDS); } List <SimilarUser> list = new List <SimilarUser>(count); return((from s in set select s.getUserID()).ToArray <long>()); }
public override List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) { log.debug("Recommending items for user ID '{}'", new object[] { userID }); PreferenceArray preferencesFromUser = this.getDataModel().getPreferencesFromUser(userID); if (preferencesFromUser.length() == 0) { return(new List <RecommendedItem>()); } FastIDSet set = this.getAllOtherItems(userID, preferencesFromUser); TopItems.Estimator <long> estimator = new Estimator(this, userID, preferencesFromUser); List <RecommendedItem> list = TopItems.getTopItems(howMany, set.GetEnumerator(), rescorer, estimator); log.debug("Recommendations are: {}", new object[] { list }); return(list); }
private void setCurrentRescorer(IDRescorer rescorer) { if (rescorer == null) { if (currentRescorer != null) { currentRescorer = null; clear(); } } else { if (!rescorer.Equals(currentRescorer)) { currentRescorer = rescorer; clear(); } } }
public override IList<IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { IDataModel dataModel = GetDataModel(); int numItems = dataModel.GetNumItems(); List<IRecommendedItem> result = new List<IRecommendedItem>(howMany); while (result.Count < howMany) { var it = dataModel.GetItemIDs(); it.MoveNext(); var skipNum = random.nextInt(numItems); for (int i=0; i<skipNum; i++) if (!it.MoveNext()) { break; } // skip() ?? long itemID = it.Current; if (dataModel.GetPreferenceValue(userID, itemID) == null) { result.Add(new GenericRecommendedItem(itemID, randomPref())); } } return result; }
public override List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer) { // Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); if (howMany < 1) { throw new Exception("howMany must be at least 1"); } ; buildClusters(); log.debug("Recommending items for user ID '{}'", userID); List <RecommendedItem> recommended = topRecsByUserID.get(userID); if (recommended == null) { return(new List <RecommendedItem>()); } DataModel dataModel = getDataModel(); List <RecommendedItem> rescored = new List <RecommendedItem>(); //Lists.newArrayListWithCapacity(recommended.size()); // Only add items the user doesn't already have a preference for. // And that the rescorer doesn't "reject". foreach (RecommendedItem recommendedItem in recommended) { long itemID = recommendedItem.getItemID(); if (rescorer != null && rescorer.isFiltered(itemID)) { continue; } if (dataModel.getPreferenceValue(userID, itemID) == null && (rescorer == null || !Double.IsNaN(rescorer.rescore(itemID, recommendedItem.getValue())))) { rescored.Add(recommendedItem); } } rescored.Sort(new ByRescoreComparator(rescorer)); return(rescored); }
public override IList <IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { //Preconditions.checkArgument(howMany >= 1, "howMany must be at least 1"); log.Debug("Recommending items for user ID '{}'", userID); long[] theNeighborhood = neighborhood.GetUserNeighborhood(userID); if (theNeighborhood.Length == 0) { return(new List <IRecommendedItem>()); } FastIDSet allItemIDs = getAllOtherItems(theNeighborhood, userID); TopItems.IEstimator <long> estimator = new Estimator(this, userID, theNeighborhood); List <IRecommendedItem> topItems = TopItems .GetTopItems(howMany, allItemIDs.GetEnumerator(), rescorer, estimator); log.Debug("Recommendations are: {}", topItems); return(topItems); }
public IList<IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { return Recommend(userID, howMany); }
public abstract IList<IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer);
public ByRescoreComparator(IDRescorer rescorer) { this.rescorer = rescorer; }
public IList <IRecommendedItem> Recommend(long userID, int howMany, IDRescorer rescorer) { return(Recommend(userID, howMany)); }
public abstract List <RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer);
public IRStatistics Evaluate(IRecommenderBuilder recommenderBuilder, IDataModelBuilder dataModelBuilder, IDataModel dataModel, IDRescorer rescorer, int at, double relevanceThreshold, double evaluationPercentage) { //Preconditions.checkArgument(recommenderBuilder != null, "recommenderBuilder is null"); //Preconditions.checkArgument(dataModel != null, "dataModel is null"); //Preconditions.checkArgument(at >= 1, "at must be at least 1"); //Preconditions.checkArgument(evaluationPercentage > 0.0 && evaluationPercentage <= 1.0, // "Invalid evaluationPercentage: " + evaluationPercentage + ". Must be: 0.0 < evaluationPercentage <= 1.0"); int numItems = dataModel.GetNumItems(); IRunningAverage precision = new FullRunningAverage(); IRunningAverage recall = new FullRunningAverage(); IRunningAverage fallOut = new FullRunningAverage(); IRunningAverage nDCG = new FullRunningAverage(); int numUsersRecommendedFor = 0; int numUsersWithRecommendations = 0; var it = dataModel.GetUserIDs(); while (it.MoveNext()) { long userID = it.Current; if (random.nextDouble() >= evaluationPercentage) { // Skipped continue; } var stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); IPreferenceArray prefs = dataModel.GetPreferencesFromUser(userID); // List some most-preferred items that would count as (most) "relevant" results double theRelevanceThreshold = Double.IsNaN(relevanceThreshold) ? computeThreshold(prefs) : relevanceThreshold; FastIDSet relevantItemIDs = dataSplitter.GetRelevantItemsIDs(userID, at, theRelevanceThreshold, dataModel); int numRelevantItems = relevantItemIDs.Count(); if (numRelevantItems <= 0) { continue; } FastByIDMap<IPreferenceArray> trainingUsers = new FastByIDMap<IPreferenceArray>(dataModel.GetNumUsers()); var it2 = dataModel.GetUserIDs(); while (it2.MoveNext()) { dataSplitter.ProcessOtherUser(userID, relevantItemIDs, trainingUsers, it2.Current, dataModel); } IDataModel trainingModel = dataModelBuilder == null ? new GenericDataModel(trainingUsers) : dataModelBuilder.BuildDataModel(trainingUsers); try { trainingModel.GetPreferencesFromUser(userID); } catch (NoSuchUserException nsee) { continue; // Oops we excluded all prefs for the user -- just move on } int size = numRelevantItems + trainingModel.GetItemIDsFromUser(userID).Count(); if (size < 2 * at) { // Really not enough prefs to meaningfully evaluate this user continue; } IRecommender recommender = recommenderBuilder.BuildRecommender(trainingModel); int intersectionSize = 0; var recommendedItems = recommender.Recommend(userID, at, rescorer); foreach (IRecommendedItem recommendedItem in recommendedItems) { if (relevantItemIDs.Contains(recommendedItem.GetItemID())) { intersectionSize++; } } int numRecommendedItems = recommendedItems.Count; // Precision if (numRecommendedItems > 0) { precision.AddDatum((double) intersectionSize / (double) numRecommendedItems); } // Recall recall.AddDatum((double) intersectionSize / (double) numRelevantItems); // Fall-out if (numRelevantItems < size) { fallOut.AddDatum((double) (numRecommendedItems - intersectionSize) / (double) (numItems - numRelevantItems)); } // nDCG // In computing, assume relevant IDs have relevance 1 and others 0 double cumulativeGain = 0.0; double idealizedGain = 0.0; for (int i = 0; i < numRecommendedItems; i++) { IRecommendedItem item = recommendedItems[i]; double discount = 1.0 / log2(i + 2.0); // Classical formulation says log(i+1), but i is 0-based here if (relevantItemIDs.Contains(item.GetItemID())) { cumulativeGain += discount; } // otherwise we're multiplying discount by relevance 0 so it doesn't do anything // Ideally results would be ordered with all relevant ones first, so this theoretical // ideal list starts with number of relevant items equal to the total number of relevant items if (i < numRelevantItems) { idealizedGain += discount; } } if (idealizedGain > 0.0) { nDCG.AddDatum(cumulativeGain / idealizedGain); } // Reach numUsersRecommendedFor++; if (numRecommendedItems > 0) { numUsersWithRecommendations++; } stopWatch.Stop(); log.Info("Evaluated with user {} in {}ms", userID, stopWatch.ElapsedMilliseconds); log.Info("Precision/recall/fall-out/nDCG/reach: {} / {} / {} / {} / {}", precision.GetAverage(), recall.GetAverage(), fallOut.GetAverage(), nDCG.GetAverage(), (double) numUsersWithRecommendations / (double) numUsersRecommendedFor); } return new IRStatisticsImpl( precision.GetAverage(), recall.GetAverage(), fallOut.GetAverage(), nDCG.GetAverage(), (double) numUsersWithRecommendations / (double) numUsersRecommendedFor); }
public IRStatistics evaluate(RecommenderBuilder recommenderBuilder, DataModelBuilder dataModelBuilder, DataModel dataModel, IDRescorer rescorer, int at, double relevanceThreshold, double evaluationPercentage) { int num = dataModel.getNumItems(); RunningAverage average = new FullRunningAverage(); RunningAverage average2 = new FullRunningAverage(); RunningAverage average3 = new FullRunningAverage(); RunningAverage average4 = new FullRunningAverage(); int num2 = 0; int num3 = 0; IEnumerator <long> enumerator = dataModel.getUserIDs(); while (enumerator.MoveNext()) { long current = enumerator.Current; if (this.random.nextDouble() < evaluationPercentage) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); PreferenceArray prefs = dataModel.getPreferencesFromUser(current); double num5 = double.IsNaN(relevanceThreshold) ? computeThreshold(prefs) : relevanceThreshold; FastIDSet relevantItemIDs = this.dataSplitter.getRelevantItemsIDs(current, at, num5, dataModel); int num6 = relevantItemIDs.size(); if (num6 > 0) { FastByIDMap <PreferenceArray> trainingUsers = new FastByIDMap <PreferenceArray>(dataModel.getNumUsers()); IEnumerator <long> enumerator2 = dataModel.getUserIDs(); while (enumerator2.MoveNext()) { this.dataSplitter.processOtherUser(current, relevantItemIDs, trainingUsers, enumerator2.Current, dataModel); } DataModel model = (dataModelBuilder == null) ? new GenericDataModel(trainingUsers) : dataModelBuilder.buildDataModel(trainingUsers); try { model.getPreferencesFromUser(current); } catch (NoSuchUserException) { continue; } int num7 = num6 + model.getItemIDsFromUser(current).size(); if (num7 >= (2 * at)) { Recommender recommender = recommenderBuilder.buildRecommender(model); int num8 = 0; List <RecommendedItem> list = recommender.recommend(current, at, rescorer); foreach (RecommendedItem item in list) { if (relevantItemIDs.contains(item.getItemID())) { num8++; } } int count = list.Count; if (count > 0) { average.addDatum(((double)num8) / ((double)count)); } average2.addDatum(((double)num8) / ((double)num6)); if (num6 < num7) { average3.addDatum(((double)(count - num8)) / ((double)(num - num6))); } double num10 = 0.0; double num11 = 0.0; for (int i = 0; i < count; i++) { RecommendedItem item2 = list[i]; double num13 = 1.0 / log2(i + 2.0); if (relevantItemIDs.contains(item2.getItemID())) { num10 += num13; } if (i < num6) { num11 += num13; } } if (num11 > 0.0) { average4.addDatum(num10 / num11); } num2++; if (count > 0) { num3++; } stopwatch.Stop(); log.info("Evaluated with user {} in {}ms", new object[] { current, stopwatch.ElapsedMilliseconds }); log.info("Precision/recall/fall-out/nDCG/reach: {} / {} / {} / {} / {}", new object[] { average.getAverage(), average2.getAverage(), average3.getAverage(), average4.getAverage(), ((double)num3) / ((double)num2) }); } } } } return(new IRStatisticsImpl(average.getAverage(), average2.getAverage(), average3.getAverage(), average4.getAverage(), ((double)num3) / ((double)num2))); }
public static List <RecommendedItem> getTopItems(int howMany, IEnumerator <long> possibleItemIDs, IDRescorer rescorer, Estimator <long> estimator) { SortedSet <RecommendedItem> collection = new SortedSet <RecommendedItem>(ByValueRecommendedItemComparator.getReverseInstance()); bool flag = false; double negativeInfinity = double.NegativeInfinity; while (possibleItemIDs.MoveNext()) { long current = possibleItemIDs.Current; if ((rescorer == null) || !rescorer.isFiltered(current)) { double num3; try { num3 = estimator.estimate(current); } catch (NoSuchItemException) { continue; } double d = (rescorer == null) ? num3 : rescorer.rescore(current, num3); if (!double.IsNaN(d) && (!flag || (d > negativeInfinity))) { collection.Add(new GenericRecommendedItem(current, (float)d)); if (flag) { collection.Remove(collection.Min); } else if (collection.Count > howMany) { flag = true; collection.Remove(collection.Min); } negativeInfinity = collection.Min.getValue(); } } } int count = collection.Count; if (count == 0) { return(new List <RecommendedItem>()); } List <RecommendedItem> list = new List <RecommendedItem>(count); list.AddRange(collection); list.Reverse(); return(list); }
public IRStatistics Evaluate(IRecommenderBuilder recommenderBuilder, IDataModelBuilder dataModelBuilder, IDataModel dataModel, IDRescorer rescorer, int at, double relevanceThreshold, double evaluationPercentage) { //Preconditions.checkArgument(recommenderBuilder != null, "recommenderBuilder is null"); //Preconditions.checkArgument(dataModel != null, "dataModel is null"); //Preconditions.checkArgument(at >= 1, "at must be at least 1"); //Preconditions.checkArgument(evaluationPercentage > 0.0 && evaluationPercentage <= 1.0, // "Invalid evaluationPercentage: " + evaluationPercentage + ". Must be: 0.0 < evaluationPercentage <= 1.0"); int numItems = dataModel.GetNumItems(); IRunningAverage precision = new FullRunningAverage(); IRunningAverage recall = new FullRunningAverage(); IRunningAverage fallOut = new FullRunningAverage(); IRunningAverage nDCG = new FullRunningAverage(); int numUsersRecommendedFor = 0; int numUsersWithRecommendations = 0; var it = dataModel.GetUserIDs(); while (it.MoveNext()) { long userID = it.Current; if (random.nextDouble() >= evaluationPercentage) { // Skipped continue; } var stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); IPreferenceArray prefs = dataModel.GetPreferencesFromUser(userID); // List some most-preferred items that would count as (most) "relevant" results double theRelevanceThreshold = Double.IsNaN(relevanceThreshold) ? computeThreshold(prefs) : relevanceThreshold; FastIDSet relevantItemIDs = dataSplitter.GetRelevantItemsIDs(userID, at, theRelevanceThreshold, dataModel); int numRelevantItems = relevantItemIDs.Count(); if (numRelevantItems <= 0) { continue; } FastByIDMap <IPreferenceArray> trainingUsers = new FastByIDMap <IPreferenceArray>(dataModel.GetNumUsers()); var it2 = dataModel.GetUserIDs(); while (it2.MoveNext()) { dataSplitter.ProcessOtherUser(userID, relevantItemIDs, trainingUsers, it2.Current, dataModel); } IDataModel trainingModel = dataModelBuilder == null ? new GenericDataModel(trainingUsers) : dataModelBuilder.BuildDataModel(trainingUsers); try { trainingModel.GetPreferencesFromUser(userID); } catch (NoSuchUserException nsee) { continue; // Oops we excluded all prefs for the user -- just move on } int size = numRelevantItems + trainingModel.GetItemIDsFromUser(userID).Count(); if (size < 2 * at) { // Really not enough prefs to meaningfully evaluate this user continue; } IRecommender recommender = recommenderBuilder.BuildRecommender(trainingModel); int intersectionSize = 0; var recommendedItems = recommender.Recommend(userID, at, rescorer); foreach (IRecommendedItem recommendedItem in recommendedItems) { if (relevantItemIDs.Contains(recommendedItem.GetItemID())) { intersectionSize++; } } int numRecommendedItems = recommendedItems.Count; // Precision if (numRecommendedItems > 0) { precision.AddDatum((double)intersectionSize / (double)numRecommendedItems); } // Recall recall.AddDatum((double)intersectionSize / (double)numRelevantItems); // Fall-out if (numRelevantItems < size) { fallOut.AddDatum((double)(numRecommendedItems - intersectionSize) / (double)(numItems - numRelevantItems)); } // nDCG // In computing, assume relevant IDs have relevance 1 and others 0 double cumulativeGain = 0.0; double idealizedGain = 0.0; for (int i = 0; i < numRecommendedItems; i++) { IRecommendedItem item = recommendedItems[i]; double discount = 1.0 / log2(i + 2.0); // Classical formulation says log(i+1), but i is 0-based here if (relevantItemIDs.Contains(item.GetItemID())) { cumulativeGain += discount; } // otherwise we're multiplying discount by relevance 0 so it doesn't do anything // Ideally results would be ordered with all relevant ones first, so this theoretical // ideal list starts with number of relevant items equal to the total number of relevant items if (i < numRelevantItems) { idealizedGain += discount; } } if (idealizedGain > 0.0) { nDCG.AddDatum(cumulativeGain / idealizedGain); } // Reach numUsersRecommendedFor++; if (numRecommendedItems > 0) { numUsersWithRecommendations++; } stopWatch.Stop(); log.Info("Evaluated with user {} in {}ms", userID, stopWatch.ElapsedMilliseconds); log.Info("Precision/recall/fall-out/nDCG/reach: {} / {} / {} / {} / {}", precision.GetAverage(), recall.GetAverage(), fallOut.GetAverage(), nDCG.GetAverage(), (double)numUsersWithRecommendations / (double)numUsersRecommendedFor); } return(new IRStatisticsImpl( precision.GetAverage(), recall.GetAverage(), fallOut.GetAverage(), nDCG.GetAverage(), (double)numUsersWithRecommendations / (double)numUsersRecommendedFor)); }