TIF_E41253394/models.py

126 lines
4.0 KiB
Python

"""
Models.py - Modul Model Klasifikasi dan Vektorisasi TF-IDF
Proyek Tugas Akhir: Analisis Sentimen Komentar Berbasis TF-IDF & Logistic Regression
Modul ini menangani:
1. Pemuatan pre-trained TF-IDF Vectorizer dan model Logistic Regression
2. Transformasi teks bersih ke vektor TF-IDF
3. Perhitungan skor probabilitas dan decision value
4. Ekstraksi fitur n-gram dominan berserta bobot koefisiennya
"""
import os
import time
import warnings
import joblib
from typing import Dict, Any
warnings.filterwarnings("ignore")
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
MODEL_PATH = os.path.join(BASE_DIR, "model_logistic_regression.pkl")
TFIDF_PATH = os.path.join(BASE_DIR, "tfidf_vectorizer.pkl")
# Memuat model dan vectorizer saat modul diimpor
model = joblib.load(MODEL_PATH)
tfidf = joblib.load(TFIDF_PATH)
def predict_sentiment(teks_bersih: str) -> Dict[str, Any]:
"""
Melakukan inferensi klasifikasi sentimen berdasarkan teks yang telah diproses:
- X = tfidf.transform([teks_bersih])
- Prediksi label: POSITIF / NEGATIF
- Probabilitas Sigmoid untuk tiap kelas
- Nilai Decision Function (z = w*x + b)
- Ekstraksi kontribusi bobot fitur dominan
"""
start_time = time.time()
if not teks_bersih or not teks_bersih.strip():
return {
"success": True,
"sentimen": "GAGAL DIANALISIS",
"preprocessing": "",
"probabilitas": {
"negatif": 0.0,
"positif": 0.0
},
"keyakinan": 0.0,
"decision_value": 0.0,
"fitur_dominan": [],
"elapsed_ms": 0.5,
"keterangan": "Hasil preprocessing kosong (tidak dapat dianalisis)."
}
# Transformasi TF-IDF
X = tfidf.transform([teks_bersih])
# Ekstraksi Fitur N-Gram Dominan
feature_names = tfidf.get_feature_names_out()
non_zero_indices = X.nonzero()[1]
has_features = len(non_zero_indices) > 0
elapsed_ms = round((time.time() - start_time) * 1000, 1)
# Bila fitur kata tidak ditemukan pada TF-IDF, jangan gunakan bias model
if not has_features:
return {
"success": True,
"sentimen": "FITUR TIDAK DITEMUKAN",
"preprocessing": teks_bersih,
"probabilitas": {
"negatif": 0.0,
"positif": 0.0
},
"keyakinan": 0.0,
"decision_value": 0.0,
"fitur_dominan": [],
"fitur_ditemukan": False,
"keterangan": "Fitur tidak ditemukan",
"elapsed_ms": max(1.0, elapsed_ms)
}
# Prediksi Label dan Probabilitas hanya bila fitur kata ditemukan
hasil_prediksi = model.predict(X)[0]
proba = model.predict_proba(X)[0]
prob_negatif = float(proba[0])
prob_positif = float(proba[1])
decision_val = float(model.decision_function(X)[0])
features_info = []
for idx in non_zero_indices:
token = feature_names[idx]
val = float(X[0, idx])
weight = float(model.coef_[0, idx])
features_info.append({
"token": token,
"tfidf": round(val, 4),
"weight": round(weight, 4)
})
# Urutkan berdasarkan nilai absolut kontribusi fitur
features_info.sort(key=lambda item: abs(item['weight'] * item['tfidf']), reverse=True)
top_features = features_info[:8]
keyakinan = (prob_negatif if hasil_prediksi == 'NEGATIF' else prob_positif) * 100
return {
"success": True,
"sentimen": str(hasil_prediksi),
"preprocessing": teks_bersih,
"probabilitas": {
"negatif": round(prob_negatif, 4),
"positif": round(prob_positif, 4)
},
"keyakinan": round(keyakinan, 1),
"decision_value": round(decision_val, 4),
"fitur_dominan": top_features,
"fitur_ditemukan": True,
"keterangan": "Fitur berhasil diekstraksi",
"elapsed_ms": max(1.0, elapsed_ms)
}
if __name__ == "__main__":
test_clean = "sok cantik banget"
hasil = predict_sentiment(test_clean)
print("Hasil Prediksi:", hasil)