/// <summary> /// Iterate over the training data, uniformly sample from users with replacement. /// TODO /// </summary> protected virtual void IterateWithReplacementUniformUser(List <Rating> ratings, MyTable ratingTable, double gamma = 0.01, double lambda = 0.01, double lambda_bias = 0.01) { int[] userIds = ratingTable.GetMainKeyArray().AsParallel().Cast <int>().OrderBy(k => k).ToArray(); int[] itemIds = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().OrderBy(k => k).ToArray(); var random = Core.Random.GetInstance(); int numberOfRatings = ratings.Count; int userId, itemId, otherItemId; for (int i = 0; i < numberOfRatings; i++) { while (true) { // randomly select a user userId = userIds[random.Next(userIds.Length)]; Hashtable itemsTable = (Hashtable)ratingTable[userId]; // copy Hashtable itemsTableCopy = new Hashtable(itemsTable); // bugs,2018.02.13 var triple = SampleItemPair(userId, itemsTable, itemIds, random); itemId = triple.Item2; otherItemId = triple.Item3; break; } UpdateFactors(userId, itemId, otherItemId, gamma, lambda, lambda_bias); } }
/// <summary> /// Get recommendations based on the trained model? /// </summary> /// <param name="ratingTable"></param> /// <param name="N"></param> /// <returns></returns> protected List <Rating> GetRecommendations(MyTable ratingTable, int N = 10) { List <Rating> recommendedItems = new List <Rating>(); var itemIds = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().ToArray(); var userIds = ratingTable.GetMainKeyArray().AsParallel().Cast <int>().ToArray(); Parallel.ForEach(userIds, userId => { Hashtable Nu = (Hashtable)ratingTable[userId]; // ratings of user u List <Rating> predictedRatings = new List <Rating>(); foreach (int itemId in itemIds) { if (!Nu.ContainsKey(itemId)) { double p = Predict(userId, itemId); predictedRatings.Add(new Rating(userId, itemId, p)); } } List <Rating> sortedLi = predictedRatings.OrderByDescending(r => r.Score).ToList(); lock (recommendedItems) { recommendedItems.AddRange(sortedLi.GetRange(0, Math.Min(sortedLi.Count, N))); } }); return(recommendedItems); }
/// <summary> /// Randomly sample negative ratings for each user from his/her rated ratings. /// Recommender systems in action, p84, vector xiang /// </summary> /// <param name="ratings">positive ratings</param> /// <param name="ratio">ratio = #(negative samples) / #(positive samples)</param> /// <param name="verbose"></param> /// <returns></returns> public static List <Rating> RandomSelectNegativeSamples(List <Rating> ratings, int ratio = 1, bool verbose = false) { if (verbose) { Console.WriteLine("ratio,{0}", ratio); } List <Rating> positiveRatings = new List <Rating>(); foreach (Rating r in ratings) { positiveRatings.Add(new Rating(r.UserId, r.ItemId, 1.0)); } MyTable ratingTable = GetRatingTable(positiveRatings); int[] items = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().ToArray(); var random = Core.Random.GetInstance(); foreach (int uId in ratingTable.Keys) { Hashtable subTable = (Hashtable)ratingTable[uId]; int counter = 0, ratedItems = subTable.Count; while ((counter < ratedItems * ratio) && (counter < items.Length - ratedItems)) { int iId = items[random.Next(items.Length)]; if (!subTable.ContainsKey(iId)) { subTable.Add(iId, 0.0); // negative samples counter++; } } } List <Rating> samples = new List <Rating>(); foreach (int uId in ratingTable.Keys) { Hashtable subTable = (Hashtable)ratingTable[uId]; foreach (int iId in subTable.Keys) { double score = (double)subTable[iId]; samples.Add(new Rating(uId, iId, score)); } } return(samples); }
protected List <Rating> GetRecommendations(MyTable ratingTable, double miu, int N = 10, bool multiThread = false) { List <Rating> recommendedItems = new List <Rating>(); int[] subKeys = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().ToArray(); if (multiThread) { int[] mainKeys = ratingTable.GetMainKeyArray().AsParallel().Cast <int>().ToArray(); Parallel.ForEach(mainKeys, userId => { Hashtable Nu = (Hashtable)ratingTable[userId]; // ratings of user u List <Rating> predictedRatings = new List <Rating>(); foreach (int itemId in subKeys) { if (!Nu.ContainsKey(itemId)) { double p = Predict(userId, itemId, miu); predictedRatings.Add(new Rating(userId, itemId, p)); } } List <Rating> sortedLi = predictedRatings.OrderByDescending(r => r.Score).ToList(); lock (recommendedItems) { recommendedItems.AddRange(sortedLi.GetRange(0, Math.Min(sortedLi.Count, N))); } }); } else { foreach (int userId in ratingTable.Keys) { Hashtable Nu = (Hashtable)ratingTable[userId]; // ratings of user u List <Rating> predictedRatings = new List <Rating>(); foreach (int itemId in subKeys) { if (!Nu.ContainsKey(itemId)) { double p = Predict(userId, itemId, miu); predictedRatings.Add(new Rating(userId, itemId, p)); } } List <Rating> sortedLi = predictedRatings.OrderByDescending(r => r.Score).ToList(); recommendedItems.AddRange(sortedLi.GetRange(0, Math.Min(sortedLi.Count, N))); } } return(recommendedItems); }
/// <summary> /// Iterate over the training data, uniformly sample from user-item pairs without replacement. /// </summary> protected virtual void IterateWithoutReplacementUniformPair(MyTable ratingTable, double gamma = 0.01, double lambda = 0.01, double lambda_bias = 0.01) { int[] itemIds = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().OrderBy(k => k).ToArray(); var random = Core.Random.GetInstance(); // need to be a static member? foreach (int userId in ratingTable.Keys) { Hashtable itemsTable = (Hashtable)ratingTable[userId]; foreach (int itemId in itemsTable.Keys) { // 1. sample a negative feedback for each positive feedback int otherItemId = SampleOtherItemId(userId, itemsTable, itemIds, random); UpdateFactors(userId, itemId, otherItemId, gamma, lambda, lambda_bias); } } }
/// <summary> /// /// </summary> /// <param name="ratingTable"></param> /// <param name="ratio"></param> /// <returns>list of triples: user id - item id - other item id</returns> protected List <Tuple <int, int, int> > SampleTriples(MyTable ratingTable, int ratio = 100) { int[] userIds = ratingTable.GetMainKeyArray().AsParallel().Cast <int>().OrderBy(k => k).ToArray(); int[] itemIds = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().OrderBy(k => k).ToArray(); List <Tuple <int, int, int> > list = new List <Tuple <int, int, int> >(); var random = Core.Random.GetInstance(); // need to be a static member? for (int i = 0; i < userIds.Length * ratio; i++) { // randomly select a user int userId = userIds[random.Next(userIds.Length)]; Hashtable itemsTable = (Hashtable)ratingTable[userId]; var triple = SampleItemPair(userId, itemsTable, itemIds, random); list.Add(triple); } return(list); }
/// <summary> /// Iterate over the training data, uniformly sample from user-item pairs with replacement. /// </summary> protected virtual void IterateWithReplacementUniformPair(List <Rating> ratings, MyTable ratingTable, double gamma = 0.01, double lambda = 0.01, double lambda_bias = 0.01) { int[] itemIds = ratingTable.GetSubKeyArray().AsParallel().Cast <int>().OrderBy(k => k).ToArray(); var random = Core.Random.GetInstance(); int numberOfRatings = ratings.Count; for (int ii = 0; ii < numberOfRatings; ii++) { Rating r = ratings[random.Next(numberOfRatings)]; int userId = r.UserId; int itemId = r.ItemId; Hashtable itemsTable = (Hashtable)ratingTable[userId]; // 1. sample a negative feedback for each positive feedback int otherItemId = SampleOtherItemId(userId, itemsTable, itemIds, random); UpdateFactors(userId, itemId, otherItemId, gamma, lambda, lambda_bias); } }