How to Build a Restaurant Recommendation System Using Latent Factor Collaborative Filtering | by Theo Jeremiah | Towards Data Science

I usually watch youtube when I am taking a break from my work. I commit to myself to watch Youtube only for 5 to 10 minutes to rest my mind. Here is what usually happens, after I finished watching one video, the next video pops out from Youtube recommendations and I click on that video. When I take a look again at my watch, it turns out that I have been watching Youtube for more than an hour! :’)
Youtube’s recommendation system is one of the most powerful and complex recommendation systems that can keep its users to watch Youtube videos for hours. Many startups giants like Netflix, Youtube, and Amazon revenues are driven mostly from the recommendation systems that they build.
This article focuses on how to build a restaurant recommendation system using latent factor collaborative filtering from scratch.
Recommender Systems or Recommendation Systems are simple algorithms that aim to provide the most relevant and accurate items (products, movies, events, articles) to the user (customers, visitors, app users, readers) by filtering useful stuff from a huge pool of information base. Recommendation engines discover data patterns in the data set by learning consumers’ choices and produces the outcomes that co-relates to their needs and interests.
Imagine a physical clothing store. The good merchant knows the personal preferences of customers. Her/His high-quality recommendations make customers satisfied and increase profits. In the case of picking a restaurant to have lunch or dinner when you are traveling to other countries or cities, commonly you will ask your friend that lives in that country or city what is the best restaurant in town. The problem is you don’t have any friends that lived in that town. Your personal recommendations can be generated by an artificial friend: the recommender system.
There are various types of Recommendation systems but for this restaurant recommendation system that I build. I focused on using Matrix Factorization or Latent Factor Collaborative Filtering. Let’s start with the term Factorization.
When we think about factorization, it is a similar concept as six times four equals twenty-four. Twenty-four is a large number but we express it as a product of two small numbers six and four, so we manage to break down a big number into a product of two small ones. This similar concept is applied to Matrix Factorization.
A Recommendation System is an information filtering system that seeks to predict the rating a user would give for the item (in this case a restaurant). We can break down the large matrix of ratings from users and items into two smaller matrixes of user-feature and item-feature. For example, user A loves to eat hotdogs but hates to eat pizza and restaurant P have great hotdogs, we multiply the matrixes using dot product and the result will be the ratings (in the example above will be 11).
Let’s start building a Restaurant Recommendation System using the techniques discussed above which should be capable of recommending restaurants that best suits you.
We will use Yelp restaurant data that can be downloaded from here.
Yelp is a business directory service and crowd-sourced review forum. The company develops, hosts and markets the Yelp.com website and the Yelp mobile app, which publish crowd-sourced reviews about businesses. It also operates an online reservation service called Yelp Reservations.
Yelp attempted to solve the problem “What should I eat?” This quickly expanded to include other business to answer other questions. This can best be represented as “I’m in [town]. Where can I go to get the [best/fastest/cheapest/easiest] [food/service/etc]?” Your friend’s recommendations are likely the largest influencer of where you will go if you have no preference. Yelp provided a service for when that was either not available or not trusted.
Let’s start by importing all the packages that we needed throughout the notebook.
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.model_selection import train_test_splitfrom sklearn.feature_extraction.text import TfidfVectorizerfrom nltk.corpus import stopwords from nltk.tokenize import WordPunctTokenizer
Now we import the dataset, we use the review dataset and business dataset.
df = pd.read_csv('yelp_review_arizona.csv')df_business = pd.read_csv('yelp_business.csv')df.head()
We need to clean up the text first, we need to remove all the punctuations and remove all the stopwords(repetitive words that we do not need such as have, do, I, you, he, etc). We are using the library from nltk.corpus for the stopwords.
We select only the stars and text for our data and we import the library that we will use.
#Select only stars and textyelp_data = df[['business_id', 'user_id', 'stars', 'text']]import stringfrom nltk.corpus import stopwordsstop = []for word in stopwords.words('english'):    s = [char for char in word if char not in string.punctuation]    stop.append(''.join(s))
Now let’s clean the text by creating a function.
def text_process(mess):    """    Takes in a string of text, then performs the following:    1. Remove all punctuation    2. Remove all stopwords    3. Returns a list of the cleaned text    """    # Check characters to see if they are in punctuation    nopunc = [char for char in mess if char not in string.punctuation]# Join the characters again to form the string.    nopunc = ''.join(nopunc)        # Now just remove any stopwords    return " ".join([word for word in nopunc.split() if word.lower() not in stop])yelp_data['text'] = yelp_data['text'].apply(text_process)
In order to use the text for the matrix factorization recommendation system, we will follow the architecture below to extract the features from the review text.
For each user, combine all the reviews to form a single paragraph, after we combine it all then we apply the TFIDF Vectorizer to extract the features from the text. The similar approach for each restaurant and we need to give the max_feature to match the dimensions of the matrixes.
userid_df = yelp_data[['user_id','text']]business_df = yelp_data[['business_id', 'text']]
userid_df = userid_df.groupby('user_id').agg({'text': ' '.join})business_df = business_df.groupby('business_id').agg({'text': ' '.join})
Now we apply the TFIDF Vectorizer to extract the features from the text.
from sklearn.feature_extraction.text import TfidfVectorizer#userid vectorizeruserid_vectorizer = TfidfVectorizer(tokenizer = WordPunctTokenizer().tokenize, max_features=5000)userid_vectors = userid_vectorizer.fit_transform(userid_df['text'])#Business id vectorizerbusinessid_vectorizer = TfidfVectorizer(tokenizer = WordPunctTokenizer().tokenize, max_features=5000)businessid_vectors = businessid_vectorizer.fit_transform(business_df['text'])
Then, we create a matrix of users and businesses with the ratings.
userid_rating_matrix = pd.pivot_table(yelp_data, values='stars', index=['user_id'], columns=['business_id'])
Let’s go back to the type of recommendation systems that we use, which is the latent factor collaborative filtering. We already have two matrixes (user-features, business-features) that we can multiply to predict the ratings that a user gives to a restaurant. In the next step, we need to update the values in the features of our two matrixes according to the Error.
To optimize the predictions we need to calculate the error using the function below.
Given P is the users-features matrix and Q is the business-features matrix. If we subtract the real ratings (r) with the predicted ratings (P.Q) and we square it, we get the LSE(Least Square Error). In the case of restaurant reviews, we have users that only give reviews to 10 restaurants but we also have users that give reviews to more than 200 restaurants. To avoid our model overfitting we have to add regularization to our LSE formula and it will become the formula written below.
We apply the equation to minimize the error using Gradient Decent to update the values of each feature in matrix P and matrix Q.
def matrix_factorization(R, P, Q, steps=25, gamma=0.001,lamda=0.02):    for step in range(steps):        for i in R.index:            for j in R.columns:                if R.loc[i,j]>0:                    eij=R.loc[i,j]-np.dot(P.loc[i],Q.loc[j])                    P.loc[i]=P.loc[i]+gamma*(eij*Q.loc[j]-lamda*P.loc[i])                    Q.loc[j]=Q.loc[j]+gamma*(eij*P.loc[i]-lamda*Q.loc[j])        e=0        for i in R.index:            for j in R.columns:                if R.loc[i,j]>0:                    e= e + pow(R.loc[i,j]-np.dot(P.loc[i],Q.loc[j]),2)+lamda*(pow(np.linalg.norm(P.loc[i]),2)+pow(np.linalg.norm(Q.loc[j]),2))        if e<0.001:            break            return P,QP, Q = matrix_factorization(userid_rating_matrix, P, Q, steps=25, gamma=0.001,lamda=0.02)
Now we already have our two matrixes updated. It is time to predict restaurant recommendations.
words = "i want to have dinner with beautiful views"test_df= pd.DataFrame([words], columns=['text'])test_df['text'] = test_df['text'].apply(text_process)test_vectors = userid_vectorizer.transform(test_df['text'])test_v_df = pd.DataFrame(test_vectors.toarray(), index=test_df.index, columns=userid_vectorizer.get_feature_names())predictItemRating=pd.DataFrame(np.dot(test_v_df.loc[0],Q.T),index=Q.index,columns=['Rating'])topRecommendations=pd.DataFrame.sort_values(predictItemRating,['Rating'],ascending=[0])[:7]for i in topRecommendations.index:    print(df_business[df_business['business_id']==i]['name'].iloc[0])    print(df_business[df_business['business_id']==i]['categories'].iloc[0])    print(str(df_business[df_business['business_id']==i]['stars'].iloc[0])+ ' '+str(df_business[df_business['business_id']==i]['review_count'].iloc[0]))    print('')
With the input “I want to have dinner with beautiful views” the model will recommend these restaurants.
Let’s take a look at one of the restaurants listed above. For example, Let’s open Compas Arizona Grill in Yelp to see the result of our recommendation systems.
It looks like the restaurant has quite a beautiful views and beautiful sunset. You can take your spouse to have a romantic dinner there (if you have one :D).
Congratulations you have created a Restaurant Recommendation System!
To see the dataset and full version of code, please visit the link below to see in the Github.