private SingleUserEvaluationResults GetSingleUserEvaluationResults <TInput, TRecommendation>( IRecommendationSource <TInput, IEnumerable <TRecommendation>, TRecommendation> recSource, TInput user, IUserInputClassifier <TInput> goodBadClassifier, Func <ClassifiedUserInput <TInput>, double, ItemsForInputAndEvaluation <TInput> > inputDivisionFunc, int numRecsToTryToGet) where TInput : IInputForUser where TRecommendation : IRecommendation { // Divide into liked and unliked. // Set aside a random X% of the liked and a random X% of the unliked ClassifiedUserInput <TInput> classified = goodBadClassifier.Classify(user); ItemsForInputAndEvaluation <TInput> divided = inputDivisionFunc(classified, FractionOfInputToSetAsideForEvaluation); // Get top N recommendations // Keep count of hits and false positives List <int> recommendedIds = new List <int>(); int truePositivesForThisUser = 0; int falsePositivesForThisUser = 0; int unknownsForThisUser = 0; foreach (TRecommendation recommendation in recSource.GetRecommendations(divided.ItemsForInput, numRecsToTryToGet)) { recommendedIds.Add(recommendation.ItemId); if (divided.LikedItemsForEvaluation.Contains(recommendation.ItemId)) { truePositivesForThisUser++; } else if (divided.UnlikedItemsForEvaluation.Contains(recommendation.ItemId)) { falsePositivesForThisUser++; } else { unknownsForThisUser++; } } int falseNegativesForThisUser = divided.LikedItemsForEvaluation.Count - truePositivesForThisUser; SingleUserEvaluationResults results = new SingleUserEvaluationResults() { TruePositives = truePositivesForThisUser, FalsePositives = falsePositivesForThisUser, Unknowns = unknownsForThisUser, FalseNegatives = falseNegativesForThisUser, }; return(results); }
public IPositiveFeedbackForUser AsPositiveFeedback(IUserInputClassifier <MalUserListEntries> classifier, Predicate <int> additionalOkToRecommendPredicate) { ClassifiedUserInput <MalUserListEntries> classified = classifier.Classify(this); HashSet <int> basicFeedback = new HashSet <int>(classified.Liked.Entries.Select(itemIdEntryPair => itemIdEntryPair.Key)); if (additionalOkToRecommendPredicate == null) { return(new BasicPositiveFeedbackForUserWithOkToRecommendPredicate(basicFeedback, ItemIsOkToRecommend)); } else { return(new BasicPositiveFeedbackForUserWithOkToRecommendPredicate(basicFeedback, (itemId) => ItemIsOkToRecommend(itemId) && additionalOkToRecommendPredicate(itemId))); } }
public static ItemsForInputAndEvaluation <MalUserListEntries> DivideClassifiedForInputAndEvaluation( ClassifiedUserInput <MalUserListEntries> classifiedInput, double fractionToSetAsideForEvaluation) { IDictionary <int, MalListEntry> entriesForInput = new Dictionary <int, MalListEntry>(); HashSet <int> likedAnimesForEvaluation = new HashSet <int>(); HashSet <int> unlikedAnimesForEvaluation = new HashSet <int>(); // Recommender could potentially use someone's "plan to watch" list to infer information about the user's taste...or something. foreach (KeyValuePair <int, MalListEntry> otherEntry in classifiedInput.Other.Entries) { entriesForInput.Add(otherEntry); } List <int> likedAnimeIds = new List <int>(classifiedInput.Liked.Entries.Keys); List <int> unlikedAnimeIds = new List <int>(classifiedInput.NotLiked.Entries.Keys); likedAnimeIds.Shuffle(); unlikedAnimeIds.Shuffle(); int numLikedForEvaluation = (int)(likedAnimeIds.Count * fractionToSetAsideForEvaluation); int numUnlikedForEvaluation = (int)(unlikedAnimeIds.Count * fractionToSetAsideForEvaluation); for (int i = 0; i < numLikedForEvaluation; i++) { likedAnimesForEvaluation.Add(likedAnimeIds[i]); } for (int i = numLikedForEvaluation; i < likedAnimeIds.Count; i++) { entriesForInput[likedAnimeIds[i]] = classifiedInput.Liked.Entries[likedAnimeIds[i]]; } for (int i = 0; i < numUnlikedForEvaluation; i++) { unlikedAnimesForEvaluation.Add(unlikedAnimeIds[i]); } for (int i = numUnlikedForEvaluation; i < unlikedAnimeIds.Count; i++) { entriesForInput[unlikedAnimeIds[i]] = classifiedInput.NotLiked.Entries[unlikedAnimeIds[i]]; } return(new ItemsForInputAndEvaluation <MalUserListEntries>() { ItemsForInput = new MalUserListEntries(entriesForInput, classifiedInput.Liked.AnimesEligibleForRecommendation, classifiedInput.Liked.MalUsername, classifiedInput.Liked.OkToRecommendPredicate), LikedItemsForEvaluation = likedAnimesForEvaluation, UnlikedItemsForEvaluation = unlikedAnimesForEvaluation }); }
public static ItemsForInputAndEvaluation<MalUserListEntries> DivideClassifiedForInputAndEvaluation( ClassifiedUserInput<MalUserListEntries> classifiedInput, double fractionToSetAsideForEvaluation) { IDictionary<int, MalListEntry> entriesForInput = new Dictionary<int, MalListEntry>(); HashSet<int> likedAnimesForEvaluation = new HashSet<int>(); HashSet<int> unlikedAnimesForEvaluation = new HashSet<int>(); // Recommender could potentially use someone's "plan to watch" list to infer information about the user's taste...or something. foreach (KeyValuePair<int, MalListEntry> otherEntry in classifiedInput.Other.Entries) { entriesForInput.Add(otherEntry); } List<int> likedAnimeIds = new List<int>(classifiedInput.Liked.Entries.Keys); List<int> unlikedAnimeIds = new List<int>(classifiedInput.NotLiked.Entries.Keys); likedAnimeIds.Shuffle(); unlikedAnimeIds.Shuffle(); int numLikedForEvaluation = (int)(likedAnimeIds.Count * fractionToSetAsideForEvaluation); int numUnlikedForEvaluation = (int)(unlikedAnimeIds.Count * fractionToSetAsideForEvaluation); for (int i = 0; i < numLikedForEvaluation; i++) { likedAnimesForEvaluation.Add(likedAnimeIds[i]); } for (int i = numLikedForEvaluation; i < likedAnimeIds.Count; i++) { entriesForInput[likedAnimeIds[i]] = classifiedInput.Liked.Entries[likedAnimeIds[i]]; } for (int i = 0; i < numUnlikedForEvaluation; i++) { unlikedAnimesForEvaluation.Add(unlikedAnimeIds[i]); } for (int i = numUnlikedForEvaluation; i < unlikedAnimeIds.Count; i++) { entriesForInput[unlikedAnimeIds[i]] = classifiedInput.NotLiked.Entries[unlikedAnimeIds[i]]; } return new ItemsForInputAndEvaluation<MalUserListEntries>() { ItemsForInput = new MalUserListEntries(entriesForInput, classifiedInput.Liked.AnimesEligibleForRecommendation, classifiedInput.Liked.MalUsername, classifiedInput.Liked.OkToRecommendPredicate), LikedItemsForEvaluation = likedAnimesForEvaluation, UnlikedItemsForEvaluation = unlikedAnimesForEvaluation }; }