ML.Recommend
1.0.0
dotnet add package ML.Recommend --version 1.0.0
NuGet\Install-Package ML.Recommend -Version 1.0.0
<PackageReference Include="ML.Recommend" Version="1.0.0" />
paket add ML.Recommend --version 1.0.0
#r "nuget: ML.Recommend, 1.0.0"
// Install ML.Recommend as a Cake Addin #addin nuget:?package=ML.Recommend&version=1.0.0 // Install ML.Recommend as a Cake Tool #tool nuget:?package=ML.Recommend&version=1.0.0
ML.Recommend
We inherit and expand the machine learning library of Microsoft ML.NET, and proceed to build a new recommendation model with named ML.Recommend, which will use Matrix Factorization and combine Time Factor for Product Recommendation. The system will provide a complete machine learning model with a set of interactive classes libraries, data and class models are conducted on user reviews for each product with time interaction and the system will recommend products respectively based on the expected score to customers that user configured. The data is experimented on the UELStore e-commerce website (http://ecom.uelstore.com/), the trained models are provided for other researchers to use together with the source code of the ML.Recommend model published by us, the researchers can reuse and expand the features for this model.
Mapping JSon Dataset with Model class (https://github.com/thanhtd32/ML.Recommend/tree/main/Dataset):
# | Dataset | Model class | Description | Number of object |
---|---|---|---|---|
1 | customers.json | Customer | List of Customer dataset | 678 |
2 | products.json | Product | List of Product dataset | 732 |
3 | ratings.json | Rating | List of Rating dataset | 130754 |
This Research from KMOU (Korea Maritime & Ocean University) - Data Science Lab - Room 407.
Authors: Duy Thanh Tran, Prof. Jun-Ho Huh
Any question, please free to contact me: thanhtd@uel.edu.vn
My full name: TRAN DUY THANH
Blog study coding: https://duythanhcse.wordpress.com/
ML.Recommend - model class
RecommendEngine is a center class of the ML.Recommend
GUI Demo:
Test ML.Recommend model
Test recommendation products for customers:
ML.Recommend - How to use?
Install nuget package
Install-Package ML.Recommend -ProjectName YourProject
Full dataset : https://github.com/thanhtd32/ML.Recommend/tree/main/Dataset
Full source code demo in Windows Desktop https://github.com/thanhtd32/ML.Recommend/tree/main/ML.RecommendDemo
Full source code demo in Web .net core https://github.com/thanhtd32/ML.Recommend/tree/main/ML.RecommendWeb
Windows Desktop demo
using ML.Recommend.Data;
using ML.Recommend.Error;
using ML.Recommend.Predict;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ML.RecommendDemo
{
public partial class frmDemoRecommend : Form
{
List<Rating> ratings;
RecommendEngine engine= new RecommendEngine();
string folder = "Models";
List<Customer> customers;
List<Product> products;
public frmDemoRecommend()
{
InitializeComponent();
}
private void frmDemoRecommend_Load(object sender, EventArgs e)
{
LoadModelIntoCombo();
}
private void btnLoadCustomer_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
customers= DataUtils.LoadCustomers(openFileDialog1.FileName);
cboCustomer.DataSource = customers;
cboCustomer.ValueMember = "Id";
cboCustomer.DisplayMember = "NickName";
}
}
private void btnLoadProduct_Click(object sender, EventArgs e)
{
if(openFileDialog1.ShowDialog()==DialogResult.OK)
{
string fileName = openFileDialog1.FileName;
string jsonString = File.ReadAllText(fileName);
products = JsonSerializer.Deserialize<List<Product>>(jsonString)!;
cboProduct.DataSource = products;
cboProduct.ValueMember = "Id";
cboProduct.DisplayMember = "Name";
}
}
private void btnLoadRating_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
ratings=DataUtils.LoadRatings(openFileDialog1.FileName,dtpFrom.Value,dtpTo.Value);
MessageBox.Show("Import ratings dataset is successfully!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
frmRating frm= new frmRating();
frm.gvRating.DataSource = ratings;
frm.lblToTal.Text ="There are "+ ratings.Count + " ratings!";
frm.Show();
}
}
private void rad1_CheckedChanged(object sender, EventArgs e)
{
if (rad1.Checked)
txtTestRatio.Text = rad1.Text;
}
private void rad2_CheckedChanged(object sender, EventArgs e)
{
if (rad2.Checked)
txtTestRatio.Text = rad2.Text;
}
private void rad3_CheckedChanged(object sender, EventArgs e)
{
if (rad3.Checked)
txtTestRatio.Text = rad3.Text;
}
private void rad4_CheckedChanged(object sender, EventArgs e)
{
if (rad4.Checked)
txtTestRatio.Text = rad4.Text;
}
private void rad5_CheckedChanged(object sender, EventArgs e)
{
if (rad5.Checked)
txtTestRatio.Text = rad5.Text;
}
private void btnImportDataset_Click(object sender, EventArgs e)
{
try
{
double testRatio = double.Parse(txtTestRatio.Text);
bool ret= engine.ImportAndSplitDataset(ratings, testRatio);
if (ret)
{
lblImportDatasetMessage.Text = "Import && split dataset for train and test set sucessful!";
}
}
catch(RecommendError ex)
{
MessageBox.Show(ex.Message);
}
}
private void btnBuildModel_Click(object sender, EventArgs e)
{
try
{
int iterator=int.Parse(txtIterator.Text);
int approximationRank = int.Parse(txtRank.Text);
bool ret = engine.BuildModel(iterator, approximationRank);
if (ret)
{
lblBuildModelMessage.Text = "Build model sucessful!";
}
}
catch (RecommendError ex)
{
MessageBox.Show(ex.Message);
}
}
private void btnEvaluateModel_Click(object sender, EventArgs e)
{
try
{
Metric metric = engine.Evaluate();
txtMAE.Text=Math.Round(metric.MAE,2).ToString();
txtMSE.Text= Math.Round(metric.MSE, 2).ToString();
txtRMSE.Text= Math.Round(metric.RMSE, 2).ToString();
txtSquared.Text= Math.Round(metric.RSquared, 2).ToString();
}
catch (RecommendError ex)
{
MessageBox.Show(ex.Message);
}
}
private void btnSaveModel_Click(object sender, EventArgs e)
{
try
{
if (Directory.Exists(folder) == false)
{
Directory.CreateDirectory(folder);
}
string path = folder + "\\ML.Recommend-" + DateTime.Now.ToString("ddMMyyyy-hhmmss") + ".zip";
bool ret = engine.SaveModel(path);
if (ret)
lblSaveModelMessage.Text = "Save Model successfully";
else
lblSaveModelMessage.Text = "Save Model failed";
LoadModelIntoCombo();
}
catch (RecommendError ex)
{
MessageBox.Show(ex.Message);
}
}
private void LoadModelIntoCombo()
{
cboModel.Items.Clear();
if (Directory.Exists(folder) == false)
{
return;
}
string[] files = Directory.GetFiles(folder);
foreach (string file in files)
{
FileInfo fi = new FileInfo(file);
cboModel.Items.Add(fi.Name);
}
}
private void btnPredict_Click(object sender, EventArgs e)
{
try
{
Customer customer = cboCustomer.SelectedItem as Customer;
Product product = cboProduct.SelectedItem as Product;
var testInput = new Rating { CustomerID = customer.Id, ProductID = product.Id };
var output = engine.Predict(testInput);
double expectedScore=double.Parse(txtExpectedScore.Text);
if (Math.Round(output.Score, 1) >= expectedScore)
{
lblResult.Text = "Score=" + Math.Round(output.Score, 1) + ", Product [" + product.Id+"-"+product.Name+"]" + " is recommended for user [" + customer.Id+" - "+customer.NickName+"]";
}
else
{
lblResult.Text = "Score=" + Math.Round(output.Score, 1) + ", Product [" + product.Id + "-" + product.Name + "]" + " is not recommended for user [" + customer.Id + " - " + customer.NickName + "]";
}
}
catch (RecommendError ex)
{
MessageBox.Show(ex.Message);
}
}
private void groupBox1_Enter(object sender, EventArgs e)
{
}
private void btnLoadModel_Click(object sender, EventArgs e)
{
try
{
if (cboModel.SelectedIndex == -1)
return;
string modelName = folder + "\\" + cboModel.Text;
bool ret = engine.LoadModel(modelName);
if (ret)
lblLoadModelMessage.Text = "Load Model successfully";
else
lblLoadModelMessage.Text = "Load Model failed";
}
catch (RecommendError ex)
{
MessageBox.Show(ex.Message);
}
}
private void btnAdvanced_Click(object sender, EventArgs e)
{
frmAdvanced frm = new frmAdvanced();
frm.customers = customers;
frm.products = products;
frm.Show();
}
}
}
Web .net core Demo
Web Project structure:
in this web project, We use ML.Recommend-1.zip to test
Web list of customers:
Web recommendation products for customers:
CustomerController.cs
using Microsoft.AspNetCore.Mvc;
using ML.Recommend.Data;
using ML.Recommend.Predict;
using System.Text.Json;
namespace ML.RecommendWeb.Controllers
{
public class CustomerController : Controller
{
private readonly IWebHostEnvironment _webHostEnvironment;
public CustomerController(IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment = webHostEnvironment;
}
public IActionResult Index()
{
string webRootPath = _webHostEnvironment.WebRootPath;
string contentRootPath = _webHostEnvironment.ContentRootPath;
string path = "";
path = Path.Combine(contentRootPath, "Dataset");
string customerFile= Path.Combine(path,"customers.json");
string jsonString = System.IO.File.ReadAllText(customerFile);
List<Customer> customers = JsonSerializer.Deserialize<List<Customer>>(jsonString)!;
return View(customers);
}
public IActionResult Recommends(int id)
{
RecommendEngine engine = new RecommendEngine();
string webRootPath = _webHostEnvironment.WebRootPath;
string contentRootPath = _webHostEnvironment.ContentRootPath;
string path = "";
path = Path.Combine(contentRootPath, "Models");
string modelPath= Path.Combine(path, "ML.Recommend-1.zip");
engine.LoadModel(modelPath);
path = "";
path = Path.Combine(contentRootPath, "Dataset");
string customerFile = Path.Combine(path, "customers.json");
string jsonString = System.IO.File.ReadAllText(customerFile);
List<Customer> customers = JsonSerializer.Deserialize<List<Customer>>(jsonString)!;
Customer customer = customers.FirstOrDefault(c => c.Id == id);
path = "";
path = Path.Combine(contentRootPath, "Dataset");
string productFile = Path.Combine(path, "products.json");
jsonString = System.IO.File.ReadAllText(productFile);
List<Product> products = JsonSerializer.Deserialize<List<Product>>(jsonString)!;
float es = 3.5f;
List<Product> rProducts = engine.Predict(customer, products,es);
ViewData["customer"] = customer;
return View(rProducts);
}
}
}
Views/Customer/Index.cshtml
@model IEnumerable<ML.Recommend.Data.Customer>
@{
ViewData["Title"] = "Index";
}
<p>
List of Customers:
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Id)
</th>
<th>
@Html.DisplayNameFor(model => model.NickName)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Id)
</td>
<td>
@Html.DisplayFor(modelItem => item.NickName)
</td>
<td>
|@Html.ActionLink("Recommendation", "Recommends", new { id=item.Id }) |
</td>
</tr>
}
</tbody>
</table>
Views/Customer/Recommends.cshtml
@using ML.Recommend.Data
@model IEnumerable<ML.Recommend.Data.Product>
@{
ViewData["Title"] = "Recommends";
}
@{
Customer customer =(Customer) ViewData["customer"];
}
<p>
List Recommended Products for Customer: <font color='blue'>@Html.Raw(customer .Id +" -"+customer .NickName) </font>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Id)
</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.UnitPrice)
</th>
<th>
@Html.DisplayNameFor(model => model.Score)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Id)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.UnitPrice)
</td>
<td>
@Html.DisplayFor(modelItem => item.Score)
</td>
<td>
</td>
</tr>
}
</tbody>
</table>
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net6.0
- Microsoft.ML (>= 1.7.1)
- Microsoft.ML.Recommender (>= 0.19.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 318 | 5/29/2022 |