Building a Product Recommendation System using Word2vec in Python

Introduction

In today‘s digital age, recommendation systems have become ubiquitous and indispensable for many online businesses. From Amazon to Netflix to Spotify, recommender systems power personalized user experiences and help customers discover new and relevant products or content. Building effective recommendation systems is both a science and an art, requiring a blend of machine learning techniques, domain knowledge, and an understanding of human behavior and preferences.

In this tutorial, we‘ll walk through how to build a product recommendation system using a technique called word2vec, borrowed from the field of natural language processing (NLP). While traditionally used for learning semantic relationships between words in a corpus of text, we‘ll show how word2vec can be creatively repurposed to learn latent relationships between products based on customer purchase histories. By the end, you‘ll gain both a conceptual understanding of the inner workings of word2vec as well as hands-on experience leveraging it to build a product recommender in Python. Let‘s dive in!

Overview of Recommendation Systems

At a high level, recommendation systems aim to predict and recommend the most relevant items to a particular user based on the user‘s previous behavior and preferences. The items can span a wide range, including products, articles, songs, movies, restaurants, online courses, and more, depending on the application domain. Recommenders unlock substantial business value in the form of increased sales and revenue, improved user satisfaction and loyalty, and better inventory and resource planning.

Broadly speaking, recommendation systems can be categorized into three main types:

  1. Content-based: recommend items similar to what a user has liked in the past based on intrinsic characteristics of the items
  2. Collaborative filtering: recommend items that users with similar tastes and preferences have liked in the past
  3. Hybrid: combine both content-based and collaborative filtering approaches

Some common approaches and algorithms used to build recommenders include:

  • Matrix factorization
  • Deep learning
  • k-Nearest Neighbors
  • Association rule mining
  • Probabilistic graphical models

In this tutorial, we‘ll focus on using word2vec, a technique grounded in both matrix factorization and deep learning, to build a recommender system for an online retail store.

Word2vec Primer

Word2vec is a popular algorithm from natural language processing (NLP) for learning vector representations of words, called "word embeddings". It was originally introduced by a team at Google led by Tomas Mikolov in 2013. The key idea behind word2vec is to learn a dense, low-dimensional vector for each word based on its usage context in a corpus of text. Words that are used in similar contexts will have vectors that are close together in the embedding space.

There are two main model architectures for learning word vectors in word2vec:

  1. Continuous Bag-of-Words (CBOW): predict a target word given its surrounding context words
  2. Continuous Skip-gram: predict the surrounding context words given a target word

In both architectures, word2vec learns the word embeddings by training a shallow neural network to perform these prediction tasks and backpropagating the errors to update the embeddings.One of the key insights behind word2vec is that the learned word vectors encode semantic meaning and relationships. For example, the embedding for "king" minus "man" plus "woman" results in a vector very close to "queen". This property can be used for reasoning by analogy and uncovering latent semantic connections.

Preparing Online Retail Data

To build our product recommendation system, we‘ll use a public dataset of ~540K transactions from a UK-based online retail store, spanning the period 12/01/2010 to 12/09/2011. Each transaction includes the following fields:

  • Invoice number
  • Stock code
  • Product description
  • Quantity
  • Invoice date
  • Customer ID

Our goal will be to recommend relevant products to a user based on their past purchase history. To do this, we‘ll train a word2vec model on sequences of products purchased by each customer.

First, let‘s load the data into a Pandas DataFrame and do some basic preprocessing:

import pandas as pd

df = pd.read_excel(‘Online Retail.xlsx‘)
df.head()
  InvoiceNo StockCode                          Description  Quantity  \
0    536365    85123A   WHITE HANGING HEART T-LIGHT HOLDER         6   
1    536365     71053                  WHITE METAL LANTERN         6   
2    536365    84406B       CREAM CUPID HEARTS COAT HANGER         8   
3    536365    84029G  KNITTED UNION FLAG HOT WATER BOTTLE         6   
4    536365    84029E       RED WOOLLY HOTTIE WHITE HEART.         6   
      InvoiceDate  UnitPrice  CustomerID         Country  

0 2010-12-01 08:26:00 2.55 17850.0 United Kingdom
1 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
2 2010-12-01 08:26:00 2.75 17850.0 United Kingdom
3 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
4 2010-12-01 08:26:00 3.39 17850.0 United Kingdom

Let‘s check for any missing values:

df.isnull().sum()
InvoiceNo           0
StockCode           0
Description      1454
Quantity            0
InvoiceDate         0
UnitPrice           0
CustomerID     135080
Country             0
dtype: int64

Since there are some missing values for CustomerID, we‘ll remove those rows:

df.dropna(subset=[‘CustomerID‘], inplace=True)

Next, we‘ll group the transactions by CustomerID and create a list of StockCodes purchased for each customer:

purchases = df.groupby(‘CustomerID‘)[‘StockCode‘].apply(list).reset_index()
purchases.head()
   CustomerID                                         StockCode
0     12346.0  [85123A, 71053, 84406B, 84029G, 84029E, 22752,...
1     12347.0  [85123A, 84077, 84879, 22411, 21731, 22623, 2...
2     12348.0                    [84879, 15056BL, 15056N, DOT]
3     12349.0                                           [21731]
4     12350.0                                   [22650, 22407]

We now have our customer "documents" ready in a format compatible with word2vec – each customer is represented by a sequence of product "words".

Training a Word2vec Model

With our data prepared, we‘re ready to train our word2vec model. We‘ll use the popular Gensim library in Python, which has an optimized implementation of word2vec.

First, let‘s split our data into a train and validation set:

from sklearn.model_selection import train_test_split

train, valid = train_test_split(purchases, test_size=0.2, random_state=2023)

Now, let‘s instantiate our word2vec model and train it on the purchase sequences:

from gensim.models import Word2Vec

model = Word2Vec(sentences=train[‘StockCode‘],
                 vector_size=100,  
                 window=5,
                 min_count=1,
                 workers=4)

model.train(train[‘StockCode‘], total_examples=len(train), epochs=10)

We set vector_size to 100, which means each product will be represented by a dense vector of 100 floating point numbers. The window parameter controls the size of the surrounding context for each target word. min_count sets the minimum frequency threshold for a word to be included in the vocabulary. We train the model for 10 epochs on the sequences.

After training, we can access the learned product embeddings through model.wv:

product_vectors = model.wv
print(len(product_vectors))
3684

Our model has learned embeddings for 3684 unique products. Let‘s spot check a few similarity examples:

product_vectors.most_similar(‘84879‘)
[(‘84991‘, 0.877117395401001),
 (‘22197‘, 0.8618917465209961), 
 (‘22428‘, 0.8580918312072754),
 (‘22424‘, 0.8369876742362976), 
 (‘22427‘, 0.8275295495986938)]

The model returns the top 5 most similar products to "84879" based on cosine similarity of the vectors. Not bad!

Visualizing Product Embeddings

Since our product embeddings live in a 100-dimensional space, we can‘t visualize them directly. However, we can apply dimensionality reduction techniques like PCA or t-SNE to project them into a 2D space for visualization purposes.

Let‘s use t-SNE from scikit-learn:

from sklearn.manifold import TSNE

tsne = TSNE(n_components=2, verbose=1, random_state=2023)
X_2d = tsne.fit_transform(product_vectors.vectors)

Now, let‘s plot the 2D embeddings with Matplotlib:

import matplotlib.pyplot as plt

plt.figure(figsize=(12, 8))
plt.scatter(X_2d[:, 0], X_2d[:, 1])
plt.title(‘2D Projection of Product Embeddings‘)
plt.show()

The plot shows some local clustering structure, where similar products are embedded close together in the space. We can even annotate a few points with the actual product descriptions to interpret the semantic relationships the model has learned.

Generating Product Recommendations

Now for the fun part – using our trained embeddings to recommend products! The general approach will be:

  1. Given a user‘s purchase history, represent it by aggregating (summing or averaging) the vectors of the purchased products
  2. Find the top k most similar products to this aggregated user vector

Let‘s write a helper function to get the top k most similar products to a given product:

def get_similar_products(product_id, k=5):
    try:
        similar_products = product_vectors.most_similar(product_id, topn=k)
        return similar_products
    except KeyError:
        return []

To recommend products for a user, we‘ll aggregate their purchase history vector and then find the most similar products to this vector:

def recommend_products(purchase_history, k=5, aggregation=‘mean‘):
    product_vectors = [model.wv[product_id] for product_id in purchase_history if product_id in model.wv]
    if len(product_vectors) == 0:
        return []
    if aggregation == ‘mean‘:
        user_vector = np.mean(product_vectors, axis=0)
    elif aggregation == ‘sum‘:
        user_vector = np.sum(product_vectors, axis=0)
    else:
        raise ValueError(‘Unknown aggregation type: {}‘.format(aggregation))
    return model.wv.most_similar(positive=[user_vector], topn=k)

Let‘s test it out on a sample user from our validation set:

sample_user = valid.iloc[0]
print(‘User ID:‘, sample_user[‘CustomerID‘])  
print(‘Purchase History:‘, sample_user[‘StockCode‘])

print(‘Recommendations:‘)
for product_id, score in recommend_products(sample_user[‘StockCode‘]):
    print(‘{}: {:.3f}‘.format(product_id, score))
User ID: 15098.0
Purchase History: [22720, 21786, 22419, 22067, 85116, 22065, 22908, 22357]

Recommendations:
22969: 0.868 22139: 0.864 85064: 0.837 22423: 0.836 22111: 0.836

Our model recommends 5 new products that this user may be interested in based on the learned product similarities. In practice, you‘d want to filter out products the user has already purchased before making recommendations.

Extensions and Next Steps

Congrats on making it this far! Let‘s discuss some potential extensions and improvements to our basic recommender system:

  • Experiment with different word2vec hyperparameters (vector size, context window, etc.)
  • Try alternate product aggregation schemes (weighted average, exponential decay, etc.)
  • Combine product embeddings with user embeddings for more personalized recommendations
  • Integrate side information (product metadata, user demographics, etc.) into the model
  • Explore other embedding approaches (e.g. GloVe, fastText)
  • Evaluate recommendations in an online A/B test

The complete code for this tutorial is available on GitHub. Feel free to use it as a starting point for your own projects.

Conclusion

In this tutorial, we covered how to build a product recommendation system using word2vec embeddings in Python. The key idea was to frame the problem in a way that allowed us to repurpose word2vec, an algorithm originally designed for learning word embeddings from natural language, to instead learn product embeddings from sequences of user purchases.

Through code examples, we demonstrated the end-to-end process of preparing the online retail dataset, training a word2vec model, visualizing the learned product embeddings, and ultimately leveraging them to generate personalized product recommendations for users based on their individual purchase histories.

While this approach is by no means the only way to build a product recommender system, it highlights the power and flexibility of embeddings as a general purpose tool for representation learning, as well as how techniques from one domain (like NLP) can often be creatively adapted to solve problems in another.

I hope this has been an informative and practical introduction to recommendation systems for you. The complete code is available, so I encourage you to try running and extending it yourself. Best of luck on your learning journey!

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Similar Posts