public override double GetEvaluation(IDictionary<User, ICollection<Preference>> testUserPrefs, Recommender recommender) { RunningAverage average = new FullRunningAverage(); foreach (KeyValuePair<User, ICollection<Preference>> entry in testUserPrefs) { foreach (Preference realPref in entry.Value) { User testUser = entry.Key; try { double estimatedPreference = recommender.EstimatePreference(testUser.ID, realPref.Item.ID); if (!double.IsNaN(estimatedPreference)) { double diff = realPref.Value - estimatedPreference; average.AddDatum(diff * diff); } } catch (NoSuchElementException nsee) { // It's possible that an item exists in the test data but not training data in which case // NSEE will be thrown. Just ignore it and move on. log.Info("Element exists in test data but not training data: " + testUser.ID, nsee); } } } return Math.Sqrt(average.Average); }
public IRStatistics Evaluate(RecommenderBuilder recommenderBuilder, DataModel dataModel, int at, double relevanceThreshold, double evaluationPercentage) { if (recommenderBuilder == null) { throw new ArgumentNullException("recommenderBuilder is null"); } if (dataModel == null) { throw new ArgumentNullException("dataModel is null"); } if (at < 1) { throw new ArgumentException("at must be at least 1"); } if (double.IsNaN(evaluationPercentage) || evaluationPercentage <= 0.0 || evaluationPercentage > 1.0) { throw new ArgumentException("Invalid evaluationPercentage: " + evaluationPercentage); } if (double.IsNaN(relevanceThreshold)) { throw new ArgumentException("Invalid relevanceThreshold: " + evaluationPercentage); } RunningAverage precision = new FullRunningAverage(); RunningAverage recall = new FullRunningAverage(); foreach (User user in dataModel.GetUsers()) { Object id = user.ID; if (random.NextDouble() < evaluationPercentage) { ICollection<Item> relevantItems = new HashedSet<Item>(/* at */); Preference[] prefs = user.GetPreferencesAsArray(); foreach (Preference pref in prefs) { if (pref.Value >= relevanceThreshold) { relevantItems.Add(pref.Item); } } int numRelevantItems = relevantItems.Count; if (numRelevantItems > 0) { ICollection<User> trainingUsers = new List<User>(dataModel.GetNumUsers()); foreach (User user2 in dataModel.GetUsers()) { if (id.Equals(user2.ID)) { ICollection<Preference> trainingPrefs = new List<Preference>(); prefs = user2.GetPreferencesAsArray(); foreach (Preference pref in prefs) { if (!relevantItems.Contains(pref.Item)) { trainingPrefs.Add(pref); } } if (trainingPrefs.Count > 0) { User trainingUser = new GenericUser<String>(id.ToString(), trainingPrefs); trainingUsers.Add(trainingUser); } } else { trainingUsers.Add(user2); } } DataModel trainingModel = new GenericDataModel(trainingUsers); Recommender recommender = recommenderBuilder.BuildRecommender(trainingModel); try { trainingModel.GetUser(id); } catch (NoSuchElementException) { continue; // Oops we excluded all prefs for the user -- just move on } int intersectionSize = 0; foreach (RecommendedItem recommendedItem in recommender.Recommend(id, at)) { if (relevantItems.Contains(recommendedItem.Item)) { intersectionSize++; } } precision.AddDatum((double) intersectionSize / (double) at); recall.AddDatum((double) intersectionSize / (double) numRelevantItems); } } } return new IRStatisticsImpl(precision.Average, recall.Average); }