Build A Movie Recommender Using C# and ML.NET Machine Learning
By: Mark Farragher
Tags: Machine Learning, Artificial Intelligence, Deep Learning, Data Science, Programming

I will build a machine learning model that reads in each user ID, movie ID, and rating, and then predicts the ratings each user would give for every movie in the dataset.

So that gives me a list of movies and ratings for every user. To recommend a movie, all I need to do is sort the list by rating and report the top 5.

Let’s get started. Here’s how to set up a new console project in NET Core:

$ dotnet new console -o Recommender

$ cd Recommender

Next, I need to install the ML.NET base package and the recommender extensions:

$ dotnet add package Microsoft.ML

$ dotnet add package Microsoft.ML.Recommender

Now I’m ready to add some classes. I’ll need one to hold a movie rating, and one to hold my model’s predictions.

I will modify the Program.cs file like this:

The MovieRating class holds one single movie rating. Note how each field is adorned with a Column attribute that tell the CSV data loading code which column to import data from.

I’m also declaring an MovieRatingPrediction class which will hold a single movie rating prediction.

Now I’m going to load the training data in memory:

This code uses the method LoadFromTextFile to load the CSV data directly into memory. The class field annotations tell the method how to store the loaded data in the MovieRating class.

Now I’m ready to start building the machine learning model:

Machine learning models in ML.NET are built with pipelines, which are sequences of data-loading, transformation, and learning components.

My pipeline has the following components:

MapValueToKey which reads the userId column and builds a dictionary of unique ID values. It then produces an output column called userIdEncoded containing an encoding for each ID. This step converts the IDs to numbers that the model can work with.

which reads the userId column and builds a dictionary of unique ID values. It then produces an output column called userIdEncoded containing an encoding for each ID. This step converts the IDs to numbers that the model can work with. Another MapValueToKey which reads the movieId column, encodes it, and stores the encodings in output column called movieIdEncoded.

which reads the movieId column, encodes it, and stores the encodings in output column called movieIdEncoded. A MatrixFactorization component that performs matrix factorization on the encoded ID columns and the ratings. This step calculates the movie rating predictions for every user and movie.

With the pipeline fully assembled, I can train the model with a call to Fit(…).

I now have a fully- trained model. So now I need to load some validation data, predict the rating for each user and movie, and calculate the accuracy metrics of my model:

This code uses the Transform(…) method to make predictions for every user and movie in the test dataset.

The Evaluate(…) method compares these predictions to the actual area values and automatically calculates three metrics for me:

Rms : this is the root mean square error or RMSE value. It’s the go-to metric in the field of machine learning to evaluate models and rate their accuracy. RMSE represents the length of a vector in n-dimensional space, made up of the error in each individual prediction.

: this is the root mean square error or RMSE value. It’s the go-to metric in the field of machine learning to evaluate models and rate their accuracy. RMSE represents the length of a vector in n-dimensional space, made up of the error in each individual prediction. L1 : this is the mean absolute prediction error, expressed as a rating.

: this is the mean absolute prediction error, expressed as a rating. L2: this is the mean square prediction error, or MSE value. Note that RMSE and MSE are related: RMSE is just the square root of MSE.

To wrap up, let’s use the model to make a prediction.

I’m going to focus on a specific user, let’s say user number 6, and check if he or she likes the James Bond movie ‘GoldenEye’.

Here’s how to make the prediction:

I use the CreatePredictionEngine method to set up a prediction engine. The two type arguments are the input data class and the class to hold the prediction. And once my prediction engine is set up, I can simply call Predict(…) to make a single prediction on a MovieRating instance.

Let’s do one more thing and predict the top-5 favorite movies for this user:

This code uses a static helper class Movies to enumerate over every movie ID. It creates predictions for user 6 and every possible movie, sorts them by score in descending order, and takes the top 5 results.

Here’s the partial source of the helper class:

There’s a Movie class that represents a single movie. The static helper class Movies has an All property with a list of all movies, and a Get method to lookup a single movie by ID value.

With the code all done, it’s time to check the predictions. Here’s the code running in the Visual Studio Code debugger on my Mac: