128 lines
4.7 KiB
Python
128 lines
4.7 KiB
Python
# 4 mencari nilai K
|
||
import joblib
|
||
import pandas as pd
|
||
import numpy as np
|
||
import math
|
||
import matplotlib.pyplot as plt
|
||
import os
|
||
from sklearn.neighbors import KNeighborsClassifier
|
||
from sklearn.model_selection import cross_val_score, GridSearchCV
|
||
|
||
print("🔬 [EKSPERIMEN] Membandingkan 3 Metode Mencari Nilai K Terbaik...")
|
||
|
||
# --- PENYESUAIAN FOLDER ---
|
||
FOLDER_OUTPUT = 'virtualEnvironment/output'
|
||
FOLDER_IMAGES = 'virtualEnvironment/images'
|
||
|
||
# 0. CEK KEAMANAN
|
||
file_xtrain = f'{FOLDER_OUTPUT}/X_train.pkl'
|
||
if not os.path.exists(file_xtrain):
|
||
raise FileNotFoundError(f"❌ File '{file_xtrain}' tidak ditemukan! Pastikan Tahap 1 sudah dijalankan.")
|
||
|
||
# Pastikan folder images ada di dalam virtualEnvironment
|
||
os.makedirs(FOLDER_IMAGES, exist_ok=True)
|
||
|
||
# 1. LOAD DATA
|
||
X_train = joblib.load(file_xtrain)
|
||
y_train = joblib.load(f'{FOLDER_OUTPUT}/y_train.pkl')
|
||
jumlah_data = X_train.shape[0]
|
||
|
||
print(f" - Jumlah Data Latih: {jumlah_data} baris")
|
||
print("-" * 50)
|
||
|
||
results = [] # Untuk menyimpan hasil perbandingan
|
||
|
||
# =========================================================
|
||
# METODE 1: AKAR KUADRAT (Square Root Rule)
|
||
# Rumus: K = Akar(Total Data)
|
||
# =========================================================
|
||
print("1️⃣ Menguji Metode Akar Kuadrat...")
|
||
k_sqrt = int(math.sqrt(jumlah_data))
|
||
|
||
# Aturan: K harus ganjil biar gak seri (draw)
|
||
if k_sqrt % 2 == 0:
|
||
k_sqrt += 1
|
||
|
||
# Uji Akurasinya (Pakai n_jobs=-1 biar ngebut)
|
||
knn_sq = KNeighborsClassifier(n_neighbors=k_sqrt, metric='cosine')
|
||
scores_sq = cross_val_score(knn_sq, X_train, y_train, cv=5, scoring='accuracy', n_jobs=-1)
|
||
acc_sq = scores_sq.mean() * 100
|
||
|
||
print(f" -> Hasil: K={k_sqrt}, Akurasi={acc_sq:.2f}%")
|
||
results.append({'Metode': 'Akar Kuadrat', 'K': k_sqrt, 'Akurasi': acc_sq})
|
||
|
||
# =========================================================
|
||
# METODE 2: ELBOW METHOD (Metode Siku)
|
||
# Coba manual dari 1 sampai 40, lalu cari error terkecil
|
||
# =========================================================
|
||
print("\n2️⃣ Menguji Metode Elbow (Looping 1-40)...")
|
||
print(" (Tunggu sebentar, sedang menghitung manual...)")
|
||
error_rates = []
|
||
acc_rates = []
|
||
k_range = range(1, 41, 2) # Coba angka ganjil: 1, 3, 5, ... 39
|
||
|
||
best_k_elbow = 0
|
||
best_acc_elbow = 0
|
||
|
||
for k in k_range:
|
||
knn = KNeighborsClassifier(n_neighbors=k, metric='cosine')
|
||
# Pakai n_jobs=-1 di sini juga biar loopingnya gak kelamaan
|
||
scores = cross_val_score(knn, X_train, y_train, cv=5, scoring='accuracy', n_jobs=-1)
|
||
acc = scores.mean()
|
||
|
||
# Simpan data buat grafik
|
||
acc_rates.append(acc)
|
||
error_rates.append(1 - acc) # Error = 100% - Akurasi
|
||
|
||
# Cek apakah ini rekor terbaik?
|
||
if acc > best_acc_elbow:
|
||
best_acc_elbow = acc
|
||
best_k_elbow = k
|
||
|
||
print(f" -> Hasil Terbaik di Range Ini: K={best_k_elbow}, Akurasi={best_acc_elbow*100:.2f}%")
|
||
results.append({'Metode': 'Elbow (Manual)', 'K': best_k_elbow, 'Akurasi': best_acc_elbow*100})
|
||
|
||
# Bikin Grafik Elbow
|
||
plt.figure(figsize=(10, 6))
|
||
plt.plot(k_range, error_rates, color='red', linestyle='dashed', marker='o',
|
||
markerfacecolor='blue', markersize=8)
|
||
plt.title('Grafik Elbow (Mencari Error Terkecil)', fontsize=14, fontweight='bold', pad=15)
|
||
plt.xlabel('Nilai K', fontsize=12, fontweight='bold')
|
||
plt.ylabel('Tingkat Error', fontsize=12, fontweight='bold')
|
||
plt.grid(True, linestyle='--', alpha=0.6)
|
||
|
||
# Simpan ke folder images
|
||
nama_gambar_elbow = f'{FOLDER_IMAGES}/grafik_elbow_knn.png'
|
||
plt.savefig(nama_gambar_elbow, dpi=300, bbox_inches='tight')
|
||
print(f" 🖼️ Grafik Elbow tersimpan: {nama_gambar_elbow}")
|
||
plt.close() # Tutup grafik biar memori lega
|
||
|
||
# =========================================================
|
||
# METODE 3: GRID SEARCH CV (Validasi Silang)
|
||
# Ini metode paling 'Sultan' dan Valid
|
||
# =========================================================
|
||
print("\n3️⃣ Menguji Metode Grid Search CV (Otomatis)...")
|
||
param_grid = {'n_neighbors': [3, 5, 7, 9, 11, 15, 19, 21, 25, 29]}
|
||
grid = GridSearchCV(KNeighborsClassifier(metric='cosine'), param_grid, cv=5, scoring='accuracy', n_jobs=-1)
|
||
grid.fit(X_train, y_train)
|
||
|
||
k_grid = grid.best_params_['n_neighbors']
|
||
acc_grid = grid.best_score_ * 100
|
||
|
||
print(f" -> Hasil: K={k_grid}, Akurasi={acc_grid:.2f}%")
|
||
results.append({'Metode': 'Grid Search CV', 'K': k_grid, 'Akurasi': acc_grid})
|
||
|
||
# =========================================================
|
||
# KESIMPULAN AKHIR
|
||
# =========================================================
|
||
print("\n" + "="*50)
|
||
print("🏆 TABEL PERBANDINGAN METODE PENENTUAN K")
|
||
print("="*50)
|
||
df_res = pd.DataFrame(results)
|
||
print(df_res.to_string(index=False))
|
||
print("-" * 50)
|
||
|
||
# Cari pemenang
|
||
best_method = df_res.loc[df_res['Akurasi'].idxmax()]
|
||
print(f"✅ REKOMENDASI: Gunakan K = {best_method['K']}")
|
||
print(f" (Berdasarkan metode {best_method['Metode']} dengan akurasi tertinggi)") |