Tutorial PyOD: Deteksi Anomali dan Outlier dengan Python

# Deteksi Anomali di Python dengan PyOD: Panduan Praktis Sebagian besar dataset di dunia nyata mengandung sebagian kecil data yang berperilaku berbeda dari mayoritas: pembayaran penipuan, pembacaan s...

By Ruby Abdullah · · tutorial
PyODAnomaly DetectionOutlier DetectionMachine LearningFraud DetectionPython

Deteksi Anomali di Python dengan PyOD: Panduan Praktis

Sebagian besar dataset di dunia nyata mengandung sebagian kecil data yang berperilaku berbeda dari mayoritas: pembayaran penipuan, pembacaan sensor yang rusak, percobaan intrusi, atau unit cacat di lini produksi. PyOD adalah pustaka matang bergaya scikit-learn yang mengemas lebih dari 40 algoritma deteksi outlier di balik satu antarmuka yang konsisten, sehingga mudah untuk mencoba beberapa metode dan membandingkannya. Tutorial ini membahas konsep inti, API terpadu, keluarga algoritma utama, dan alur kerja realistis dari awal hingga akhir.

Apa Itu Deteksi Outlier / Anomali?

Deteksi outlier (sering dipakai bergantian dengan deteksi anomali) adalah tugas mengidentifikasi observasi yang menyimpang begitu jauh dari mayoritas sehingga kemungkinan dihasilkan oleh proses yang berbeda. Tidak seperti klasifikasi biasa, biasanya Anda hanya punya sangat sedikit anomali berlabel, atau tidak sama sekali, sehingga sebagian besar pekerjaan bersifat tanpa pengawasan (unsupervised): model mempelajari seperti apa "normal" itu dan memberi skor pada setiap titik berdasarkan seberapa jauh ia dari wilayah normal tersebut.

Beberapa poin kerangka berpikir penting:

  • Anomali pada dasarnya jarang. Jika 40% data Anda "anomali," itu kemungkinan bukan masalah anomali melainkan masalah klasifikasi yang tidak seimbang.
  • Batas antara normal dan abnormal jarang tegas. Detektor menghasilkan skor kontinu; Andalah yang memilih ambang batas.
  • "Anomali" bergantung pada konteks. Transaksi sebesar USD 5.000 normal bagi satu pelanggan tetapi mencurigakan bagi yang lain.

Kasus Penggunaan di Dunia Nyata

  • Deteksi penipuan. Transaksi kartu kredit, klaim asuransi, pengambilalihan akun. Pola penipuan berubah seiring waktu, sehingga detektor unsupervised atau semi-supervised melengkapi mesin aturan.
  • Deteksi gangguan dan cacat. Sensor getaran, suhu, dan tekanan pada peralatan industri; barang cacat di manufaktur.
  • Deteksi intrusi jaringan. Volume lalu lintas yang tidak biasa, perilaku pemindaian port, atau pola koneksi yang berbeda dari baseline yang dipelajari.
  • Kontrol kualitas. Pengukuran di luar spesifikasi dalam satu batch produksi, atau pembacaan yang melenceng dari toleransi yang diharapkan.
  • Pembersihan data. Menangkap baris yang rusak, kesalahan satuan, dan gangguan sensor sebelum mencemari model di hilir.

Instalasi

PyOD sendiri ringan dan terutama bergantung pada NumPy, SciPy, dan scikit-learn.

pip install pyod

Beberapa detektor memiliki dependensi opsional. Model neural (misalnya AutoEncoder) memerlukan PyTorch, dan beberapa utilitas menggunakan paket tambahan:

# Diperlukan hanya untuk detektor berbasis jaringan saraf

pip install torch

Opsional, dipakai oleh sebagian helper kombinasi/visualisasi

pip install combo matplotlib

Anda dapat memverifikasi instalasi dari shell Python:

import pyod

print(pyod.version)

API Terpadu Bergaya scikit-learn

Setiap detektor di PyOD mengikuti siklus hidup yang sama, dan inilah alasan utama pustaka ini nyaman digunakan. Begitu Anda menguasai satu model, Anda menguasai semuanya.

Bagian-bagian umumnya adalah:

  • fit(X) — melatih model dari data latih. Deteksi umumnya unsupervised, jadi Anda tidak mengoper label.
  • decisionfunction(X) — mengembalikan skor outlier mentah untuk data baru. Semakin tinggi berarti semakin anomali.
  • predict(X) — mengembalikan label biner (0 = inlier, 1 = outlier).
  • predictproba(X) — mengembalikan probabilitas (terkalibrasi secara longgar) untuk menjadi outlier.
  • decisionscores — skor outlier mentah yang dihitung pada data latih saat fit.
  • labels — label biner yang diberikan ke data latih.
  • threshold — ambang batas skor yang dipakai untuk memisahkan inlier dari outlier.
  • contamination — parameter konstruktor yang memberi tahu model proporsi outlier yang diharapkan (default 0.1). Parameter ini dipakai untuk menetapkan threshold.

Nilai contamination sangat sentral. PyOD mengurutkan semua titik latih berdasarkan skor dan melabeli fraksi teratas sebesar contamination sebagai outlier. Ia tidak mengubah cara skor dihitung, hanya di mana ambang batas jatuh. Jika diset terlalu tinggi Anda mendapat banyak false positive; terlalu rendah dan Anda melewatkan anomali nyata.

Contoh Pertama: KNN pada Dataset 2D

PyOD menyertakan generator data yang membuat campuran inlier dan outlier yang disuntikkan, berguna untuk belajar dan untuk pemeriksaan kewarasan.

from pyod.models.knn import KNN

from pyod.utils.data import generatedata

0,1 dari titik adalah outlier

Xtrain, Xtest, ytrain, ytest = generatedata(

ntrain=500,

ntest=200,

nfeatures=2,

contamination=0.1,

randomstate=42,

)

clf = KNN(contamination=0.1)

clf.fit(Xtrain)

Hasil pada data latih disimpan pada objek yang sudah di-fit

trainscores = clf.decisionscores # skor mentah

trainlabels = clf.labels # 0 / 1

print("Ambang batas:", clf.threshold)

Terapkan ke data yang belum pernah dilihat

testscores = clf.decisionfunction(Xtest)

testlabels = clf.predict(Xtest)

testproba = clf.predictproba(Xtest)

print("Outlier yang diprediksi pada set uji:", testlabels.sum())

Detektor KNN memberi skor pada setiap titik berdasarkan jarak ke tetangga terdekat ke-k: titik yang jauh dari tetangganya berada di wilayah berkepadatan rendah dan mendapat skor tinggi. Anda dapat mengubah agregasinya dengan argumen method (largest, mean, atau median).

Keluarga Algoritma Utama

Tidak ada satu detektor terbaik. Metode yang berbeda mengasumsikan hal yang berbeda tentang apa yang membuat sebuah titik dianggap anomali, jadi memahami keluarga-keluarganya dan mencoba beberapa di antaranya akan menguntungkan.

Metode Berbasis Kedekatan (Proximity)

Metode ini bergantung pada jarak atau kepadatan lokal. Bekerja baik ketika anomali terpisah secara spasial dari kluster padat, tetapi sensitif terhadap penskalaan fitur dan bisa kesulitan pada dimensi yang sangat tinggi.

from pyod.models.knn import KNN

from pyod.models.lof import LOF

from pyod.models.cblof import CBLOF

knn = KNN(nneighbors=20, contamination=0.05)

lof = LOF(nneighbors=20, contamination=0.05) # Local Outlier Factor

cblof = CBLOF(nclusters=8, contamination=0.05) # Cluster-Based LOF

for name, model in [("KNN", knn), ("LOF", lof), ("CBLOF", cblof)]:

model.fit(Xtrain)

print(name, "menandai", model.labels.sum(), "outlier latih")

LOF membandingkan kepadatan lokal sebuah titik dengan tetangganya, sehingga menangkap anomali yang hanya abnormal relatif terhadap kluster lokal. CBLOF terlebih dahulu mengklusterkan data dan memberi skor titik berdasarkan jaraknya ke kluster besar, yang berskala lebih baik daripada LOF murni pada dataset besar.

Metode Linier dan Statistik

Metode ini memodelkan struktur data normal dengan proyeksi linier atau distribusi probabilitas.

from pyod.models.pca import PCA

from pyod.models.mcd import MCD

from pyod.models.ecod import ECOD

from pyod.models.copod import COPOD

pca = PCA(contamination=0.05) # error rekonstruksi di subruang utama

mcd = MCD(contamination=0.05) # jarak Mahalanobis yang robust

ecod = ECOD(contamination=0.05) # distribusi kumulatif empiris

copod = COPOD(contamination=0.05) # berbasis copula

for name, model in [("PCA", pca), ("MCD", mcd), ("ECOD", ecod), ("COPOD", copod)]:

model.fit(Xtrain)

print(name, "ambang batas:", round(model.threshold, 3))

ECOD dan COPOD layak disebut secara khusus. Keduanya bebas parameter dan cepat: keduanya memperkirakan probabilitas ekor (tail) dari setiap fitur lalu menggabungkannya, tanpa tetangga, kluster, atau komputasi jarak yang perlu disetel. Keduanya menangani data berdimensi tinggi dengan baik dan menjadi baseline default yang sangat baik. Ketika Anda tidak tahu harus mulai dari mana, jalankan ECOD lebih dulu.

Metode Ensemble dan Berbasis Pohon

Metode ini menggabungkan banyak detektor lemah atau memanfaatkan struktur pohon untuk mengisolasi titik.

from pyod.models.iforest import IForest

from pyod.models.featurebagging import FeatureBagging

from pyod.models.lof import LOF

iforest = IForest(nestimators=200, contamination=0.05, randomstate=42)

fb = FeatureBagging(baseestimator=LOF(), nestimators=20, contamination=0.05)

iforest.fit(Xtrain)

fb.fit(Xtrain)

print("Outlier IForest:", iforest.labels.sum())

print("Outlier FeatureBagging:", fb.labels.sum())

IForest (Isolation Forest) mengisolasi titik dengan pemisahan acak; anomali butuh lebih sedikit pemisahan untuk diisolasi, sehingga mendapat skor lebih tinggi. Metode ini cepat, menangani banyak fitur, dan merupakan pilihan serbaguna yang kuat. FeatureBagging melatih detektor dasar pada subset fitur acak lalu menggabungkannya, yang meningkatkan ketahanan pada dimensi tinggi.

Metode Neural

Untuk dataset yang lebih besar dan kompleks, sebuah autoencoder belajar merekonstruksi data normal; titik yang rekonstruksinya buruk akan ditandai. Ini memerlukan PyTorch.

from pyod.models.autoencoder import AutoEncoder

ae = AutoEncoder(

hiddenneuronlist=[32, 16, 16, 32],

epochnum=30,

batchsize=64,

contamination=0.05,

)

ae.fit(Xtrain)

print("Outlier AutoEncoder:", ae.labels.sum())

Detektor neural membutuhkan lebih banyak data dan penyetelan dibanding metode statistik, jadi gunakan ketika pendekatan yang lebih sederhana sudah mentok, bukan sebagai langkah pertama.

Menggabungkan Beberapa Detektor

Karena tidak ada satu metode yang mendominasi, menggabungkan beberapa metode bisa memberi hasil yang lebih robust. PyOD menyediakan utilitas kombinasi, tetapi pertama-tama Anda harus menormalkan skor agar detektor yang berbeda dapat dibandingkan.

import numpy as np

from pyod.models.knn import KNN

from pyod.models.iforest import IForest

from pyod.models.copod import COPOD

from pyod.utils.utility import standardizer

from pyod.models.combination import average, maximization, aom

detectors = [KNN(), IForest(randomstate=42), COPOD()]

Kumpulkan satu kolom skor per detektor

trainscores = np.zeros([Xtrain.shape[0], len(detectors)])

testscores = np.zeros([Xtest.shape[0], len(detectors)])

for i, clf in enumerate(detectors):

clf.fit(Xtrain)

trainscores[:, i] = clf.decisionscores

testscores[:, i] = clf.decisionfunction(Xtest)

Normalkan agar setiap detektor berkontribusi pada skala yang sama

trainscoresnorm, testscoresnorm = standardizer(trainscores, testscores)

Tiga strategi kombinasi umum

combavg = average(testscoresnorm)

combmax = maximization(testscoresnorm)

combaom = aom(testscoresnorm, nbuckets=3)

print("Bentuk kombinasi rata-rata:", combavg.shape)

Strateginya berbeda dalam karakter:

  • average stabil dan mengurangi varians; pilihan default yang baik.
  • maximization mengambil skor tertinggi di antara detektor, sehingga sensitif — berguna ketika satu detektor saja yang menandai suatu titik sudah harus diperhitungkan.
  • aom (Average of Maximum) dan moa (Maximum of Average) membagi detektor ke dalam beberapa keranjang (bucket) lalu memadukan kedua perilaku, menyeimbangkan stabilitas dan sensitivitas.

Melewatkan standardizer adalah kesalahan umum: skor Isolation Forest dan jarak KNN berada pada skala yang benar-benar berbeda, dan merata-ratakannya secara mentah membuat satu detektor mendominasi.

Penentuan Ambang Batas: Dari Skor ke Label

Skor mentah adalah keluaran jujur dari sebuah detektor; label biner adalah keputusan yang Anda terapkan di atasnya. PyOD menurunkan threshold dari contamination saat fit, tetapi Anda bebas memilih ambang batas sendiri pada skor.

import numpy as np

from pyod.models.iforest import IForest

clf = IForest(contamination=0.05, randomstate=42)

clf.fit(Xtrain)

scores = clf.decisionfunction(Xtest)

Opsi 1: gunakan ambang batas yang dipelajari model

labelsdefault = clf.predict(Xtest)

Opsi 2: pilih ambang batas persentil kustom

cutoff = np.percentile(clf.decisionscores, 97) # 3% teratas sebagai outlier

labelscustom = (scores > cutoff).astype(int)

print("Default ditandai:", labelsdefault.sum())

print("Kustom ditandai:", labelscustom.sum())

Memilih ambang batas adalah keputusan bisnis sekaligus statistik. Jika setiap kasus yang ditandai memicu tinjauan manual yang mahal, Anda ingin ambang batas konservatif (tinggi). Jika anomali yang terlewat berakibat fatal, Anda menerima lebih banyak false positive.

Evaluasi

Ketika Anda Punya Label

Jika Anda punya holdout berlabel sekalipun kecil, gunakanlah. evaluateprint dari PyOD melaporkan ROC-AUC dan precision@n dalam satu baris.

from pyod.models.knn import KNN

from pyod.utils.data import generatedata

from pyod.utils.data import evaluateprint

Xtrain, Xtest, ytrain, ytest = generatedata(

ntrain=500, ntest=200, contamination=0.1, randomstate=42

)

clf = KNN()

clf.fit(Xtrain)

Skor pada set uji

ytestscores = clf.decisionfunction(Xtest)

evaluateprint("KNN", ytest, ytestscores)

  • ROC-AUC mengukur kualitas pemeringkatan di seluruh ambang batas: apakah detektor mampu menempatkan anomali di atas titik normal? Metrik ini tidak bergantung pada ambang batas.
  • Precision@n bertanya: dari n titik yang dinilai detektor paling anomali (di mana n adalah jumlah anomali sebenarnya), berapa banyak yang benar? Ini sesuai dengan kenyataan praktis ketika anggaran tinjauan terbatas.

Ketika Anda Tidak Punya Label

Ini adalah kasus yang umum, dan benar-benar sulit. Tanpa ground truth Anda tidak dapat menghitung ROC-AUC secara jujur. Taktik praktis:

  • Minta pakar domain meninjau secara manual titik-titik peringkat teratas dan menilai precision@n secara informal.
  • Periksa stabilitas: apakah beberapa algoritma berbeda sepakat pada titik-titik yang sama yang ditandai? Kesepakatan yang tinggi menenangkan.
  • Suntikkan anomali sintetis dengan properti yang diketahui dan pastikan detektor menangkapnya.
  • Pantau tingkat penandaan dari waktu ke waktu; lonjakan mendadak biasanya berarti pergeseran (drift) atau masalah pipeline data, bukan lonjakan anomali nyata.

Jujurlah tentang ketidakpastian. Detektor unsupervised yang "menemukan 200 anomali" telah menemukan 200 titik tidak biasa; apakah itu anomali yang Anda pedulikan adalah pertanyaan terpisah yang tidak bisa dijawab oleh data semata.

Persistensi Model

Detektor yang sudah di-fit adalah objek Python biasa, jadi joblib bekerja baik untuk menyimpan dan memuat.

import joblib

from pyod.models.iforest import IForest

clf = IForest(contamination=0.05, randomstate=42)

clf.fit(Xtrain)

joblib.dump(clf, "iforestdetector.joblib")

Nanti, di proses lain

loaded = joblib.load("iforestdetector.joblib")

newlabels = loaded.predict(Xtest)

Simpan scaler yang sudah di-fit bersama modelnya. Memberi skor data baru dengan penskalaan berbeda dari saat latih adalah sumber prediksi buruk yang sering terjadi dan tersembunyi.

Contoh Lengkap dari Awal hingga Akhir: Menandai Transaksi Abnormal

Pipeline berikut mencerminkan cara Anda menangani masalah penipuan / transaksi abnormal tabular dalam praktik: skalakan fitur, pilih contamination secara sengaja, fit detektor yang robust, tentukan ambang batas, dan periksa kasus-kasus teratas.

import numpy as np

import pandas as pd

from sklearn.preprocessing import StandardScaler

from pyod.models.ecod import ECOD

from pyod.models.iforest import IForest

Pengganti sintetis untuk tabel transaksi.

Di produksi ini berasal dari gudang data Anda.

rng = np.random.defaultrng(42)

n = 5000

normal = pd.DataFrame({

"amount": rng.lognormal(mean=3.0, sigma=0.5, size=n),

"ntx24h": rng.poisson(5, size=n),

"merchantrisk": rng.normal(0.2, 0.1, size=n),

"distancekm": rng.exponential(10, size=n),

})

Segelintir transaksi abnormal yang disuntikkan

abnormal = pd.DataFrame({

"amount": rng.lognormal(mean=6.0, sigma=0.6, size=50),

"ntx24h": rng.poisson(40, size=50),

"merchantrisk": rng.normal(0.85, 0.1, size=50),

"distancekm": rng.exponential(400, size=50),

})

df = pd.concat([normal, abnormal], ignoreindex=True)

features = ["amount", "ntx24h", "merchantrisk", "distancekm"]

1. Skalakan: detektor berbasis jarak dan distribusi butuh fitur yang sebanding

scaler = StandardScaler()

X = scaler.fittransform(df[features])

2. Pilih contamination dari perkiraan awal tingkat penipuan.

Sekitar 50 / 5050 di sini; pada data nyata, mulai dari tingkat penipuan historis.

contamination = 0.01

3. Fit baseline bebas parameter dan ensemble pohon, lalu bandingkan

ecod = ECOD(contamination=contamination)

iforest = IForest(contamination=contamination, nestimators=200, randomstate=42)

ecod.fit(X)

iforest.fit(X)

df["ecodscore"] = ecod.decisionscores

df["iforestscore"] = iforest.decisionscores

df["ecodflag"] = ecod.labels

df["iforestflag"] = iforest.labels

4. Kesepakatan antar detektor adalah sinyal keyakinan yang berguna

df["bothflag"] = ((df["ecodflag"] == 1) & (df["iforestflag"] == 1)).astype(int)

print("ECOD menandai:", int(df["ecodflag"].sum()))

print("IForest menandai:", int(df["iforestflag"].sum()))

print("Keduanya sepakat:", int(df["bothflag"].sum()))

5. Periksa transaksi berisiko tertinggi untuk tinjauan manual

top = df.sortvalues("iforestscore", ascending=False).head(10)

print(top[features + ["iforestscore", "bothflag"]])

Pada sistem nyata Anda akan mengganti frame sintetis dengan kueri gudang data Anda, mengalibrasi contamination terhadap tingkat penipuan historis, mengarahkan penandaan yang disepakati ke antrean tinjauan, dan mengumpankan kembali setiap label yang terkonfirmasi untuk memperbaiki ambang batas seiring waktu.

Catatan Cakupan: GPU dan Deret Waktu

  • Akselerasi GPU. Untuk dataset yang sangat besar, pustaka pendamping pytod mengimplementasikan ulang beberapa detektor PyOD di atas tensor PyTorch agar dapat berjalan di GPU. API-nya mencerminkan PyOD, jadi migrasi sebagian besar hanya mengganti impor. Gunakan hanya ketika runtime CPU benar-benar menjadi hambatan.
  • Deret waktu (time series). PyOD memperlakukan setiap baris sebagai observasi independen; ia tidak memodelkan urutan temporal dengan sendirinya. Untuk deteksi anomali deret waktu Anda biasanya merekayasa fitur berjendela (windowed) atau bergeser (lagged) terlebih dahulu, atau memakai pustaka yang dibangun untuk urutan (proyek terkait tods menyasar ini). Jangan memberi timestamp mentah dan berharap konteks temporal.

Praktik Terbaik

  • Selalu skalakan fitur Anda. Detektor berbasis jarak dan kepadatan (KNN, LOF, CBLOF, PCA, MCD) jika tidak akan didominasi oleh fitur bermagnitudo besar. Metode berbasis pohon kurang sensitif, tetapi penskalaan jarang merugikan.
  • Pilih contamination secara sengaja. Dasarkan pada perkiraan awal tingkat anomali, bukan default 0.1. Saat ragu, cenderung konservatif dan periksa distribusi skornya.
  • Mulai dengan baseline bebas parameter. ECOD dan COPOD memberi referensi yang kuat, cepat, dan tanpa penyetelan sebelum Anda berinvestasi pada model yang lebih berat.
  • Ensemble untuk ketahanan. Gabungkan beberapa detektor yang beragam dengan standardizer plus average; kesepakatan antar metode adalah sinyal keyakinan yang bermakna.
  • Bersikap skeptis terhadap evaluasi tanpa label. Skor unsupervised memeringkat tingkat ketidakbiasaan, bukan definisi spesifik Anda tentang "buruk." Validasi dengan pakar domain dan kesepakatan antar detektor.
  • Simpan scaler bersama modelnya. Praproses yang tidak cocok saat penilaian secara diam-diam menurunkan kualitas prediksi.
  • Pisahkan skor dari keputusan. Simpan skor mentah; tetapkan ambang batas sesuai biaya false positive versus anomali yang terlewat.

Kesimpulan dan Poin Penting

PyOD mengubah deteksi anomali dari kumpulan paper yang tersebar menjadi satu perangkat yang konsisten. API terpadu fit / decision_function / predict berarti Anda dapat menukar algoritma dengan perubahan satu baris dan membandingkannya secara adil. Mulailah sederhana dengan detektor bebas parameter seperti ECOD, tambahkan Isolation Forest untuk sudut pandang berbasis pohon, dan gabungkan keduanya saat Anda membutuhkan ketahanan.

Poin penting:

  • Deteksi anomali sebagian besar bersifat unsupervised: model mempelajari "normal" dan memberi skor pada penyimpangan.
  • contamination menetapkan ambang batas, bukan skornya; pilih berdasarkan pengetahuan domain.
  • Skalakan fitur, terutama untuk metode berbasis kedekatan.
  • ECOD dan COPOD adalah default yang cepat, bebas parameter, dan ramah dimensi tinggi.
  • Gabungkan detektor yang beragam dengan normalisasi skor untuk ketahanan.
  • Evaluasi dengan ROC-AUC dan precision@n ketika label ada; andalkan tinjauan pakar dan kesepakatan antar metode ketika tidak ada.
  • Simpan scaler yang sudah di-fit bersama detektornya.

Dengan blok-blok bangunan ini Anda dapat beranjak dari pemeriksaan kewarasan KNN cepat menuju pipeline deteksi tingkat produksi menggunakan pustaka dan kerangka berpikir yang sama sepanjang prosesnya.

Artikel Terkait

Tutorial Lengkap Comet ML: Platform MLOps untuk Experiment Tracking dan Model Management

Tutorial Lengkap Comet ML: Platform MLOps untuk Experiment Tracking dan Model Management Dalam dunia machine learning mo...

Tutorial MLX: Framework Machine Learning Apple untuk Apple Silicon

Tutorial MLX: Framework Machine Learning Apple untuk Apple Silicon MLX adalah framework machine learning open-source dar...

Tutorial SHAP: Explainable AI dan Interpretasi Model

SHAP - Panduan Praktis Explainable AI dan Interpretabilitas Model Model machine learning makin sering dipakai untuk meng...

Tutorial spaCy: NLP Berskala Industri dengan Python

spaCy: NLP Kelas Industri di Python spaCy adalah pustaka open-source untuk pemrosesan bahasa alami (NLP) yang dirancang ...