ML.NET Series: Mendeteksi Jenis Kanker Payudara (Binary Classification)

Hi rekan-rekan Makers,

Kali ini kita akan mencoba membuat model ML untuk mengklasifikasi jenis kanker payudara menjadi 2 kategori jinak dan ganas. Untuk itu kita akan menggunakan ML.NET yaitu framework machine learning dari Microsoft berbasis .NET, beberapa kapabilitasnya bisa rekan-rekan pelajari pada artikel ini.

Data yang kita gunakan berasal dari University of Wisconsin Hospitals, informasi mengenai dataset ini bisa diakses dari link ini. Data ini mengkategorikan jenis kanker payudara menjadi 2 class yaitu jinak dan ganas. Beberapa attribut dari dataset ini adalah:

  1. Sample code number: id number, attribut ini tidak digunakan karena hanya penomoran sample
  2. Clump Thickness: 1 – 10, attribut ini menjadi features
  3. Uniformity of Cell Size: 1 – 10, attribut ini menjadi features
  4. Uniformity of Cell Shape: 1 – 10, attribut ini menjadi features
  5. Marginal Adhesion: 1 – 10, attribut ini menjadi features
  6. Single Epithelial Cell Size: 1 – 10, attribut ini menjadi features
  7. Bare Nuclei: 1 – 10, attribut ini menjadi features
  8. Bland Chromatin: 1 – 10, attribut ini menjadi features
  9. Normal Nucleoli: 1 – 10, attribut ini menjadi features
  10. Mitoses: 1 – 10, attribut ini menjadi features
  11. Class: (2 for benign, 4 for malignant), ini adalah label (2 – kanker jinak dan 4 – kanker ganas)

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 BreastCancerApp

Lalu masuk ke folder yang baru dibuat dengan mengetik:

cd BreastCancerApp

Selanjutnya buat aplikasi console dengan mengetik:

dotnet new console

Kita perlu menambahkan nuget package ML.NET dan algoritma FastLearner dengan mengetik:

dotnet add package Microsoft.ML

Kemudian buatlah folder dengan nama “Data” dengan mengetik:

mkdir Data

Lalu download file csv dari link ini, dan masukan ke folder “Data” tersebut.

Kemudian buka dengan visual studio code folder “BreastCancerApp”

pada Program.cs masukan namespace ML.NET dengan mengetik pada bagian atas:

using Microsoft.ML;
using System.IO;
using Microsoft.ML.Trainers;
using Microsoft.ML.Data;
using System.Linq;
using System.Collections.Generic;

Lalu buat kita buat data class, buat file dengan nama “BreastCancerData.cs”, masukan kode berikut:

using Microsoft.ML.Data;
namespace BreastCancerApp
{
 public class BreastCancerData
 {
 [ColumnName("SampleNo"), LoadColumn(0)]
 public float SampleNo { get; set; }


 [ColumnName("ClumpThickness"), LoadColumn(1)]
 public float ClumpThickness { get; set; }


 [ColumnName("UniformityOfCellSize"), LoadColumn(2)]
 public float UniformityOfCellSize { get; set; }


 [ColumnName("UniformityOfCellShape"), LoadColumn(3)]
 public float UniformityOfCellShape { get; set; }


 [ColumnName("MarginalAdhesion"), LoadColumn(4)]
 public float MarginalAdhesion { get; set; }


 [ColumnName("SingleEpithelialCellSize"), LoadColumn(5)]
 public float SingleEpithelialCellSize { get; set; }


 [ColumnName("BareNuclei"), LoadColumn(6)]
 public float BareNuclei { get; set; }


 [ColumnName("BlandChromatin"), LoadColumn(7)]
 public float BlandChromatin { get; set; }


 [ColumnName("NormalNucleoli"), LoadColumn(8)]
 public float NormalNucleoli { get; set; }


 [ColumnName("Mitoses"), LoadColumn(9)]
 public float Mitoses { get; set; }


 [ColumnName("ClassCategory"), LoadColumn(10)]
 public int ClassCategory { get; set; }

 public bool IsBenign { get; set; }
 }
}

Lalu kita buat class untuk prediksi dengan nama “PredictionBreastCancerData.cs”, isikan kode berikut:

using System;
using Microsoft.ML.Data;

namespace BreastCancerApp
{ 
 public class PredictionBreastCancerData : BreastCancerData
 {
 [ColumnName("PredictedLabel")]
 public bool Prediction { get; set; }

 public float Probability { get; set; }

 public float Score { get; set; }
 }
}

Kemudian kembali buka file “Program.cs” lalu masukan variable ini pada class Program:

static string TrainingFile = "breast-cancer-wisconsin.data";

Lalu di dalam void Main, masukan kode berikut:

var DataDir = new DirectoryInfo(GetAbsolutePath(@"..\..\..\Data"));
 //Create MLContext
 MLContext mlContext = new MLContext();

 //Load Data File
 var Lines = File.ReadAllLines(Path.Combine(DataDir.FullName, TrainingFile));
 var ListData = new List<BreastCancerData>();
 int counter = 0;
 Lines.ToList().ForEach(x => {
 counter++;
 //skip header
 if (counter > 1)
 {
 var Cols = x.Split(',');
 ListData.Add(new BreastCancerData() { SampleNo = float.Parse(Cols[0]), ClumpThickness = float.Parse(Cols[1]), UniformityOfCellSize = float.Parse(Cols[2]), UniformityOfCellShape = float.Parse(Cols[3]), MarginalAdhesion = float.Parse(Cols[4]), SingleEpithelialCellSize = float.Parse(Cols[5]), BareNuclei = float.Parse(Cols[6] == "?" ? "0" : Cols[6]), BlandChromatin = float.Parse(Cols[7]), NormalNucleoli = float.Parse(Cols[8]), Mitoses = float.Parse(Cols[9]), ClassCategory = int.Parse(Cols[10]), IsBenign = Cols[10] == "4" ? false:true });
 }
 });

 IDataView allData = mlContext.Data.LoadFromEnumerable<BreastCancerData>(ListData);
 
 DataOperationsCatalog.TrainTestData dataSplit = mlContext.Data.TrainTestSplit(allData, testFraction: 0.2);
 IDataView trainData = dataSplit.TrainSet;
 IDataView testData = dataSplit.TestSet;

Kode diatas untuk memuat data training dari file csv, lalu membaginya menjadi data training dan data test dengan proporsi 80:20. Untuk tipe label diambil dari kolom ClassCategory lalu kita mapping ke kolom baru dengan nama “IsReign” dengan tipe boolean ( 2-true, 4-false). Pola memuat data dari collection of object ini bisa diaplikasikan juga untuk memuat data dari database. Selanjutnya masukan code berikut:

// Data process configuration with pipeline data transformations
var dataPrepTransform = mlContext.Transforms.CopyColumns("Label", "IsBenign")
.Append(mlContext.Transforms.IndicateMissingValues(new[] { new InputOutputColumnPair("BareNuclei_MissingIndicator", "BareNuclei") }))
.Append(mlContext.Transforms.Conversion.ConvertType(new[] { new InputOutputColumnPair("BareNuclei_MissingIndicator", "BareNuclei_MissingIndicator") }))
.Append(mlContext.Transforms.ReplaceMissingValues(new[] { new InputOutputColumnPair("BareNuclei", "BareNuclei") }))
.Append(mlContext.Transforms.Concatenate("Features", new[] { "BareNuclei_MissingIndicator", "BareNuclei", "ClumpThickness", "UniformityOfCellSize", "UniformityOfCellShape", "MarginalAdhesion", "SingleEpithelialCellSize", "BlandChromatin", "NormalNucleoli", "Mitoses" }))
.Append(mlContext.Transforms.NormalizeMinMax("Features", "Features"))
.AppendCacheCheckpoint(mlContext);

// Create data prep transformer
ITransformer dataPrepTransformer = dataPrepTransform.Fit(trainData);
IDataView transformedTrainingData = dataPrepTransformer.Transform(trainData);

Kode diatas digunakan untuk melakukan pemilihan kolom-kolom yang menjadi features, dan menggantikan kolom yang nilainya kosong (?),  kemudian menentukan kolom yang menjadi label.  Selanjutnya masukan kode berikut:

 var SdcaEstimator = mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features");
 // Build machine learning model
 var trainedModel = dataPrepTransformer.Append(SdcaEstimator.Fit(transformedTrainingData));

Kode diatas untuk memilih algoritma ML untuk training, dan menjalankan proses training dengan memanggil method Fit. Selanjutnya kita akan mengevaluasi akurasi model ML kita dengan kode berikut:

// Apply data prep transformer to test data 
 IDataView testDataPredictions = trainedModel.Transform(testData);

 // Measure trained model performance
 // Extract model metrics and get eval params
 var metrics = mlContext.BinaryClassification.Evaluate(testDataPredictions);
 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 ===============");

Pada metrik pengukuran tersebut kita bisa menyimpulkan, 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 masukan 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));

Kode diatas berguna untuk menyimpan model ke dalam format binary. Selanjutnya masukan kode berikut:

 ITransformer mlModel = mlContext.Model.Load(GetAbsolutePath(modelRelativePath), out DataViewSchema inputSchema);
 var predEngine = mlContext.Model.CreatePredictionEngine<BreastCancerData, PredictionBreastCancerData>(mlModel);

 // Create sample data to do a single prediction with it 
 
 //ganas
 BreastCancerData sampleData = new BreastCancerData()
 {
 SampleNo = 0,
 ClumpThickness = 8,
 UniformityOfCellSize = 10,
 UniformityOfCellShape = 10,
 MarginalAdhesion = 8,
 SingleEpithelialCellSize = 7,
 BareNuclei = 10,
 BlandChromatin = 9,
 NormalNucleoli = 7,
 Mitoses = 1

 };
 // Try a single prediction
 PredictionBreastCancerData predictionResult = predEngine.Predict(sampleData);
 Console.WriteLine($"Single Prediction --> Predicted: { (predictionResult.Prediction ? "Jinak":"Ganas") }");

Kode diatas memuat  model dari binary file, lalu membuat class predictionEngine untuk melakukan single prediction. Lalu kita siapkan 1 contoh data untuk diprediksi, lalu panggil method Predict untuk melakukan inferensi. dan tampilkan hasilnya.

Selesai, yaay.. Nah sekarang rekan-rekan bisa mencoba dengan sample data sendiri. Cobalah membuat klasifikasi untuk mendeteksi email spam atau bukan, atau contoh lainnya.

Semoga bermanfaat, sampai bertemu di artikel selanjutnya. Oh ya, untuk source code lengkapnya silakan unduh dari sini.

Salam Makers

Loading

You May Also Like