Machine Learning: Membuat Logistic Regression dari Scratch
Story ini adalah story lanjutan dari Machine Learning: Logistic Regression. Disini, saya akan mengkoding Logistic Regression dengan bahasa Python dari scratch / tidak pake library.
Untuk mengerti apa yang dikodekan pada story ini, sebaiknya juga sambil membuka story sebelumnya tentang logistic regression di tab lainnya (jadi bisa switch2 lihat-lihat teori sambil ngoding).
Persiapan Data
Pada story kali ini, data yang digunakan adalah data bunga Iris yang dimodifikasi. Kenapa dimodifikasi? karena Logistic Regression pada dasarnya hanya bisa mengklasifikasikan 2 kelas berbeda, sementara data Iris memiliki 3 kelas.
Import data iris dari pustaka sklearn. Karena hanya memerlukan 2 kelas saja, hanya 100 data saja yang kita simpan ke dalam variabel x dan y. (data iris berisi 150 data, namun 50 data paling akhir merupakan kelas ketiga).
Linear Function dan Logistic Function
Sekarang, kita deklarasikan fungsi untuk mencari Linear Function dan Logistic Function. Untuk operasi matematika kita gunakan pustaka numpy.
Linear function akan me-return dot product dari data dan weights / bobot. Misalkan pada data iris, fiturnya berupa sepal_length, sepal_width, petal_length, pedal_width disimpan dalam array sebagai berikut: [2.4, 4.1, 3.0, 3.2]. Misalkan bobotnya adalah [0.1, 0.2, 0.3, 0.4], maka hasil linear function adalah seperti pada gambar dibawah:
Untuk logistic function, cukup jelas sepertinya, tinggal memasukan 3.24 ke dalam fungsi logisticFunction() dan hasilnya akan keluar.
Inisialisasi Bobot Awal
Jumlah bobot akan selalu sama dengan jumlah fitur pada data. Misalnya pada data iris terdapat 4 fitur, maka bobotnya juga harus 4 (seperti variable x untuk fitur dan w untuk bobot pada gambar sebelumnya yang berjumlah 4 buah keduanya).
Inisialisasi bobot kita buat agar bisa mengikuti banyaknya fitur data yang dilatih secara otomatis.
variabel featureCount menyimpan banyaknya fitur dari data ke 0, yaitu sejumlah 4. Selanjutnya kita simpan bobot awal dengan membuat array sebesar featureCount berisi angka random antara 0–1. Dalam menentukan angka random, digunakan fungsi random dari pustaka numpy.
Update Bobot
Kita buat fungsi untuk melakukan update bobot dengan nama updateWeights(). Fungsi ini akan menerima 4 input, yaitu bobot awal (weights), learning rate, datum (x), dan target dari datum tersebut (y).
Variabel temp merupakan variabel temporary / sementara untuk menyimpan bobot baru. Variabel temp diinisialisasikan sebagai array zero sebesar banyaknya fitur (jika di run, variabel temp diatas akan menyimpan array [0.0, 0.0, 0.0, 0.0]). Kemudian setiap posisi 0.0 akan diupdate dengan 2 persamaan pada teori di story sebelumnya:
Variabel d adalah dLoss/dB pada persamaan diatas. Yprediksi adalah hasil dari fungsi logisticFunction() dan Yaktual adalah target y. Pada fungsi X pada dLoss/dB adalah x[i] pada fungsi updateWeights(). Kalau ada yang bingung kenapa x[i], karena bobot yang diubah adalah bobot posisi ke-i, sehingga menggunakan fitur x yang dikalikan dengan bobot tersebut.
Kemudian masuk ke dalam peng-update-an bobot. Variabel temp akan diisi dengan bobot lama weights[i] dikurangi dengan perkalian learningRate dengan d.
Proses Learning
Fungsi-fungsi yang sudah kita buat, kemudian kita susun agar menjadi model yang bisa membedakan bunga iris. Pertama, saya set banyaknya epoch adalah 100. variabel ListResult akan menympan hasil prediksi pada epoch tersebut, sehingga bisa dicatat nilai Loss dan Akurasi.
Untuk setiap epoch, kita loop data iris yang telah kita simpan di variabel x (Gambar 1). Append hasil prediksi ke dalam variabel ListResult, kemudian update bobot dengan fungsi updateWeights(). Print juga nilai Loss dan Accuracy dari setiap epoch agar terlihat kalau model belajar mengenali bunga iris.
Dari Gambar 8, terlihat bahwa model menjadi semakin baik seiring bertambahnya epoch (nilai Loss yang semakin mengecil dan nilai akurasi yang semakin meningkat).
Yey, kita berhasil membuat model Logistic Regression dari scratch!
Tambahan 1: Fungsi Loss
Fungsi Loss dan Akurasi pada gambar sebelumnya akan dijelaskan pada bagian ini.
Fungsi Loss yang didefinisikan sebagai logisticRegressionLoss() menerima 2 variabel, yaitu yPredicted dan yActual. yPredicted adalah array hasil prediksi, dengan kata lain variabel ini akan diisi dengan array listResult (lihat Gambar 8). yActual adalah data kelas target, yaitu variabel y yang berisi kelas sesungguhnya dari data iris (lihat Gambar 1).
Kenapa ada fungsi mean pada Gambar 9? karena Loss yang dihitung adalah per epoch, jadi masing-masing 100 hasil prediksi dalam 1 epoch akan dihitung lossnya terhadap 100 data target sebenarnya, kemuadian dibagi 100.
Tambahan 2: Fungsi Akurasi
Input dari fungsi logisticRegressionAccuracy() sama dengan input untuk fungsi Loss. Pada tahapan ini, hasil prediksi yang disimpan pada listResult (Gambar 8) dibulatkan menjadi angka 0 atau 1.
Type-cast dengan astype(int) karena kalau tidak di type-cast akan menjadi 0.0 dan 1.0, sementara data y isinya angka 0 dan 1 (desimal dan int tidak bisa dibandingkan). Kemudian, kita hitung nilai akurasi, yaitu banyaknya nilai yPredicted dan yActual yang sama pada posisi tertentu, kemudian dibagi banyaknya data.
Pada tahapan ini bisa menggunakan looping sederhana sebenarnya, tapi saya menggunakan operasi bitwise XOR karena menurut saya ngodingnya lebih pendek.
XOR ketika 1 ketemu 0 atau sebaliknya, nilainya akan menjadi 1. Sementara ketika 1 ketemu 1 atau 0 ketemu 0, nilainya akan menjadi 0. Jadi untuk menghitung banyaknya nilai yPredicted dan yActual yang sama pada posisi tertentu, tinggal hitung saja banyaknya kemunculan angka 0 hasil operasi XOR :D.
Tambahan 3: Membuat Class agar seperti library-library yang ada
Intinya kode yang diatas diubah jadi class, jadi bisa reusable. Juga ditambahkan fungsi fit() dan predict() agar memudahkan proses pemakaian.
Penutup
Demikian story tentang Membuat Logistic Regression dari Scratch, semoga story kali ini cukup membantu mengerti proses-proses dan ilmu yang berkaitan dengan Logistic Regression. Terima kasih telah meluangkan waktu untuk membaca :D
(Jangan lupa kunjungi Github Logistic Regression dengan mengunjungi https://github.com/vincentmichael089/ML-Logistic-Regression. Repository berisi PDF slide presentasi tentang Logistic Regression dan Python Notebooks menyelesaikan masalah klasifikasi dengan Logistic Regression library SciKit-Learn, serta file python Logistic Regression dari scratch)