Hi rekan-rekan Makers,
Bertemu lagi di seri ML.NET, kali ini kita akan mencoba menggunakan ML.NET untuk memberikan rekomendasi berdasarkan data history. Untuk rekan-rekan yang belum mengikuti seri ini dari awal silakan baca dari artikel ini. Adapun beberapa hal yang sebelumnya dibahas antara lain regression, binary classification, multiclass classification, clustering, time-series dan recommendation dengan matrix factorization.
Ini adalah artikel lanjutan dari artikel tentang algoritma rekomendasi menggunakan matrix factorization, seperti dibahas di artikel sebelumnya kali ini kita akan mencoba membuat model rekomendasi dengan lebih dari 2 features menggunakan Field-Aware Factorization Machine. Kasus kali ini adalah tentang bagaimana memberikan rekomendasi property Air BnB berdasarkan data history listing sebagai data training. Nah dataset yang akan kita gunakan memiliki attribut antara lain:
- id, ini cuma penomoran, tidak digunakan
- name,tidak digunakan
- host_id,tidak digunakan
- host_name, tidak digunakan
- neighbourhood_group, tidak ada data, tidak digunakan
- neighbourhood, attribut ini kita gunakan sebagai features
- latitude,attribut ini kita gunakan sebagai features
- longitude, attribut ini kita gunakan sebagai features
- room_type, attribut ini kita gunakan sebagai features
- price, attribut ini kita gunakan sebagai features
- minimum_nights, attribut ini kita gunakan sebagai features
- number_of_reviews, kita gunakan untuk mengkalkulasi rating
- last_review, tidak digunakan
- reviews_per_month, kita gunakan untuk mengkalkulasi rating
- calculated_host_listings_count, kita gunakan untuk mengkalkulasi rating
- availability_365, attribut ini kita gunakan sebagai features
selanjutnya, rekan-rekan memastikan sudah menginstall .NET Core / .NET Framework versi terakhir, dalam artikel ini saya menggunakan .NET Core versi 2.2. Jika belum silakan download disini. Jika belum memiliki IDE silakan download visual studio and vs code.
Langkah pertama silakan buat project baru dengan tipe console application. Kalau dengan dengan .Net Core bisa menggunakan CLI, silakan buka terminal atau command line (cmd.exe). Lalu ketik:
mkdir AirBnBApp
Lalu masuk ke folder yang baru dibuat dengan mengetik:
cd AirBnBApp
Selanjutnya buat aplikasi console dengan mengetik:
dotnet new console
Kita perlu menambahkan nuget package ML.NET dan algoritma Recommendation dengan mengetik:
dotnet add package Microsoft.ML dotnet add package Microsoft.ML.Recommender
Kemudian buatlah folder dengan nama “Data” dengan mengetik:
mkdir Data
Lalu download file tsv dari link ini, dan masukan ke folder “Data” tersebut.
Kemudian buka dengan visual studio code folder “AirBnBApp”
pada Program.cs masukan namespace ML.NET dengan mengetik pada bagian atas:
using Microsoft.ML; using System; using System.Collections.Generic; using System.IO; using System.Linq;
Selanjutnya buatlah class dengan nama “ListingData.cs” isikan kode berikut:
using Microsoft.ML.Data;
using System;
using System.Collections.Generic;
using System.Text;
namespace AirBnBApp
{
public class ListingData
{
[ColumnName("id"), LoadColumn(0)] public int id { get; set; }
[ColumnName("name"), LoadColumn(1)] public string name { get; set; }
[ColumnName("host_id"), LoadColumn(2)] public string host_id { get; set; }
[ColumnName("host_name"), LoadColumn(3)] public string host_name { get; set; }
[ColumnName("neighbourhood_group"), LoadColumn(4)] public string neighbourhood_group { get; set; }
[ColumnName("neighbourhood"), LoadColumn(5)] public string neighbourhood { get; set; }
[ColumnName("latitude"), LoadColumn(6)] public float latitude { get; set; }
[ColumnName("longitude"), LoadColumn(7)] public float longitude { get; set; }
[ColumnName("room_type"), LoadColumn(8)] public string room_type { get; set; }
[ColumnName("price"), LoadColumn(9)] public float price { get; set; }
[ColumnName("minimum_nights"), LoadColumn(10)] public float minimum_nights { get; set; }
[ColumnName("number_of_reviews"), LoadColumn(11)] public int number_of_reviews { get; set; }
[ColumnName("last_review"), LoadColumn(12)] public string last_review { get; set; }
[ColumnName("reviews_per_month"), LoadColumn(13)] public float reviews_per_month { get; set; }
[ColumnName("calculated_host_listings_count"), LoadColumn(14)] public int calculated_host_listings_count { get; set; }
[ColumnName("availability_365"), LoadColumn(15)] public float availability_365 { get; set; }
public bool Label;
}
}
Class diatas merepresentasikan struktur data training yang kita gunakan. Lalu buatlah class dengan nama “ListingPrediction.cs” isikan kode berikut:
using System;
using System.Collections.Generic;
using System.Text;
namespace AirBnBApp
{
public class ListingPrediction
{
public bool PredictedLabel;
public float Probability;
public string neighbourhood { get; set; }
public string room_type { get; set; }
public float price { get; set; }
public float minimum_nights { get; set; }
public float availability_365 { get; set; }
}
}
Class ini digunakan untuk melakukan prediksi rekomendasi listing. Lalu kembali ke file “Program.cs” lalu masukan kode berikut dalam void main:
var filePath = GetAbsolutePath("../../../Data/listings_tsv.txt");
List<ListingData> DataFromCSV = new List<ListingData>();
int RowCount = 0;
foreach (var line in File.ReadAllLines(filePath))
{
RowCount++;
//skip header
if (RowCount > 1)
{
var cols = line.Split('\t');
DataFromCSV.Add(new ListingData() {
name = cols[1],
neighbourhood = cols[5],
room_type = cols[8],
price = float.Parse(cols[9]),
minimum_nights = int.Parse(cols[10]),
availability_365 = int.Parse(cols[15]),
//calculate recommendation (min night <5, num review > 1, rev per month > 0.1, host list count >= 1, availability per year > 10
Label = (int.Parse(cols[10]) < 5 && int.Parse(cols[11]) > 1 && float.Parse(cols[13]) > 0.1 && int.Parse(cols[14]) >= 1 && int.Parse(cols[15]) > 10)
});
}
}
//Create MLContext
MLContext mlContext = new MLContext();
//Load Data File
IDataView trainData = mlContext.Data.LoadFromEnumerable<ListingData>(DataFromCSV);
Kode diatas memuat data training dari tsv, lalu kita masukan data ke dalam list secara manual, karena kita butuh melakukan kalkulasi kolom label berisi nilai true atau false. Nilai ini mengindikasikan property ini direkomendasikan atau tidak, hal ini bisa kita tentukan sendiri kriterianya. Dalam hal ini kita menandai sebuah listing itu direkomendasikan jika memenuhi syarat berikut:
- min night <5 : lama stay minimum dibawah 5 hari
- num review > 1, jumlah review lebih dari 1
- rev per month > 0.1, review sebulan lebih besar dari 0.1
- host list count >= 1, host punya lebih dari 1 unit
- availability per year > 10, dalam 1 tahun listing tersedia lebih dari 10 hari
setelah mengkalkulasi nilai Label, lalu kita muat data list ke objek IDataView agar bisa digunakan untuk melakukan training. Rekan-rekan bisa melihat preview datanya dengan method Preview(). Selanjut kita lakukan transformasi data dengan kode berikut:
//Data process configuration with pipeline data transformations
var dataPrepTransform = mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "neighbourhood_encoded", inputColumnName: "neighbourhood")
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "room_type_encoded", inputColumnName: "room_type"))
.Append(mlContext.Transforms.Concatenate("Features", new[] { "neighbourhood_encoded", "room_type_encoded", "price", "minimum_nights", "availability_365", "latitude","longitude" }))
.AppendCacheCheckpoint(mlContext);
// Create data transformer
ITransformer dataPrepTransformer = dataPrepTransform.Fit(trainData);
IDataView transformedTrainingData = dataPrepTransformer.Transform(trainData);
Semua kolom yang kita gunakan sebagai features harus berbentuk numerik, yang berbentuk string kategori kita lakukan transformasi menggunakan One Hot Encoding. Lalu semua kolom kita satukan menjadi vektor di kolom Features. Selanjutnya kita pilih algoritma rekomendasinya:
// Choose learner
var CluteringEstimator = mlContext.BinaryClassification.Trainers.FieldAwareFactorizationMachine(new string[] { "Features" });
// Build machine learning model
var trainedModel = dataPrepTransformer.Append(CluteringEstimator.Fit(transformedTrainingData));
Kita gunakan Field Aware Factorization Machine karena kita memiliki lebih dari 2 features dan nilai label berupa boolean. Selanjutnya kita panggil method Fit untuk mentraining model. Lalu kita ukur seberapa akurat model kita dengan kode berikut:
// Measure trained model performance
var testData = trainedModel.Transform(transformedTrainingData);
var metrics = mlContext.BinaryClassification.Evaluate(testData);
Console.WriteLine();
Console.WriteLine("Model quality metrics evaluation");
Console.WriteLine("--------------------------------");
Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
Console.WriteLine($"Auc: {metrics.AreaUnderRocCurve:P2}");
Console.WriteLine($"F1Score: {metrics.F1Score:P2}");
Console.WriteLine("=============== End of model evaluation ===============");
Kita gunakan evaluator yang sama dengan algoritma binary classification. Sehingga beberapa metriknya bisa disimpulkan: Accuracy menunjukan nilai proporsi prediksi yang tepat yang dihasilkan model, semakin besar semakin baik, AreaUnderRocCurve menunjukan seberapa yakin dalam mengklasifikasi class yang positif dan negatif, semakin mendekati 1 semakin baik. F1Score menunjukan keseimbangan pengukuran antara recall (jumlah prediksi yang tepat classnya / jumlah total aktual yang memang sesuai class) dan precision (jumlah prediksi yang tepat classnya/jumlah total prediksi yang sesuai classnya), semakin mendekati 1 semakin baik. Selanjutnya model kita simpan dalam format binary dengan kode berikut:
var modelRelativePath = GetAbsolutePath("MLModel.zip");
mlContext.Model.Save(trainedModel, trainData.Schema, GetAbsolutePath(modelRelativePath));
Console.WriteLine("The model is saved to {0}", GetAbsolutePath(modelRelativePath));
Kemudian kita ujicoba untuk memuat model dari file, dan lakukan prediksi tunggal dengan data contoh:
ITransformer mlModel = mlContext.Model.Load(GetAbsolutePath(modelRelativePath), out DataViewSchema inputSchema);
var predEngine = mlContext.Model.CreatePredictionEngine<ListingData, ListingPrediction>(mlModel);
// Create sample data to do a single prediction with it
var sampleDatas = mlContext.Data.CreateEnumerable<ListingData>(trainData, false).Take(10);
foreach (var sampleData in sampleDatas)
{
// Try a single prediction
ListingPrediction predictionResult = predEngine.Predict(sampleData);
Console.WriteLine($"Single Prediction {sampleData.name} --> Predicted: { (predictionResult.PredictedLabel ? "Recommended" : "Not Recommended") }");
}
Nah kode diatas akan melakukan ujicoba prediksi tunggal ke 10 sampel data, dan menghasilkan nilai True jika direkomendasikan.
Nah jika saat dirunning ada error tenang saja, rekan-rekan bisa unduh source codenya dari sini. Agar akurasi semakin baik coba tambahkan jumlah dataset dan tuning hyper parameter dari model yang digunakan.
Nah sekarang rekan-rekan sudah paham bagaimana membuat rekomendasi dengan ML.NET, silakan bereksperimen dengan data-data sendiri. Jangan lupa post karya rekan-rekan di bagian komentar. Ditunggu karya-karya kerennya ya…
Di artikel selanjutnya kita akan membahas bagaimana menggunakan model deep learning untuk melakukan transfer learning dengan ML.NET. Ikuti terus ya…
Semoga manfaat dan berkah.
Salam Makers