[Test()] public void TestGetEntriesByRow() { var matrix = new SparseBooleanMatrix(); for (int i = 0; i < 5; i++) if (i != 2 && i !=3) { matrix[i, 1] = true; matrix[i, 4] = true; } Assert.AreEqual(2, matrix.GetEntriesByRow(0).Count); Assert.AreEqual(2, matrix.GetEntriesByRow(1).Count); Assert.AreEqual(0, matrix.GetEntriesByRow(2).Count); Assert.AreEqual(0, matrix.GetEntriesByRow(3).Count); Assert.AreEqual(2, matrix.GetEntriesByRow(4).Count); }
/// <summary>Evaluation for rankings of items recommended to groups</summary> /// <remarks> /// </remarks> /// <param name="recommender">group recommender</param> /// <param name="test">test cases</param> /// <param name="train">training data</param> /// <param name="group_to_user">group to user relation</param> /// <param name="candidate_items">a collection of integers with all candidate items</param> /// <param name="ignore_overlap">if true, ignore items that appear for a group in the training set when evaluating for that user</param> /// <returns>a dictionary containing the evaluation results</returns> public static ItemRecommendationEvaluationResults Evaluate( this GroupRecommender recommender, IPosOnlyFeedback test, IPosOnlyFeedback train, SparseBooleanMatrix group_to_user, ICollection<int> candidate_items, bool ignore_overlap = true) { var result = new ItemRecommendationEvaluationResults(); int num_groups = 0; foreach (int group_id in group_to_user.NonEmptyRowIDs) { var users = group_to_user.GetEntriesByRow(group_id); var correct_items = new HashSet<int>(); foreach (int user_id in users) correct_items.UnionWith(test.UserMatrix[user_id]); correct_items.IntersectWith(candidate_items); var candidate_items_in_train = new HashSet<int>(); foreach (int user_id in users) candidate_items_in_train.UnionWith(train.UserMatrix[user_id]); candidate_items_in_train.IntersectWith(candidate_items); int num_eval_items = candidate_items.Count - (ignore_overlap ? candidate_items_in_train.Count() : 0); // skip all groups that have 0 or #candidate_items test items if (correct_items.Count == 0) continue; if (num_eval_items - correct_items.Count == 0) continue; IList<int> prediction_list = recommender.RankItems(users, candidate_items); if (prediction_list.Count != candidate_items.Count) throw new Exception("Not all items have been ranked."); var ignore_items = ignore_overlap ? candidate_items_in_train : new HashSet<int>(); double auc = AUC.Compute(prediction_list, correct_items, ignore_items); double map = PrecisionAndRecall.AP(prediction_list, correct_items, ignore_items); double ndcg = NDCG.Compute(prediction_list, correct_items, ignore_items); double rr = ReciprocalRank.Compute(prediction_list, correct_items, ignore_items); var positions = new int[] { 5, 10 }; var prec = PrecisionAndRecall.PrecisionAt(prediction_list, correct_items, ignore_items, positions); var recall = PrecisionAndRecall.RecallAt(prediction_list, correct_items, ignore_items, positions); // thread-safe incrementing lock(result) { num_groups++; result["AUC"] += (float) auc; result["MAP"] += (float) map; result["NDCG"] += (float) ndcg; result["MRR"] += (float) rr; result["prec@5"] += (float) prec[5]; result["prec@10"] += (float) prec[10]; result["recall@5"] += (float) recall[5]; result["recall@10"] += (float) recall[10]; } if (num_groups % 1000 == 0) Console.Error.Write("."); if (num_groups % 60000 == 0) Console.Error.WriteLine(); } result["num_groups"] = num_groups; result["num_lists"] = num_groups; result["num_items"] = candidate_items.Count; return result; }