package edu.umn.cs.recsys.ii; import org.grouplens.lenskit.basic.AbstractItemScorer; import org.grouplens.lenskit.data.dao.UserEventDAO; import org.grouplens.lenskit.data.event.Rating; import org.grouplens.lenskit.data.history.History; import org.grouplens.lenskit.data.history.RatingVectorUserHistorySummarizer; import org.grouplens.lenskit.data.history.UserHistory; import org.grouplens.lenskit.knn.NeighborhoodSize; import org.grouplens.lenskit.scored.ScoredId; import org.grouplens.lenskit.vectors.MutableSparseVector; import org.grouplens.lenskit.vectors.SparseVector; import org.grouplens.lenskit.vectors.VectorEntry; import javax.annotation.Nonnull; import javax.inject.Inject; import java.util.List; import java.util.Map; /** * @author <a href="http://www.grouplens.org">GroupLens Research</a> */ public class SimpleItemItemScorer extends AbstractItemScorer { private final SimpleItemItemModel model; private final UserEventDAO userEvents; private final int neighborhoodSize; @Inject public SimpleItemItemScorer(SimpleItemItemModel m, UserEventDAO dao, @NeighborhoodSize int nnbrs) { model = m; userEvents = dao; neighborhoodSize = nnbrs; } /** * Score items for a user. * @param user The user ID. * @param scores The score vector. Its key domain is the items to score, and the scores * (rating predictions) should be written back to this vector. */ @Override public void score(long user, @Nonnull MutableSparseVector scores) { SparseVector ratings = getUserRatingVector(user); for (VectorEntry e: scores.fast(VectorEntry.State.EITHER)) { long item = e.getKey(); List<ScoredId> neighbors = model.getNeighbors(item); int nghbrCount = 0; double numerator = 0, denominator = 0; for(ScoredId thisNghbr : neighbors){ if(nghbrCount < neighborhoodSize){ if (!ratings.containsKey(thisNghbr.getId())) continue; double thisItemRating = ratings.get(thisNghbr.getId()); double thisItemSimilarity = thisNghbr.getScore(); numerator += thisItemRating * thisItemSimilarity; denominator += thisItemSimilarity; nghbrCount++; } } scores.set(item, numerator/denominator); } } /** * Get a user's ratings. * @param user The user ID. * @return The ratings to retrieve. */ private SparseVector getUserRatingVector(long user) { UserHistory<Rating> history = userEvents.getEventsForUser(user, Rating.class); if (history == null) { history = History.forUser(user); } return RatingVectorUserHistorySummarizer.makeRatingVector(history); } }