{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "a954725d", "metadata": {}, "outputs": [], "source": [ "# 1 extraction features TF-IDF\n", "import pandas as pd\n", "import joblib\n", "import os\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "from sklearn.model_selection import train_test_split\n", "\n", "print(\"šŸ”„ [TAHAP 1] Memulai Preprocessing & TF-IDF...\")\n", "\n", "# --- CONFIG ---\n", "# Gunakan Absolute Path dengan 'r' di depan agar aman di Windows\n", "FILE_DATA = r'd:\\project skripsi machine learning intoleransi\\virtualEnvironment\\dataset\\dataYangDiPakai\\data_label_revisi_goblog.csv' \n", "\n", "# 0. CEK KEAMANAN FILE SEBELUM JALAN\n", "if not os.path.exists(FILE_DATA):\n", " raise FileNotFoundError(f\"āŒ File tidak ditemukan di jalur:\\n{FILE_DATA}\\nCoba pastikan nama file dan foldernya sudah persis sama!\")\n", "\n", "# Bikin folder otomatis\n", "os.makedirs('output', exist_ok=True) \n", "os.makedirs('models', exist_ok=True) \n", "\n", "# 1. LOAD DATA\n", "print(\" - Membaca dataset...\")\n", "df = pd.read_csv(FILE_DATA, sep=';') \n", "\n", "# Cek keamanan kolom (Biar tidak error kalau nama kolom salah)\n", "if 'terjemahan_indo' not in df.columns or 'label' not in df.columns:\n", " print(f\"Daftar kolom yang ada di filemu: {df.columns.tolist()}\")\n", " raise KeyError(\"āŒ Kolom 'terjemahan_indo' atau 'label' tidak ada! Coba cek tulisan di atas, pastikan namanya cocok.\")\n", "\n", "# Bersihkan data kosong\n", "df = df.dropna(subset=['terjemahan_indo', 'label']) \n", "print(f\" - Total data bersih yang siap diproses: {len(df)} baris\")\n", "\n", "# 2. TF-IDF (Ubah Huruf jadi Angka)\n", "print(\" - Melakukan ekstraksi fitur TF-IDF...\")\n", "vectorizer = TfidfVectorizer(max_features=5000)\n", "X = vectorizer.fit_transform(df['terjemahan_indo'].astype(str))\n", "y = df['label'].astype(int) # Pastikan label berupa angka (0, 1, 2)\n", "\n", "# 3. SIMPAN KAMUS TF-IDF\n", "joblib.dump(vectorizer, 'models/vectorizer_tfidf.pkl')\n", "\n", "# 4. SPLIT DATA (80% Latih, 20% Uji)\n", "print(\" - Memecah data (80% Data Latih, 20% Data Uji)...\")\n", "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n", "\n", "# 5. SIMPAN DATA MATANG\n", "print(\" - Menyimpan data matang ke folder 'output'...\")\n", "joblib.dump(X_train, 'output/X_train.pkl')\n", "joblib.dump(X_test, 'output/X_test.pkl')\n", "joblib.dump(y_train, 'output/y_train.pkl')\n", "joblib.dump(y_test, 'output/y_test.pkl')\n", "\n", "print(\"āœ… SELESAI TAHAP 1. Data sudah siap!\")\n", "print(\"šŸ‘‰ Silakan lanjut jalankan '2_training.py' atau '2_training.ipynb'\")" ] }, { "cell_type": "code", "execution_count": null, "id": "15e21017", "metadata": {}, "outputs": [], "source": [ "# 2 pelatihan model SVM, KNN dan ensemble\n", "import joblib\n", "import pandas as pd\n", "import os\n", "from sklearn.svm import SVC\n", "from sklearn.neighbors import KNeighborsClassifier\n", "from sklearn.ensemble import VotingClassifier\n", "from sklearn.model_selection import GridSearchCV\n", "\n", "print(\"šŸ‹ļø [TAHAP 2] Training: DATA ASLI (Tanpa Penyeimbang Apapun)...\")\n", "\n", "# 0. CEK KEAMANAN: Pastikan folder dan file Tahap 1 sudah ada\n", "if not os.path.exists('output/X_train.pkl'):\n", " raise FileNotFoundError(\"āŒ File 'output/X_train.pkl' tidak ditemukan! Pastikan kamu sudah menjalankan '1_preprocessing.py' terlebih dahulu.\")\n", "os.makedirs('models', exist_ok=True) # Jaga-jaga kalau folder models terhapus\n", "\n", "# 1. AMBIL DATA DARI TAHAP 1\n", "print(\" - Memuat data latih...\")\n", "X_train = joblib.load('output/X_train.pkl')\n", "y_train = joblib.load('output/y_train.pkl')\n", "\n", "print(f\" - Jumlah Data Latih Asli: {len(y_train)} baris\")\n", "print(f\" - Komposisi Label: {y_train.value_counts().to_dict()}\")\n", "\n", "# ---------------------------------------------------------\n", "# 2. LATIH SVM (MODEL UTAMA)\n", "# ---------------------------------------------------------\n", "print(\"\\nšŸš€ Melatih SVM (Mencari Settingan Terbaik)...\")\n", "print(\" (Mohon tunggu, ini akan memakan waktu beberapa menit ā˜•)\")\n", "\n", "param_svm = {\n", " 'C': [0.1, 1, 10],\n", " 'kernel': ['linear', 'rbf'],\n", " 'gamma': ['scale', 'auto']\n", "}\n", "\n", "# n_jobs=-1 artinya kita memakai seluruh \"otak\" CPU laptop agar cepat selesai\n", "svm_grid = GridSearchCV(SVC(probability=True, random_state=42), param_svm, cv=3, verbose=1, n_jobs=-1)\n", "svm_grid.fit(X_train, y_train) \n", "\n", "best_svm = svm_grid.best_estimator_\n", "joblib.dump(best_svm, 'models/model_svm.pkl')\n", "print(f\" āœ… SVM Selesai (Akurasi Validasi: {svm_grid.best_score_*100:.2f}%)\")\n", "\n", "# ---------------------------------------------------------\n", "# 3. LATIH KNN (METRIC COSINE)\n", "# ---------------------------------------------------------\n", "print(\"\\nšŸš€ Melatih KNN (Wajib Cosine)...\")\n", "\n", "param_knn = {\n", " 'n_neighbors': [3, 5, 7, 9, 11, 15], \n", " 'metric': ['cosine'] \n", "}\n", "\n", "knn_grid = GridSearchCV(KNeighborsClassifier(), param_knn, cv=3, verbose=1, n_jobs=-1)\n", "knn_grid.fit(X_train, y_train)\n", "\n", "best_knn = knn_grid.best_estimator_\n", "joblib.dump(best_knn, 'models/model_knn.pkl')\n", "print(f\" āœ… KNN Selesai (Best K: {knn_grid.best_params_['n_neighbors']})\")\n", "\n", "# ---------------------------------------------------------\n", "# 4. LATIH ENSEMBLE (SVM + KNN)\n", "# ---------------------------------------------------------\n", "print(\"\\nšŸš€ Melatih ENSEMBLE (Voting SVM + KNN)...\")\n", "\n", "# Gabungkan dua model terbaik\n", "ensemble_model = VotingClassifier(\n", " estimators=[\n", " ('svm', best_svm), \n", " ('knn', best_knn)\n", " ],\n", " voting='soft',\n", " weights=[2, 1] # SVM kita beri bobot suara lebih tinggi\n", ")\n", "\n", "ensemble_model.fit(X_train, y_train)\n", "joblib.dump(ensemble_model, 'models/model_ensemble.pkl')\n", "print(\" āœ… Ensemble Selesai.\")\n", "\n", "print(\"\\n==================================================\")\n", "print(\"šŸŽ‰ TRAINING DATA MURNI SELESAI!\")\n", "print(\"šŸ‘‰ Silakan jalankan '3_evaluasi.py' untuk melihat hasil akhirnya.\")" ] }, { "cell_type": "code", "execution_count": null, "id": "38511828", "metadata": {}, "outputs": [], "source": [ "# 3 evaluasi hasil model\n", "import joblib\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "from sklearn.metrics import accuracy_score, classification_report, confusion_matrix\n", "import os\n", "\n", "print(\"šŸ“Š [TAHAP 3] Evaluasi Hasil Model...\")\n", "\n", "# 0. CEK KEAMANAN\n", "if not os.path.exists('output/X_test.pkl'):\n", " raise FileNotFoundError(\"āŒ File 'output/X_test.pkl' tidak ditemukan! Pastikan Tahap 1 sudah dijalankan.\")\n", "if not os.path.exists('models/model_svm.pkl'):\n", " raise FileNotFoundError(\"āŒ File 'models/model_svm.pkl' tidak ditemukan! Pastikan Tahap 2 sudah selesai 100%.\")\n", "\n", "# Bikin folder images otomatis\n", "os.makedirs('images', exist_ok=True)\n", "\n", "# 1. Ambil Data Uji\n", "print(\" - Memuat data uji...\")\n", "X_test = joblib.load('output/X_test.pkl')\n", "y_test = joblib.load('output/y_test.pkl')\n", "\n", "# 2. Daftar Model (CUMA 3 SEKARANG)\n", "print(\" - Memuat model-model AI...\")\n", "daftar_model = {\n", " \"SVM\": joblib.load('models/model_svm.pkl'),\n", " \"KNN\": joblib.load('models/model_knn.pkl'),\n", " \"Ensemble\": joblib.load('models/model_ensemble.pkl')\n", "}\n", "\n", "# 3. Loop Evaluasi\n", "for nama, model in daftar_model.items():\n", " print(f\"\\n==========================================\")\n", " print(f\"--- Evaluasi Model: {nama} ---\")\n", " print(f\"==========================================\")\n", "\n", " # Lakukan Prediksi\n", " y_pred = model.predict(X_test)\n", " \n", " # Hitung Akurasi\n", " acc = accuracy_score(y_test, y_pred)\n", " print(f\"šŸŽÆ Akurasi {nama}: {acc*100:.2f}%\\n\")\n", " \n", " # Laporan Lengkap (Precision, Recall, F1-Score)\n", " print(\"šŸ“‹ Laporan Klasifikasi:\")\n", " print(classification_report(y_test, y_pred))\n", "\n", " # Bikin Grafik Confusion Matrix\n", " cm = confusion_matrix(y_test, y_pred)\n", " plt.figure(figsize=(7, 5))\n", " sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', \n", " annot_kws={\"size\": 14}) # Angka di dalam kotak diperbesar\n", " \n", " # Hiasan Grafik (Lebih rapi untuk masuk ke buku Skripsi)\n", " plt.title(f'Confusion Matrix - {nama}\\n(Akurasi: {acc*100:.2f}%)', fontsize=14, fontweight='bold', pad=15)\n", " plt.xlabel('Prediksi Mesin', fontsize=12, fontweight='bold')\n", " plt" ] }, { "cell_type": "code", "execution_count": null, "id": "ff1f299c", "metadata": {}, "outputs": [], "source": [ "# 3.2 Menampilkan Distribusi Data\n", "# Menampilkan perbandingan jumlah data dan tampilan grafik perbandingan data\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "import os\n", "\n", "# Pastikan folder images ada untuk menyimpan hasil\n", "os.makedirs('images', exist_ok=True)\n", "\n", "# ==========================================\n", "# 1. LOAD DATA\n", "# ==========================================\n", "nama_file = r'd:\\project skripsi machine learning intoleransi\\virtualEnvironment\\dataset\\dataYangDiPakai\\data_label_revisi_goblog.csv'\n", "\n", "print(f\"šŸ“‚ Membaca file: {nama_file}...\")\n", "df = pd.read_csv(nama_file, sep=';') \n", "\n", "# ==========================================\n", "# 2. HITUNG JUMLAH LABEL\n", "# ==========================================\n", "# Kita pastikan kolom 'label' ada\n", "if 'label' not in df.columns:\n", " raise ValueError(\"āŒ Kolom 'label' tidak ditemukan di dataset! Coba cek separatornya (sep=';' atau sep=',')\")\n", "\n", "jumlah_label = df['label'].value_counts().sort_index()\n", "\n", "print(\"\\nšŸ“Š STATISTIK JUMLAH DATA:\")\n", "print(\"-\" * 30)\n", "label_names = {0: \"Netral (0)\", 1: \"Kritik (1)\", 2: \"Hujatan (2)\"}\n", "for lbl, count in jumlah_label.items():\n", " print(f\" {label_names.get(lbl, lbl)}: {count} data\")\n", "print(\"-\" * 30)\n", "print(f\" TOTAL: {len(df)} data\")\n", "\n", "# ==========================================\n", "# 3. BUAT GRAFIK (VISUALISASI)\n", "# ==========================================\n", "plt.figure(figsize=(8, 6)) # Ukuran gambar (Lebar, Tinggi)\n", "\n", "# Bikin Bar Chart warna-warni (tambah hue=... agar tidak muncul warning di versi Seaborn terbaru)\n", "ax = sns.barplot(x=jumlah_label.index, y=jumlah_label.values, hue=jumlah_label.index, palette='viridis', legend=False)\n", "\n", "# Hiasan Grafik\n", "plt.title('Perbandingan Jumlah Data per Label', fontsize=16, fontweight='bold', pad=15)\n", "plt.xlabel('Kategori Label', fontsize=12, fontweight='bold')\n", "plt.ylabel('Jumlah Data', fontsize=12, fontweight='bold')\n", "\n", "# Pastikan urutan label sesuai dengan 0, 1, 2\n", "urutan_label = sorted(jumlah_label.index.tolist())\n", "plt.xticks(ticks=range(len(urutan_label)), labels=['0\\n(Netral)', '1\\n(Kritik)', '2\\n(Hujatan)'])\n", "plt.grid(axis='y', linestyle='--', alpha=0.5)\n", "\n", "# Tampilkan Angka di Atas Batang\n", "for p in ax.patches:\n", " ax.annotate(f'{int(p.get_height())}', \n", " (p.get_x() + p.get_width() / 2., p.get_height()), \n", " ha='center', va='center', \n", " xytext=(0, 10), \n", " textcoords='offset points',\n", " fontsize=14, fontweight='bold', color='black')\n", "\n", "# Simpan Gambar di dalam folder 'images'\n", "nama_gambar = 'images/grafik_distribusi_data.png'\n", "plt.savefig(nama_gambar, dpi=300, bbox_inches='tight')\n", "print(f\"\\nšŸ–¼ļø Grafik berhasil disimpan: {nama_gambar}\")\n", "\n", "# Tampilkan gambar di layar\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "id": "c2325607", "metadata": {}, "outputs": [], "source": [ "import joblib\n", "import pandas as pd\n", "import numpy as np\n", "import math\n", "import matplotlib.pyplot as plt\n", "import os\n", "from sklearn.neighbors import KNeighborsClassifier\n", "from sklearn.model_selection import cross_val_score, GridSearchCV\n", "\n", "print(\"šŸ”¬ [EKSPERIMEN] Membandingkan 3 Metode Mencari Nilai K Terbaik...\")\n", "\n", "# 0. CEK KEAMANAN\n", "if not os.path.exists('output/X_train.pkl'):\n", " raise FileNotFoundError(\"āŒ File 'output/X_train.pkl' tidak ditemukan! Pastikan Tahap 1 sudah dijalankan.\")\n", "\n", "# Pastikan folder images ada\n", "os.makedirs('images', exist_ok=True)\n", "\n", "# 1. LOAD DATA\n", "X_train = joblib.load('output/X_train.pkl')\n", "y_train = joblib.load('output/y_train.pkl')\n", "jumlah_data = X_train.shape[0]\n", "\n", "print(f\" - Jumlah Data Latih: {jumlah_data} baris\")\n", "print(\"-\" * 50)\n", "\n", "results = [] # Untuk menyimpan hasil perbandingan\n", "\n", "# =========================================================\n", "# METODE 1: AKAR KUADRAT (Square Root Rule)\n", "# Rumus: K = Akar(Total Data)\n", "# =========================================================\n", "print(\"1ļøāƒ£ Menguji Metode Akar Kuadrat...\")\n", "k_sqrt = int(math.sqrt(jumlah_data))\n", "\n", "# Aturan: K harus ganjil biar gak seri (draw)\n", "if k_sqrt % 2 == 0:\n", " k_sqrt += 1\n", "\n", "# Uji Akurasinya (Pakai n_jobs=-1 biar ngebut)\n", "knn_sq = KNeighborsClassifier(n_neighbors=k_sqrt, metric='cosine')\n", "scores_sq = cross_val_score(knn_sq, X_train, y_train, cv=5, scoring='accuracy', n_jobs=-1)\n", "acc_sq = scores_sq.mean() * 100\n", "\n", "print(f\" -> Hasil: K={k_sqrt}, Akurasi={acc_sq:.2f}%\")\n", "results.append({'Metode': 'Akar Kuadrat', 'K': k_sqrt, 'Akurasi': acc_sq})\n", "\n", "# =========================================================\n", "# METODE 2: ELBOW METHOD (Metode Siku)\n", "# Coba manual dari 1 sampai 40, lalu cari error terkecil\n", "# =========================================================\n", "print(\"\\n2ļøāƒ£ Menguji Metode Elbow (Looping 1-40)...\")\n", "print(\" (Tunggu sebentar, sedang menghitung manual...)\")\n", "error_rates = []\n", "acc_rates = []\n", "k_range = range(1, 41, 2) # Coba angka ganjil: 1, 3, 5, ... 39\n", "\n", "best_k_elbow = 0\n", "best_acc_elbow = 0\n", "\n", "for k in k_range:\n", " knn = KNeighborsClassifier(n_neighbors=k, metric='cosine')\n", " # Pakai n_jobs=-1 di sini juga biar loopingnya gak kelamaan\n", " scores = cross_val_score(knn, X_train, y_train, cv=5, scoring='accuracy', n_jobs=-1)\n", " acc = scores.mean()\n", "\n", " # Simpan data buat grafik\n", " acc_rates.append(acc)\n", " error_rates.append(1 - acc) # Error = 100% - Akurasi\n", "\n", " # Cek apakah ini rekor terbaik?\n", " if acc > best_acc_elbow:\n", " best_acc_elbow = acc\n", " best_k_elbow = k\n", "\n", "print(f\" -> Hasil Terbaik di Range Ini: K={best_k_elbow}, Akurasi={best_acc_elbow*100:.2f}%\")\n", "results.append({'Metode': 'Elbow (Manual)', 'K': best_k_elbow, 'Akurasi': best_acc_elbow*100})\n", "\n", "# Bikin Grafik Elbow\n", "plt.figure(figsize=(10, 6))\n", "plt.plot(k_range, error_rates, color='red', linestyle='dashed', marker='o',\n", " markerfacecolor='blue', markersize=8)\n", "plt.title('Grafik Elbow (Mencari Error Terkecil)', fontsize=14, fontweight='bold', pad=15)\n", "plt.xlabel('Nilai K', fontsize=12, fontweight='bold')\n", "plt.ylabel('Tingkat Error', fontsize=12, fontweight='bold')\n", "plt.grid(True, linestyle='--', alpha=0.6)\n", "\n", "# Simpan ke folder images\n", "nama_gambar_elbow = 'images/grafik_elbow_knn.png'\n", "plt.savefig(nama_gambar_elbow, dpi=300, bbox_inches='tight')\n", "print(f\" šŸ–¼ļø Grafik Elbow tersimpan: {nama_gambar_elbow}\")\n", "plt.close() # Tutup grafik biar memori lega\n", "\n", "# =========================================================\n", "# METODE 3: GRID SEARCH CV (Validasi Silang)\n", "# Ini metode paling 'Sultan' dan Valid\n", "# =========================================================\n", "print(\"\\n3ļøāƒ£ Menguji Metode Grid Search CV (Otomatis)...\")\n", "param_grid = {'n_neighbors': [3, 5, 7, 9, 11, 15, 19, 21, 25, 29]}\n", "grid = GridSearchCV(KNeighborsClassifier(metric='cosine'), param_grid, cv=5, scoring='accuracy', n_jobs=-1)\n", "grid.fit(X_train, y_train)\n", "\n", "k_grid = grid.best_params_['n_neighbors']\n", "acc_grid = grid.best_score_ * 100\n", "\n", "print(f\" -> Hasil: K={k_grid}, Akurasi={acc_grid:.2f}%\")\n", "results.append({'Metode': 'Grid Search CV', 'K': k_grid, 'Akurasi': acc_grid})\n", "\n", "# =========================================================\n", "# KESIMPULAN AKHIR\n", "# =========================================================\n", "print(\"\\n\" + \"=\"*50)\n", "print(\"šŸ† TABEL PERBANDINGAN METODE PENENTUAN K\")\n", "print(\"=\"*50)\n", "df_res = pd.DataFrame(results)\n", "print(df_res.to_string(index=False))\n", "print(\"-\" * 50)\n", "\n", "# Cari pemenang\n", "best_method = df_res.loc[df_res['Akurasi'].idxmax()]\n", "print(f\"āœ… REKOMENDASI: Gunakan K = {best_method['K']}\")\n", "print(f\" (Berdasarkan metode {best_method['Metode']} dengan akurasi tertinggi)\")" ] } ], "metadata": { "kernelspec": { "display_name": "virtualEnvironment", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }