public override void RemovePreference(long userID, long itemID) { IDataModel dataModel = GetDataModel(); float? oldPref = dataModel.GetPreferenceValue(userID, itemID); base.RemovePreference(userID, itemID); if (oldPref.HasValue) { lock (this) { //buildAveragesLock.writeLock().lock(); IRunningAverage itemAverage = itemAverages.Get(itemID); if (itemAverage == null) { throw new InvalidOperationException("No preferences exist for item ID: " + itemID); } itemAverage.RemoveDatum(oldPref.Value); IRunningAverage userAverage = userAverages.Get(userID); if (userAverage == null) { throw new InvalidOperationException("No preferences exist for user ID: " + userID); } userAverage.RemoveDatum(oldPref.Value); overallAveragePrefValue.RemoveDatum(oldPref.Value); }/* finally { * buildAveragesLock.writeLock().unlock(); * }*/ } }
public override void SetPreference(long userID, long itemID, float value) { IDataModel dataModel = GetDataModel(); double prefDelta; try { float?oldPref = dataModel.GetPreferenceValue(userID, itemID); prefDelta = !oldPref.HasValue ? value : value - oldPref.Value; } catch (NoSuchUserException nsee) { prefDelta = value; } base.SetPreference(userID, itemID, value); lock (this) { //buildAveragesLock.writeLock().lock(); IRunningAverage average = itemAverages.Get(itemID); if (average == null) { IRunningAverage newAverage = new FullRunningAverage(); newAverage.AddDatum(prefDelta); itemAverages.Put(itemID, newAverage); } else { average.ChangeDatum(prefDelta); } } //finally { //buildAveragesLock.writeLock().unlock(); //} }
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 float EstimatePreference(long userID, long itemID) { IDataModel dataModel = GetDataModel(); float? actualPref = dataModel.GetPreferenceValue(userID, itemID); if (actualPref.HasValue) { return(actualPref.Value); } return(doEstimatePreference(userID, itemID)); }
public override float EstimatePreference(long userID, long itemID) { IDataModel model = GetDataModel(); float? actualPref = model.GetPreferenceValue(userID, itemID); if (actualPref.HasValue) { return(actualPref.Value); } long[] theNeighborhood = neighborhood.GetUserNeighborhood(userID); return(doEstimatePreference(userID, theNeighborhood, itemID)); }
protected virtual float doEstimatePreference(long theUserID, long[] theNeighborhood, long itemID) { if (theNeighborhood.Length == 0) { return(float.NaN); } IDataModel dataModel = GetDataModel(); double preference = 0.0; double totalSimilarity = 0.0; int count = 0; foreach (long userID in theNeighborhood) { if (userID != theUserID) { // See GenericItemBasedRecommender.doEstimatePreference() too float?pref = dataModel.GetPreferenceValue(userID, itemID); if (pref.HasValue) { double theSimilarity = similarity.UserSimilarity(theUserID, userID); if (!Double.IsNaN(theSimilarity)) { preference += theSimilarity * pref.Value; totalSimilarity += theSimilarity; count++; } } } } // Throw out the estimate if it was based on no data points, of course, but also if based on // just one. This is a bit of a band-aid on the 'stock' item-based algorithm for the moment. // The reason is that in this case the estimate is, simply, the user's rating for one item // that happened to have a defined similarity. The similarity score doesn't matter, and that // seems like a bad situation. if (count <= 1) { return(float.NaN); } float estimate = (float)(preference / totalSimilarity); if (capper != null) { estimate = capper.capEstimate(estimate); } return(estimate); }
public override Factorization Factorize() { prepareTraining(); double currentLearningRate = learningRate; for (int it = 0; it < numIterations; it++) { for (int index = 0; index < cachedUserIDs.Length; index++) { long userId = cachedUserIDs[index]; long itemId = cachedItemIDs[index]; float?rating = dataModel.GetPreferenceValue(userId, itemId); updateParameters(userId, itemId, rating.Value, currentLearningRate); } currentLearningRate *= learningRateDecay; } return(createFactorization(userVectors, itemVectors)); }
public virtual float?GetPreferenceValue(long userID, long itemID) { if (userID == TEMP_USER_ID) { if (tempPrefs == null) { throw new NoSuchUserException(TEMP_USER_ID); } for (int i = 0; i < tempPrefs.Length(); i++) { if (tempPrefs.GetItemID(i) == itemID) { return(tempPrefs.GetValue(i)); } } return(null); } return(_delegate.GetPreferenceValue(userID, itemID)); }
public void testPreferenceShufflerWithSyntheticData() { setUpSyntheticData(); ParallelSGDFactorizer.PreferenceShuffler shuffler = new ParallelSGDFactorizer.PreferenceShuffler(dataModel); shuffler.shuffle(); shuffler.stage(); FastByIDMap <FastByIDMap <bool?> > checkedLst = new FastByIDMap <FastByIDMap <bool?> >(); for (int i = 0; i < shuffler.size(); i++) { IPreference pref = shuffler.get(i); float?value = dataModel.GetPreferenceValue(pref.GetUserID(), pref.GetItemID()); Assert.AreEqual(pref.GetValue(), value.Value, 0.0); if (!checkedLst.ContainsKey(pref.GetUserID())) { checkedLst.Put(pref.GetUserID(), new FastByIDMap <bool?>()); } Assert.IsNull(checkedLst.Get(pref.GetUserID()).Get(pref.GetItemID())); checkedLst.Get(pref.GetUserID()).Put(pref.GetItemID(), true); } var userIDs = dataModel.GetUserIDs(); int index = 0; while (userIDs.MoveNext()) { long userID = userIDs.Current; IPreferenceArray preferencesFromUser = dataModel.GetPreferencesFromUser(userID); foreach (IPreference preference in preferencesFromUser) { Assert.True(checkedLst.Get(preference.GetUserID()).Get(preference.GetItemID()).Value); index++; } } Assert.AreEqual(index, shuffler.size()); }
/// This computation is in a technical sense, wrong, since in the domain of "bool preference users" where /// all preference values are 1, this method should only ever return 1.0 or NaN. This isn't terribly useful /// however since it means results can't be ranked by preference value (all are 1). So instead this returns a /// sum of similarities to any other user in the neighborhood who has also rated the item. protected override float doEstimatePreference(long theUserID, long[] theNeighborhood, long itemID) { if (theNeighborhood.Length == 0) { return(float.NaN); } IDataModel dataModel = GetDataModel(); IUserSimilarity similarity = getSimilarity(); float totalSimilarity = 0.0f; bool foundAPref = false; foreach (long userID in theNeighborhood) { // See GenericItemBasedRecommender.doEstimatePreference() too if (userID != theUserID && dataModel.GetPreferenceValue(userID, itemID) != null) { foundAPref = true; totalSimilarity += (float)similarity.UserSimilarity(theUserID, userID); } } return(foundAPref ? totalSimilarity : float.NaN); }
public override float?GetPreferenceValue(long userID, long itemID) { return(_delegate.GetPreferenceValue(userID, itemID)); }