Sepanjang Section ini kita menulis kode prosedural: variabel, loop, fungsi, modul, hingga penyelamatan program lewat try-except pada chapter Penanganan Error
. Begitu membuka dokumentasi library data science, bentuknya tiba-tiba berubah menjadi model.fit(X, y), df.head(), atau ax.plot(hari, penjualan) — kode yang penuh tanda titik. Titik-titik itu bukan gaya penulisan; itu adalah tanda bahwa kita sedang bekerja dengan object. Pada chapter ini kita pelajari konsep di baliknya — pemrograman berorientasi object (object-oriented programming, OOP) — dengan sasaran yang terbatas dan praktis: cukup untuk membaca kode library seperti scikit-learn dan pandas, bukan untuk menjadi arsitek OOP. Pemahaman ini adalah pintu terakhir sebelum kita memasuki tiga library inti data science.
Class: Cetakan yang Menyimpan Data dan Perilaku #
Kita mulai dari dua kata kuncinya. Class adalah cetakan: definisi yang menyatakan data apa saja yang dimiliki setiap wujud dan perilaku apa saja yang bisa dilakukan wujud tersebut. Object (disebut juga instance) adalah satu wujud hasil pencetakan. Satu class bisa dicetak berkali-kali, dan setiap object membawa salinan datanya sendiri. Proses mencetak object dari sebuah class disebut instansiasi.
Empat istilah berikut akan muncul terus-menerus di dokumentasi library, jadi kita petakan dulu ke bentuk kodenya:
| Istilah | Wujud pada kode | Peran |
|---|---|---|
| Class | class TarifTaksi: | Cetakan: definisi atribut dan method |
| Object/instance | taksi_bandung = TarifTaksi(8000, 2500) | Satu wujud hasil cetakan |
| Atribut | taksi_bandung.tarif_per_km | Data yang menempel pada satu object |
| Method | taksi_bandung.hitung_tarif(5) | Fungsi yang menempel pada satu object |
Dua nama khusus menyertainya: __init__ adalah method yang otomatis berjalan ketika object dibuat, dan self adalah nama baku untuk parameter pertama setiap method — ia menunjuk object yang sedang memanggil method tersebut. Keduanya akan terlihat wujudnya pada contoh pertama.
Class Pertama: TarifTaksi #
Kasusnya sederhana: tarif taksi online terdiri dari tarif buka pintu dan tarif per kilometer, dan kedua angka tersebut berbeda antar kota. Alih-alih memakai dua variabel lepas dan satu fungsi yang menerima banyak parameter, kita bungkus setelan tarif menjadi satu class TarifTaksi yang punya method penghitung:
class TarifTaksi:
"""Tarif taksi online: tarif buka pintu + tarif per kilometer."""
def __init__(self, tarif_buka, tarif_per_km):
self.tarif_buka = tarif_buka
self.tarif_per_km = tarif_per_km
def hitung_tarif(self, jarak_km):
return self.tarif_buka + self.tarif_per_km * jarak_km
taksi_bandung = TarifTaksi(8000, 2500)
taksi_surabaya = TarifTaksi(10000, 3000)
print("Bandung 5 km :", taksi_bandung.hitung_tarif(5))
print("Surabaya 5 km :", taksi_surabaya.hitung_tarif(5))
print("Bandung 8 km :", taksi_bandung.hitung_tarif(8))Output yang Dihasilkan:
Bandung 5 km : 20500
Surabaya 5 km : 25000
Bandung 8 km : 28000Mari kita telaah baris-baris kode di atas:
- Baris 1 (
class TarifTaksi:): mendefinisikan cetakan baru. Seluruh definisi atribut dan method hidup di blok indentasi di bawahnya, sama seperti isi sebuah fungsi. - Baris 4-6 (
__init__): method ini berjalan otomatis pada saat instansiasi. Parametertarif_bukadantarif_per_kmberasal dari pemanggilanTarifTaksi(8000, 2500); nilai keduanya lalu disimpan sebagai atribut lewatself.tarif_bukadanself.tarif_per_km. - Baris 8-9 (
hitung_tarif): method penghitung membaca tarif dariself— data yang sudah menempel pada object — dan hanya menerimajarak_kmdari pemanggil. Karena itulah pemanggilantaksi_bandung.hitung_tarif(5)cukup satu argumen: tarif tidak perlu dikirim ulang. - Baris 12-13: dua instansiasi menghasilkan dua object dengan setelan tarif berbeda — 20500 berasal dari
8000 + 2500*5, sedangkan 25000 dari10000 + 3000*5.
Inilah perbedaan mendasar dengan fungsi murni: fungsi menerima semua data lewat parameter setiap kali dipanggil, sedangkan object menyimpan datanya sendiri dan method tinggal membacanya dari self.
Object yang Mandiri: Pelanggan dan isinstance #
Setiap object memiliki salinan atributnya sendiri, dan perubahan pada satu object tidak menyentuh object lain dari class yang sama. Kita buktikan pada class Pelanggan Toko Kopi Kita, sekaligus memperkenalkan isinstance — fungsi untuk memeriksa asal-usul sebuah object:
class Pelanggan:
"""Pelanggan Toko Kopi Kita dengan poin loyalitas."""
def __init__(self, nama, poin):
self.nama = nama
self.poin = poin
def hitung_diskon(self):
"""Diskon 10 persen bila poin minimal 50."""
if self.poin >= 50:
return 10
return 0
budi = Pelanggan("Budi", 65)
siti = Pelanggan("Siti", 20)
print(f"Diskon {budi.nama}: {budi.hitung_diskon()}%")
print(f"Diskon {siti.nama}: {siti.hitung_diskon()}%")
budi.poin = 40 # poin Budi ditukar; hanya object budi yang berubah
print(f"Setelah tukar poin, diskon Budi : {budi.hitung_diskon()}%")
print(f"Diskon Siti tidak terpengaruh : {siti.hitung_diskon()}%")
print("budi adalah Pelanggan :", isinstance(budi, Pelanggan))
print("budi adalah angka int :", isinstance(budi, int))Output yang Dihasilkan:
Diskon Budi: 10%
Diskon Siti: 0%
Setelah tukar poin, diskon Budi : 0%
Diskon Siti tidak terpengaruh : 0%
budi adalah Pelanggan : True
budi adalah angka int : FalseAda tiga perilaku yang per dicatat. Pertama, budi.hitung_diskon() mengembalikan 10 karena 65 poin melampaui batas 50, sementara Siti dengan 20 poin belum berhak diskon. Kedua, penugasan budi.poin = 40 mengubah atribut milik budi saja — diskon Siti tetap 0 dan poin Siti tidak tersentuh; tiap instans benar-benar terpisah. Ketiga, isinstance(budi, Pelanggan) mengembalikan True sedangkan isinstance(budi, int) mengembalikan False; fungsi ini berguna ketika sebuah library mengembalikan object dan kita perlu memastikan jenisnya sebelum diproses.
Pola .fit() dan .predict() pada API Library #
Sekarang kita tahu mengapa tanda titik itu penting. Seluruh API scikit-learn dibangun dari object yang punya siklus dua tahap: latih dengan model.fit(X, y), lalu pakai dengan model.predict(X). Alih-alih langsung memakai scikit-learn, kita tiru pola tersebut pada class buatan sendiri — SederhanaRataRata, model yang memprediksi penjualan selalu dengan rata-rata hasil pelatihan:
class SederhanaRataRata:
"""Model yang selalu memprediksi rata-rata target data latih."""
def fit(self, X, y):
"""Pelajari pola dari data: simpan rata-rata y pada object."""
self.rata_ = sum(y) / len(y)
return self
def predict(self, X):
"""Prediksi setiap baris X dengan rata-rata tersebut."""
return [self.rata_] * len(X)
# X: jumlah pengunjung kafe per hari; y: gelas kopi susu terjual
X = [120, 150, 90, 200, 175]
y = [70, 85, 55, 110, 90]
model = SederhanaRataRata()
model.fit(X, y) # 1. latih: object menyimpan hasil belajarnya
prediksi = model.predict(X) # 2. pakai: object menghasilkan angka
print("Rata-rata dipelajari :", model.rata_)
print("Prediksi :", prediksi)
print("Nilai sebenarnya :", y)Output yang Dihasilkan:
Rata-rata dipelajari : 82.0
Prediksi : [82.0, 82.0, 82.0, 82.0, 82.0]
Nilai sebenarnya : [70, 85, 55, 110, 90]Mari kita baca ulang contoh tersebut dengan kacamata tiga baris terakhirnya:
model = SederhanaRataRata(): instansiasi — sama sepertiTarifTaksi(8000, 2500), hanya saja class ini tidak menuntut lewat__init__.model.fit(X, y): methodfitmenghitung rata-ratay(410 dibagi 5 = 82.0) lalu menyimpannya pada object sebagai atributself.rata_, bukan mengembalikannya sebagai nilai balik. Perhatikan pula parameterX: karena model rata-rata tidak membaca fitur,Xhanya dipakai untuk menghitunglen(X)dipredict.model.predict(X): methodpredictmembacaself.rata_dan mengembalikan satu prediksi per barisX— lima baris, lima angka 82.0.
Mulai bab machine learning nanti kita akan menulis model = LinearRegression(), model.fit(X, y), model.predict(X_baru) — tiga baris yang bentuknya persis contoh di atas; satu-satunya perbedaan adalah fit() milik LinearRegression mempelajari rumus yang jauh lebih pintar dari sekadar rata-rata.
Sebagai penutup konsep: di balik layar, library-library tersebut juga memakai inheritance (pewarisan) — mekanisme class baru menerima atribut dan method dari class lain. Untuk membaca dan memakai API-nya, kita tidak perlu membedah mekanisme itu; cukup tahu istilahnya agar dokumentasi tidak asing.
Rangkuman #
- Class adalah cetakan; object adalah wujud hasil cetakan; pencetakan disebut instansiasi dan dilakukan dengan memanggil nama class seperti fungsi.
- Atribut menampung data pada satu object (
objek.nama); method adalah perilakunya (objek.nama());__init__mengisi nilai awal danselfmenunjuk object pemanggil. - Tiap instans berdiri sendiri — mengubah atribut satu object tidak memengaruhi object lain;
isinstance(objek, Class)memeriksa asal-usul object. - API library data science berbentuk object:
model.fit()/model.predict()di scikit-learn,df.head()di pandas,ax.plot()di matplotlib — semuanya method yang dipanggil lewat titik. - Atribut hasil pelatihan scikit-learn memakai akhiran garis bawah, misalnya
coef_.
Konsep titik di saku kita sekarang. Library pertama yang kita bedah, NumPy, justru memperlihatkan konsepnya secara halus: array NumPy adalah object yang membawa data numerik beserta puluhan method agregasi seperti arr.sum() dan arr.mean(). Kita masuk ke sana pada chapter berikutnya, Dasar NumPy
.
Referensi #
- scikit-learn — LinearRegression
— halaman API resmi; perhatikan method
fit(X, y)danpredict(X)beserta atributcoef_yang mengikuti konvensi garis bawah.