3 Approaches To Building A Recommendation System | by Kurtis Pykes | Towards Data Science

It’s no doubt that Recommendation systems are one of the most obvious ways to enhance user experience on various platforms, as well as introduce Machine Learning into a company. Hence, many companies have been adopting the “Recommended For You” mantra that has been popularized by the likes of Amazon, Netflix and Youtube by implementing there own version of recommendations to suit their customer needs.
Before heading on to the various approaches of implementation, we first define a recommendation system as a method of discarding redundant or useless information from an information stream before presenting the information to a human user, or more specifically, as a subclass of an information filtering system that seeks to predict the “rating” or “preference” a user will give to an item (Source: Wikipedia).
With this knowledge we may begin to look at some approaches to this problem — for the full code generated in this post visit my Github.
github.com
For the following demonstrations, we will be using the MovieLens 100k Dataset.
Collaborative filtering is one of the most popular implementations for Recommendation engines and is based on the assumption that people that were in agreement in the past will be in agreement in the future, and as a result they will like similar kinds of items as they liked in the past.
An example of Collaborative filtering may be that a friend and myself liked an identical range of books in the past and he/she goes on to like a book that I have not read, but because we agreed in the past and he/she liked the new book of which I have not read, it is highly likely I will also like that book so that book would recommended to me. The logic describes what is known as user-based collaborative filtering.
Taking from the previous example, instead of focusing solely on what my friend likes, we may decide to focus on the range of items liked previously and ensure I am recommended a new item based on the similarity between the items that have been liked in the past of which the similarity is calculated by using the ratings of the items — “users that like this item also liked”. The logic behind this algorithm is known as item-based collaborative filtering.
In all, these two methods fall under a heading of collaborative filtering known as memory based methods. Let’s see an example of a memory based method in Python.
import numpy as npimport pandas as pdfrom sklearn.metrics import mean_squared_error, pairwise# creating n x m matrix where n is user_id and m is item_id user_ratings = pd.pivot_table(rating, index="user_id", columns="item_id", values="rating").fillna(0)# user and item counts n_users = len(user_ratings.index)n_items = len(user_ratings.columns)print(f"Users: {n_users}\nItems: {n_items}")user_ratings.head()Users: 943Items: 1682
Now we have our data in the format we need, I will randomly generate a train and test set that we can use to test how well our approach is doing.
# https://www.ethanrosenthal.com/2015/11/02/intro-to-collaborative-filtering/ def train_test_split(data: np.array, n_users: int, n_items:int):     # create a empty array of shape n x m for test    test = np.zeros((n_users, n_items))    train = data.copy()        # for each user, we generate a random sample of 5 from movies they've watched    for user in range(n_users):        random_sample = np.random.choice(data[user, :].nonzero()[0],                                          size=5,                                          replace=False)        # set the train to zero to represent no rating and the test will be the original rating        train[user, random_sample] = 0.         test[user, random_sample] = data[user, random_sample]            return train, testtrain, test = train_test_split(data=user_ratings.to_numpy(), n_users=n_users, n_items=n_items)
The first step of building a Collaborative filtering system is to calculate the similarity between users (for user based) or items (for item based).
user_similarity = pairwise.cosine_similarity(train + 1e-9)item_similarity = pairwise.cosine_similarity(train.T + 1e-9)print(user_similarity.shape, item_similarity.shape)(943, 943) (1682, 1682)
The next step is to predict the ratings that were not included in the data. Once we have made our predictions, we can compare our results with that of the actual test data to evaluate the quality of our model — evaluation metrics are beyond the scope of this tutorial.
# predict user ratings not included in datauser_preds = user_similarity.dot(train) / np.array([np.abs(user_similarity).sum(axis=1)]).T# # get the nonzero elementsnonzero_test = test[test.nonzero()]nonzero_user_preds = user_preds[test.nonzero()]user_rating_preds = mean_squared_error(nonzero_test, nonzero_user_preds)print(f"UBCF Mean Squared Error: {user_rating_preds}")UBCF Mean Squared Error: 8.250006012927786
The above code is an example of User-Based collaborative filtering. We can also do Item-based collaborative filtering.
# predict item ratings not included in dataitem_preds = train.dot(item_similarity) / np.array([np.abs(item_similarity).sum(axis=1)])# get the nonzero elementsnonzero_item_preds = item_preds[test.nonzero()]item_rating_preds = mean_squared_error(nonzero_test, nonzero_item_preds)print(f"IBCF Mean Squared Error: {item_rating_preds}")IBCF Mean Squared Error: 11.361431844412557
Our algorithm isn’t that great, but hopefully you get the gist!
We now know that Collaborative based approaches may be classified is memory-based and we’ve seen a Python implementation of this above. Another way we may classify a collaborative filtering method is as a model based approach.
In this approach, models are developed using different data mining, machine learning algorithms to predict users’ rating of unrated items (Source: Wikipedia).
Another popular way to recommend useful information to users is via Content-based filtering. This technique is based on the description of the item and a profile of the users preferences. It’s best suited in situations where there is known information on an item, but not much known information of the user. That being so, the Content-based filtering approach teats recommendations as a user specific classification problem.
An example of content-based filtering could be explained by using a movie recommendation scenario. Imagine we have built a fairly new site and we don’t currently have much user information, but what we do have is details about the movies in our backlog. What we’d do is take the meta-data/characteristics of the movie such as genre, actors, directors, length of the movie, etc and use them as inputs to predict whether a user would like a movie.
The scenario above would also suggest we have a user profile of preferences. This data may be collected via user interrogation — meaning that the user would set his or her preferences for filtering — or by recording user behavior as an implicit approach.
Note: You may also use a hybrid method for an optimal data collection strategy.
Let’s see how to do this in Python...
# merge data so we know the features of each moviemovies = pd.merge(item, rating, right_on="item_id", left_on="movie_id")# create a pivot tablemovies_pivot = pd.pivot_table(movies, index="user_id", columns="movie_title", values="rating")# Transpose only so it fit's in the screenmovies_pivot.T.head()
# avg ratings and rating countsavg_rating = movies.groupby("movie_title")["rating"].mean()num_ratings = movies.groupby("movie_title")["rating"].count()# getting counts and average ratingsratings_counts = pd.DataFrame({"avg_rating": avg_rating,                               "num_of_ratings": num_ratings})# joining the new values to movie datafull_movie_data = pd.merge(movies, ratings_counts, left_on="movie_title", right_index=True)# https://towardsdatascience.com/recommender-system-in-python-part-2-content-based-system-693a0e4bb306def get_similar_movies(full_movie_data: pd.DataFrame,                       movie_matrix: pd.DataFrame,                       movie_title: str,                       min_num_of_ratings: int = 100,                       n_recommendations: int = 5                       ):    """    Get similar movies based on correlation with other movies     """    # get most correlated movies    similar_movies = movie_matrix.corrwith(movie_matrix[movie_title])    # converting to a dataframe and dropping NaN's    similar_corr_df = pd.DataFrame({"correlation":similar_movies})    similar_corr_df.dropna(inplace=True)        # store the oringinal dataframe    orig = full_movie_data.copy()        # merge with correlated dataframe but only keep specified columns    corr_with_movie = pd.merge(left=similar_corr_df,                               right=orig,                                on="movie_title")[        ["movie_title", "correlation", "avg_rating", "num_of_ratings"]].drop_duplicates().reset_index(drop=True)        # filter movies with less than min_num_of_ratings    result = corr_with_movie[corr_with_movie['num_of_ratings'] > min_num_of_ratings].sort_values(                                                                                     by='correlation',                                                                                     ascending=False)    return result.iloc[1:, :].head()# test function on Toy Storyget_similar_movies(full_movie_data, movies_pivot, "Toy Story (1995)")
A hybrid system is much more common in the real world as a combining components from various approaches can overcome various traditional shortcomings; In this example we talk more specifically of hybrid components from Collaborative-Filtering and Content-based filtering.
The paper by Jung KY, Park DH, Lee JH (2004) [1] states “To be effective, a recommender system must deal with well with two fundamental problems. First, the sparse rating problem; the number of ratings already obtained is very small compared to the number of ratings that need to be predicted. Effective generation from a small number of examples is thus important. This problem is particularly severe during the startup phase of the system when the number of users is small. Second, the first-rater problem; an item cannot be recommended unless a user has rated it before.”
This approach can significantly improve predictions of a recommender system.
As a task to the reader, build your own hybrid recommender system! (Share with me when you’ve done it)
[1] Jung KY., Park DH., Lee JH. (2004) Hybrid Collaborative Filtering and Content-Based Filtering for Improved Recommender System. In: Bubak M., van Albada G.D., Sloot P.M.A., Dongarra J. (eds) Computational Science — ICCS 2004. ICCS 2004. Lecture Notes in Computer Science, vol 3036. Springer, Berlin, Heidelberg. https://doi.org/10.1007/978-3-540-24685-5_37
In this post we covered 3 practical ways of approaching recommendation systems and how to implement 2 of them (Collaborative Filtering and Content Based) using Python. I am aware that I did not go into much details regarding the theory behind the algorithms or performance metrics to evaluate them, but if you’d like a more in-depth insight to these feats then I highly recommend the Andrew Ng Recommender Systems playlist on Youtube.
Let’s continue the conversation on LinkedIn...