How to Build a Recommender System with Embeddinghub
Tags: python, machinelearning, computerscience, programming
Published: 2022-05-19 22:17:16

<!-- wp:paragraph -->
<p>A common problem in applied machine learning is how to recommend items in a database to users based on their past behavior. Features like text or categories need to be converted into a numerical feature and then embedded so that they can be used by models.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Usually <em>embeddings</em> — dense numerical representations of real-world objects and relationships, expressed as a vector — are stored in database servers such as PostgreSQLEmbedding. However <a href="https://github.com/featureform/embeddinghub" rel="noreferrer noopener" target="_blank">Embeddinghub</a> makes it easier to store your embeddings and load them. You can get started with minimal setup, and it also makes your code look less verbose as compared to, say, building a KNN model using <code>scikit-learn</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This article walks you through using Embeddinghub to build a content-based recommendation model to recommend anime to a viewer.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Common Methods for Recommendation Systems</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Before we dive into the setup, let’s explore our options. There are a few commonly used paradigms when it comes to building a recommendation model:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>Popularity-based filtering.</strong> This is the most straightforward type of recommendation model. It recommends the top items based on what the general population likes. The <em>Top 10 in Canada</em> on Netflix is a good example of a popularity-based recommendation model. An obvious caveat is that not everyone will like the moves in Netflix’s <em>Top 10 in Canada</em>.</li><li><strong>Content-based filtering.</strong> This works under the assumption that if the user liked item X, they would also like other items similar to X. Models like this try to find similarities between items and group them together. The recommendation given is based on the user’s likes and dislikes. This is the model you’ll be building in this article.</li><li><strong>Collaborative-based filtering.</strong> This model recommends items based on the actions of other users who are similar to you. The assumption is that if user A and user B are similar, both of them will have similar interests. If User B moves to a new genre of a movie all of a sudden, the model assumes that user A would do the same and so will recommend movies with the new genre to user A.</li><li><strong>Hybrid filtering.</strong> This model combines content-based filtering and collaborative-based filtering.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>Common use cases of these various recommendation systems include:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>Product recommendation.</strong> Most e-commerce stores have a section dedicated to recommending products to visitors. These are either based on the things a visitor bought earlier, the item they’re currently viewing, or their past browsing history.</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1760/0*rFRjoJpSilUA5cu4.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li><strong>Restaurant recommendation.</strong> Based on the previous restaurants a visitor has tried on apps like DoorDash and UberEats, they’ll get recommendations for new restaurants. They also recommend the most popular restaurants or national favorites.</li></ul>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1760/0*DCkEfzlG19T1cD1m.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li><strong>Media recommendation.</strong> Apps like Spotify, Netflix, and Youtube recommend media to you based on your browsing history. In fact, Netflix drives <a href="https://www.businessinsider.com/netflixs-recommendation-engine-drives-75-of-viewership-2012-4#:~:text=Flickr%2FJdlasica%20Netflix%20is%20pulling,comes%20from%20its%20recommendation%20engine." rel="noreferrer noopener" target="_blank">around 75 percent</a> of its viewership due to its recommendation engine.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>How to Build a Recommender System with Embeddinghub</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>For the purposes of this tutorial, you will be working with the <a href="https://www.kaggle.com/CooperUnion/anime-recommendations-database/version/1?select=anime.csv" rel="noreferrer noopener" target="_blank">anime recommendation dataset</a> provided on Kaggle. You’ll use the data provided to build a content-based recommendation model. It will be able to recommend anime based on a show the user has watched. For example, if a viewer liked Pokemon, they might like Dragon Ball Z, Digimon, etc.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You’ll use <a href="https://github.com/featureform/embeddinghub" rel="noreferrer noopener" target="_blank">Embeddinghub’s</a> Python module to create a vector space (a space where you represent your feature’s embeddings. If your embeddings are two-dimensional, you will require a 2D vector space to represent them) and store your embeddings. You’ll also use Embeddinghub to recommend anime using a nearest-neighbor algorithm.</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><em>You can find the </em><a href="https://github.com/rahulbanerjee26/Embeddinghub-Anime-Recommender" rel="noreferrer noopener" target="_blank"><em>source code for this tutorial here</em></a><em>.</em></p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3>Download Data and Setup Environment</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Download the <a href="https://www.kaggle.com/CooperUnion/anime-recommendations-database/version/1?select=anime.csv" rel="noreferrer noopener" target="_blank">dataset here</a> and create a new folder for the project.</p>
<!-- /wp:paragraph -->

<!-- wp:code {"language":"bash"} -->
<pre class="wp-block-code"><code>mkdir anime-recommendation</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Create a new virtual environment.</p>
<!-- /wp:paragraph -->

<!-- wp:code {"language":"bash"} -->
<pre class="wp-block-code"><code>python3 -m venv venv</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>And activate it.</p>
<!-- /wp:paragraph -->

<!-- wp:code {"language":"bash"} -->
<pre class="wp-block-code"><code>source venv/bin/activate</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Next, install the dependencies.</p>
<!-- /wp:paragraph -->

<!-- wp:code {"language":"bash"} -->
<pre class="wp-block-code"><code>pip3 install pandas embeddinghub protobuf</code></pre>
<!-- /wp:code -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><em>There is a </em><a href="https://github.com/featureform/embeddinghub/issues/69" rel="noreferrer noopener" target="_blank"><em>known issue</em></a><em> in Embeddinghub about protobuf being a missing dependency. If you get a </em><code><em>module 'google' not found</em></code><em> error, you will need to install protobuf.</em></p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3>Load Data</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>You can download the anime data from <a href="https://github.com/rahulbanerjee26/Embeddinghub-Anime-Recommender/blob/main/anime.csv" target="_blank" rel="noreferrer noopener">here</a></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Use pandas’s <code>read_csv</code> function to load the csv file as a dataframe. Print the dataframe to the console, then explore the columns.</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed https://gist.github.com/rahulbanerjee26/59339ea81a421c4a7241c460341b8fd8 %}
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>For building the recommendation model in this tutorial, you will only need the genre of the anime. To keep it simple, you can use one-hot encoding to embed the genre.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Data Processing</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>As you might have noticed, the value in the genre column is basically a list of genres. You can use the following code snippet to embed the genres as one-hot-encoding</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed
https://gist.github.com/rahulbanerjee26/56681fa13b08c02fb56b6e3ede9a9d6c %}
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>The dimension of your embedding is the total number of columns or genres. This will be required when you create the vector space. You can also add the <code>anime_id</code> and the anime's name to <code>genre_df</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed https://gist.github.com/rahulbanerjee26/32b6c3d6e5b109b23178dc2bae0abde3 %}
<!-- /wp:shortcode -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><em>There is a </em><a href="https://github.com/featureform/embeddinghub/issues/89" rel="noreferrer noopener" target="_blank"><em>known issue</em></a><em> related to the maximum number of elements in an Embeddinghub vector space. For that reason, I only considered the first 2000 animes.</em></p></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3>Create an Embeddinghub Vector&nbsp;Space</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>You’ll need to create a vector space to be able to represent your feature embeddings. In the previous section, you stored the number of genres. You’ll use this when you create the vector space.</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed https://gist.github.com/rahulbanerjee26/1b88f1504c6c9d5a4d88b06cb6c708d2 %}
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>In line 2, I used LocalConfig. However, if you wish, you can run Embeddinghub as a Docker container.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>docker run featureformcom/embeddinghub -p 7462:7462</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Instead of LocalConfig, you could use the following:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>hub = eh.connect(eh.Config())</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>It basically defines where to store and index the embeddings. If you use LocalConfig, it will do so locally.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In line 3, a vector space with dimension equal to the number of genres is created. This is used to represent the embedding, i.e., the one-hot-encoding of your different anime.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Adding Embeddings to Vector&nbsp;Space</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>As mentioned at the beginning of this article, embeddings help represent real-world objects; in our case, anime are a vector with numerical values. These embeddings can help determine how similar two shows are.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Embeddinghub requires the embeddings to be in the form of a dictionary.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>{key : value}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>In this case, <code>value</code> is the embedding, and <code>key</code> is something used to uniquely identify the embedding. The key could be the anime's name and the value could be the embedding.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let’s create a dictionary with the anime and their respective embeddings.</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed https://gist.github.com/rahulbanerjee26/e2ed122385788051c0ce0b6843830a7f %}
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>You do not require the <code>anime_id</code> or the name for the value of the embedding. Therefore, the embedding will start from the third column.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Embeddinghub lets you write embeddings one at a time or in bulk. For convenience, we can write it in bulk.</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed
https://gist.github.com/rahulbanerjee26/0ac49347ebfd2f72f4adf044dcc351d8 %}
<!-- /wp:shortcode -->

<!-- wp:heading {"level":3} -->
<h3>Using Nearest Neighbor to Get an Anime Recommendation</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Since you have a vector space with the anime’s embedding, you can measure the similarity of two anime by measuring the distance between them. The lesser the distance between them, the more similar they are.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let’s try getting recommendations for a user who recently watched <em>Kizumonogatari II: Nekketsu-hen</em>. You can find its genres using the following code snippet:</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed
https://gist.github.com/rahulbanerjee26/2a5011b29785392945275bd939d64935 %}
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>Based on the genres, you would want the user to be recommended an anime along the same lines. To get recommendations, you can either use the key of the embedding (the anime’s name), or a vector (its embedding).</p>
<!-- /wp:paragraph -->

<!-- wp:shortcode -->
{% embed
https://gist.github.com/rahulbanerjee26/a765b35eba693475f852df78afe2b36d %}
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>The <code>num</code> parameter is the number of recommendations or the number of closest neighbors you want. If you want to get a recommendation based on an embedding instead of the key, simply pass a parameter <code>vector</code> with the embedding instead of the key.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Areas for Improvement</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>A good recommendation model can always be made better. Here are a few key places where you might be able to improve your system:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li><strong>Reduce the number of dimensions of the vector space.</strong> The dimension right now is 82 since there are 83 genres. This might cause the nearest neighbor algorithm to suffer from the curse of dimensionality. In other words, items that are not similar will not be further apart from each other.</li><li><strong>Use a more sophisticated embedding algorithm with the help of a neural network,</strong> as opposed to one-hot-encoding.</li><li><strong>Make your embeddings more representative of the feature.</strong> The current embeddings ignore ratings and <code>anime_type</code> (movie or TV show). Including these could improve the recommendations.</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":3} -->
<h3>Conclusion</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>If you followed along with this tutorial, you just built a content-based recommendation model to recommend anime. And if you didn’t, the <a href="https://github.com/rahulbanerjee26/Embeddinghub-Anime-Recommender" rel="noreferrer noopener" target="_blank">source code for it is right here</a>.</p>
<!-- /wp:paragraph -->

---
>
Want to connect with the Author? 🤝
[LinkedIn](https://www.linkedin.com/in/rahulbanerjee2699/)
The article was originally posted on [realpythonproject.com](https://www.realpythonproject.com/how-to-build-an-anime-recommender-system-with-embeddinghub/)