# -*- coding: utf-8 -*- import sys, io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') """ Evaluasi Efektivitas Sistem Rekomendasi Gemini AI Aplikasi Muning Assistant - Amor Coffee Menggunakan: scikit-learn, pandas, matplotlib """ import pandas as pd import numpy as np from sklearn.metrics import ( confusion_matrix, classification_report, accuracy_score, precision_score, recall_score, f1_score, ConfusionMatrixDisplay ) import matplotlib matplotlib.use('Agg') # non-interactive, tidak buka window GUI import matplotlib.pyplot as plt matplotlib.rcParams['font.family'] = 'DejaVu Sans' # ───────────────────────────────────────────── # BAGIAN 1: DATA HASIL PENGUJIAN (30 SKENARIO) # ───────────────────────────────────────────── # Keterangan kegagalan yang tercatat saat pengujian: # S07 - Kategori: AI merekomendasikan bundling, padahal diminta minuman saja # S22 - Kategori: AI merekomendasikan makanan, padahal diminta minuman # S14 - Budget : Harga rekomendasi melebihi budget Rp15.000 # S29 - Budget : Harga rekomendasi melebihi budget Rp20.000 # S08 - Alergen : Rekomendasi mengandung susu (pengguna alergi susu) # Selebihnya (25 skenario) → semua kriteria terpenuhi ✅ data = { "skenario": [f"S{i:02d}" for i in range(1, 31)], # Kriteria 1: Kesesuaian Kategori (minuman/makanan/bundling) "kategori_expected": [1]*30, "kategori_actual": [ 1,1,1,1,1, 1,0,1,1,1, # S07 = 0 1,1,1,1,1, 1,1,1,1,1, 1,1,0,1,1, 1,1,1,1,1, # S23 = 0 ], # Kriteria 2: Kepatuhan Batas Budget "budget_expected": [1]*30, "budget_actual": [ 1,1,1,1,1, 1,1,1,1,1, 1,1,1,0,1, 1,1,1,1,1, # S14 = 0 1,1,1,1,1, 1,1,1,0,1, # S29 = 0 ], # Kriteria 3: Bebas Alergen "alergen_expected": [1]*30, "alergen_actual": [ 1,1,1,1,1, 1,1,0,1,1, # S08 = 0 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, ], # Kriteria 4: Kevalidan Keseluruhan (semua kriteria terpenuhi) "overall_expected": [1]*30, "overall_actual": [ 1,1,1,1,1, 1,0,0,1,1, # S07,S08 = 0 1,1,1,0,1, 1,1,1,1,1, # S14 = 0 1,1,0,1,1, 1,1,1,0,1, # S23,S29 = 0 ], } df = pd.DataFrame(data) # ───────────────────────────────────────────── # BAGIAN 2: FUNGSI EVALUASI PER KRITERIA # ───────────────────────────────────────────── def evaluasi_kriteria(y_true, y_pred, nama_kriteria): print(f"\n{'='*55}") print(f" EVALUASI: {nama_kriteria.upper()}") print(f"{'='*55}") acc = accuracy_score(y_true, y_pred) prec = precision_score(y_true, y_pred, zero_division=0) rec = recall_score(y_true, y_pred, zero_division=0) f1 = f1_score(y_true, y_pred, zero_division=0) cm = confusion_matrix(y_true, y_pred) tn, fp, fn, tp = cm.ravel() if cm.size == 4 else (0, 0, 0, sum(y_true)) print(f"\n Confusion Matrix:") print(f" +-----------------------------+") print(f" | Prediksi AI |") print(f" | Valid | Tidak Valid |") print(f" +----------+------------------+") print(f" | Aktual Valid | TP={tp:3d} FN={fn:3d} |") print(f" | Aktual Tdk V | FP={fp:3d} TN={tn:3d} |") print(f" +-----------------------------+") print(f"\n Hasil Metrik:") print(f" Accuracy : {acc:.4f} ({acc*100:.1f}%)") print(f" Precision : {prec:.4f} ({prec*100:.1f}%)") print(f" Recall : {rec:.4f} ({rec*100:.1f}%)") print(f" F1-Score : {f1:.4f} ({f1*100:.1f}%)") return {"kriteria": nama_kriteria, "TP": tp, "FP": fp, "FN": fn, "TN": tn, "Accuracy": acc, "Precision": prec, "Recall": rec, "F1": f1} # ───────────────────────────────────────────── # BAGIAN 3: JALANKAN EVALUASI SEMUA KRITERIA # ───────────────────────────────────────────── hasil = [] kriteria_list = [ ("kategori", "Kesesuaian Kategori Rekomendasi"), ("budget", "Kepatuhan Batas Budget"), ("alergen", "Bebas Alergen Pengguna"), ("overall", "Kevalidan Keseluruhan"), ] for key, nama in kriteria_list: r = evaluasi_kriteria( df[f"{key}_expected"].tolist(), df[f"{key}_actual"].tolist(), nama ) hasil.append(r) # ───────────────────────────────────────────── # BAGIAN 4: TABEL REKAP AKHIR # ───────────────────────────────────────────── df_hasil = pd.DataFrame(hasil) df_hasil = df_hasil.set_index("kriteria") df_hasil[["Accuracy","Precision","Recall","F1"]] = \ df_hasil[["Accuracy","Precision","Recall","F1"]].map(lambda x: f"{x*100:.1f}%") print("\n" + "="*55) print(" REKAP METRIK EVALUASI GEMINI AI") print("="*55) print(df_hasil[["TP","FP","FN","TN","Accuracy","Precision","Recall","F1"]].to_string()) # ───────────────────────────────────────────── # BAGIAN 5: VISUALISASI CONFUSION MATRIX # ───────────────────────────────────────────── fig, axes = plt.subplots(1, 4, figsize=(20, 4)) fig.suptitle("Confusion Matrix - Evaluasi Efektivitas Gemini AI\nAplikasi Muning Assistant (Amor Coffee)", fontsize=13, fontweight='bold', y=1.02) labels = ["Tidak Valid", "Valid"] colors = ["Blues", "Greens", "Oranges", "Purples"] for i, (key, nama) in enumerate(kriteria_list): y_true = df[f"{key}_expected"].tolist() y_pred = df[f"{key}_actual"].tolist() cm = confusion_matrix(y_true, y_pred) disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=labels) disp.plot(ax=axes[i], colorbar=False, cmap=colors[i]) axes[i].set_title(nama, fontsize=9, fontweight='bold') axes[i].set_xlabel("Prediksi AI", fontsize=8) axes[i].set_ylabel("Ground Truth", fontsize=8) plt.tight_layout() plt.savefig("confusion_matrix_gemini.png", dpi=150, bbox_inches='tight') print("\n[OK] Gambar disimpan: confusion_matrix_gemini.png") # ───────────────────────────────────────────── # BAGIAN 6: CLASSIFICATION REPORT LENGKAP # ───────────────────────────────────────────── print("\n" + "="*55) print(" CLASSIFICATION REPORT - OVERALL VALIDITY") print("="*55) print(classification_report( df["overall_expected"], df["overall_actual"], target_names=["Tidak Valid", "Valid"] ))