This paper by Yifan Hu et al. introduces me to implicit feedback for recommender systems and I like the paper. Recall the Netflix problem where a subset of user ratings are revealed and we want to predict ratings. Where ratings are present, we call it an explicit dataset. In practice, what is more common is whether the user watched a movie or reserved a restaurant or clicked an ad. We only observe user interactions and such a dataset is an implicit dataset.
Advantage of an implicit dataset: More data is available in this form. Most users do not bother to give ratings.
Disadvantage of an implicit dataset: Data is harder to interpret. Unlike an explicit dataset, whenever a user-item pair is missing, we cannot be sure whether it is because the user hasn’t interacted with the item, or because the user does not like the item.
We will consider ALS (Alternating Least Squares) collaborative filtering. There are other methods for recommender engines, but ALS is what we will focus on for now. It is also known to perform well for users that have sufficiently interacted with the items. For relatively new users, content-based methods are more appropriate as they do not have to deal with the cold-start problem.
Objective function
First, recall the ALS method for the explicit dataset. Let be user rating between user u and item i. Minimize the RMSE loss:
Note that this first sum over u, i is over observed entries only. Also note that length of is the same, which is the number of “latent factors” in the model. Essentially, we are trying to approximate a matrix as a low rank matrix where are rows of respectively.
For the implicit dataset, is instead of the number of interactions between user u and item i. We introduce a new indicator variable which is 1 if and 0 otherwise. We want instead a row rank approximation of the boolean matrix . The ’s however are used as a confidence value:
where the confidence value or . Observe that most of ’s are equal to 1 as is mostly zero. This will be important later.
ALS modified for implicit
ALS works by fixing X, solving for Y and vice versa, repeatedly. For the explicit dataset, the solution for (for every user u) is
where is a vector of length equal to the number of items. Remember Y is a tall matrix. The number of rows is the number of items. The number of columns is the number of factors. This equation is the standard least squares solution. The solution for is unsurprisingly where is a vector of length equal to the number of users.
For an implicit dataset, we have to replace with the boolean matrix values . In addition, we need to bring in the confidence values. It can be shown that the solution for is
where is a square diagonal matrix. Its number of rows or columns is equal to the number of items. And its diagonal entry value is
Let f be the number of factors. Typically it is really small so the matrix inversion is really cheap. The computational bottleneck lies in computing and we need a computation trick. While is a very large matrix, most of its entries are equal to 1. In other words, if is a really sparse matrix. Hence, we evaluate as
The term can be computed just once and used for every user u. Say Y is a matrix and is the number of items. Then computing takes only which is small. For each user, computing takes where is the number of item-ratings user has. Summing over users, we have where is the support size of the interaction matrix . Including the matrix inversion, the overall running time for solving all ’s is equal to . This is linear with the support size, while fixing .
Solving for ’s is similar and we omit the details.
Remarks
Sparse, diagonal, low rank matrices are nice to work with, and so are linear combinations of them. Here we are using “diagonal + sparse”.
As of Dec 2018, Spark only supports ALS for implicit datasets/feedback. See for example this link. I guess the reason is that in practice, it is rare to find large explicit datasets that needs the brute force of Spark, whereas implicit datasets tend to be much bigger and common.