From dc707605b3aad1866c93a8be554488e971d6678d Mon Sep 17 00:00:00 2001 From: adistya13 Date: Mon, 1 Jun 2026 06:19:50 +0700 Subject: [PATCH] revisi prepo dikit --- nrt_activation.json | 2 +- page_modules/preprocessing_page.py | 298 ++++++------- sentiment_service.py | 482 ++++++++++++++++------ tweets-data/Error-30-05-2026_08-21-41.png | Bin 0 -> 4254 bytes tweets-data/Error-30-05-2026_08-22-55.png | Bin 0 -> 4254 bytes tweets-data/Error-30-05-2026_08-29-08.png | Bin 0 -> 4254 bytes tweets-data/Error-30-05-2026_08-30-33.png | Bin 0 -> 4254 bytes tweets-data/Error-30-05-2026_19-21-03.png | Bin 0 -> 92336 bytes tweets-data/hasil_top.csv | 10 +- tweets-data/hasil_top.old.csv | 8 +- 10 files changed, 484 insertions(+), 316 deletions(-) create mode 100644 tweets-data/Error-30-05-2026_08-21-41.png create mode 100644 tweets-data/Error-30-05-2026_08-22-55.png create mode 100644 tweets-data/Error-30-05-2026_08-29-08.png create mode 100644 tweets-data/Error-30-05-2026_08-30-33.png create mode 100644 tweets-data/Error-30-05-2026_19-21-03.png diff --git a/nrt_activation.json b/nrt_activation.json index 54df601..858d112 100644 --- a/nrt_activation.json +++ b/nrt_activation.json @@ -1 +1 @@ -{"activated": true, "updated_at": "2026-05-29T05:53:53.439233+00:00"} \ No newline at end of file +{"activated": true, "updated_at": "2026-05-31T01:21:56.067731+00:00"} \ No newline at end of file diff --git a/page_modules/preprocessing_page.py b/page_modules/preprocessing_page.py index 033356c..b3bb15a 100644 --- a/page_modules/preprocessing_page.py +++ b/page_modules/preprocessing_page.py @@ -10,13 +10,17 @@ PIPELINE 5 TAHAP: 4. Stopword Removal — hapus kata umum (DARI FILE stopword); JAGA kata sentimen 5. Stemming — bentuk dasar kata via Sastrawi ECS -PERUBAHAN DARI VERSI SEBELUMNYA: - - Normalisasi kini dimuat dari 'indonesian-normalisasi-slangword-complete.txt' - (1.700+ entri), menggantikan dict hardcoded yang hanya ~60 entri. - - Stopword kini murni dari 'indonesian-stopwords-complete.txt', ditambah - noise Twitter yang spesifik — tidak ada penghapusan manual acak. - - KATA_SENTIMEN_PENTING diperluas dengan kata domain e-commerce/ongkir. - - Semua fungsi preprocessing menerima parameter eksplisit (tidak pakai global). +PERBAIKAN DARI VERSI SEBELUMNYA (sync dengan sentiment_service.py): + - Domain override 'mending' → 'lebih baik' DIHAPUS. + Alasan: mengubah kata kritis/negatif menjadi sinyal positif di lexicon. + "mending X daripada Y" = kritik; setelah diubah jadi "lebih baik X..." + lexicon menangkap 'baik' sebagai POSITIF → hasil sentimen salah. + - Domain override 'mendingan' → 'lebih baik' DIHAPUS (alasan sama). + - 'mending', 'mendingan', 'daripada', 'ketimbang', 'ngapain', 'percuma', + 'begini' DILINDUNGI dari stopword removal agar pola kontekstual + (POLA_KOMPARATIF, POLA_KRITIK_TERSIRAT) di sentiment_service.py tetap + dapat mendeteksinya saat input lexicon preprocessing. + - KATA_SENTIMEN_PENTING diperluas: tambahkan 'mending', 'malah'. CATATAN PENTING: Pipeline ini HARUS IDENTIK dengan sentiment_service.py agar token yang @@ -119,18 +123,16 @@ def _sync_dynamic_period(): # Kata-kata ini WAJIB DIJAGA dan tidak boleh dihapus saat # stopword removal, meskipun ada di file stopword. # -# Kenapa perlu? Karena file stopword mengandung kata seperti -# "tidak", "belum", "sangat" yang justru krusial untuk -# menentukan sentimen positif/negatif suatu kalimat. +# PERBAIKAN: Tambahkan 'mending' dan 'malah' agar tidak +# hilang di stopword removal dan bisa dideteksi oleh +# pola kontekstual di sentiment_service.py. # ─────────────────────────────────────────────────────────── KATA_SENTIMEN_PENTING = { # ── Negasi (pembalik makna kalimat) ────────────────── - # "tidak bagus" ≠ "bagus" → "tidak" wajib ada "tidak", "bukan", "jangan", "kurang", "belum", "tanpa", # ── Intensitas (penguat/pelemah sentimen) ───────────── - # "sangat bagus" lebih positif dari "bagus" saja "sangat", "banget", "sekali", "paling", "amat", - "luar", "biasa", # ← "luar biasa" = dua token, keduanya dijaga + "luar", "biasa", # ── Positif umum ────────────────────────────────────── "keren", "bagus", "mantap", "setuju", "dukung", "mendukung", "andal", "handal", "gercep", "bangga", "senang", "suka", @@ -150,30 +152,52 @@ KATA_SENTIMEN_PENTING = { "rugi", "boros", # ── Emosi ───────────────────────────────────────────── "marah", "sedih", "khawatir", "kecewa", + # ── DITAMBAHKAN: Penanda pola kontekstual ───────────── + # Kata-kata ini perlu tetap ada agar pola komparatif dan + # pola kritik tersirat bisa terdeteksi di sentiment_service. + "mending", # "mending X daripada Y" = kritik implisit + "mendingan", # variasi mending + "malah", # "malah rugi / malah tambah mahal" = negatif + "percuma", # "percuma aja kebijakan ini" = sia-sia/negatif +} + + +# ─────────────────────────────────────────────────────────── +# KATA POLA PENTING +# Kata struktural yang diperlukan agar pola kontekstual +# di sentiment_service.py bisa bekerja dengan benar. +# Kata-kata ini HARUS dilindungi dari stopword removal. +# ─────────────────────────────────────────────────────────── +KATA_POLA_PENTING = { + "mending", # penanda pola komparatif negatif + "mendingan", # variasi mending + "daripada", # komponen "mending X daripada Y" + "ketimbang", # variasi daripada + "ngapain", # penanda kritik tersirat + "percuma", # penanda sia-sia + "begini", # "kebijakan begini" = kritik tersirat } # ─────────────────────────────────────────────────────────── # LOAD NORMALIZATION DARI FILE -# File: indonesian-normalisasi-slangword-complete.txt -# Format per baris: slang,kata_baku -# Contoh: gk,tidak | ongkir,ongkos kirim | free,gratis +# PERBAIKAN: Hapus override 'mending' → 'lebih baik' # ─────────────────────────────────────────────────────────── def _load_normalization() -> dict: """ Muat kamus normalisasi dari file eksternal. - KENAPA DARI FILE? - File berisi 1.700+ pasang slang→baku yang jauh lebih lengkap - dibanding dict hardcoded. Dengan ini, kata seperti: - gk/ga/gak/kagak/ngga → semua jadi "tidak" - bgt/bngt/bget → semua jadi "sangat" - ongkir/ongkr → jadi "ongkos kirim" - ...dan ribuan kasus lainnya tertangani otomatis. + PERUBAHAN DARI VERSI SEBELUMNYA: + - 'mending' TIDAK lagi dioverride ke 'lebih baik' + - 'mendingan' TIDAK lagi dioverride ke 'lebih baik' - Setelah file dimuat, override dengan entri khusus domain - (nama platform, singkatan kebijakan) yang mungkin belum ada - di file generik. + KENAPA? + 'mending' dalam tweet biasanya digunakan sebagai kritik: + "mending ngurusin judol daripada ngurusin ongkir" + Jika diubah ke "lebih baik", lexicon scoring mendeteksi 'baik' + sebagai sinyal positif → hasil sentimen SALAH (Positif, harusnya Negatif). + Biarkan 'mending' apa adanya agar POLA_KOMPARATIF_NEGATIF + di sentiment_service.py bisa mendeteksinya. """ norm_file = "indonesian-normalisasi-slangword-complete.txt" norm_dict: dict = {} @@ -184,28 +208,20 @@ def _load_normalization() -> dict: line = line.strip() if not line: continue - # Split hanya pada koma pertama — nilai bisa mengandung koma - # Contoh: "on the way, sedang di jalan,dijalan" → split jadi 2 bagian parts = line.split(",", 1) if len(parts) != 2: continue - # Bersihkan tanda kutip liar di awal/akhir (ada di beberapa baris file) slang = parts[0].strip().strip("'\"").lower() normal = parts[1].strip().lower() if slang and normal: norm_dict[slang] = normal except FileNotFoundError: - # Jika file tidak ditemukan, lanjut dengan dict kosong. - # Entri domain di bawah tetap akan ditambahkan. st.warning( "⚠️ File normalisasi tidak ditemukan: " f"'{norm_file}'. Hanya entri domain yang aktif." ) # ── Override khusus domain ─────────────────────────── - # Entri ini menimpa file generik karena domain spesifik - # membutuhkan perlakuan khusus (nama platform tidak diubah, - # singkatan kebijakan punya padanan resmi, dll.) DOMAIN_OVERRIDES: dict = { # Nama platform — pertahankan apa adanya "shopee": "shopee", @@ -237,6 +253,28 @@ def _load_normalization() -> dict: "seller": "penjual", "buyer": "pembeli", "online": "online", + # Negasi informal + "gk": "tidak", "ga": "tidak", "gak": "tidak", + "nggak": "tidak", "ngga": "tidak", "tdk": "tidak", + "tak": "tidak", "enggak": "tidak", "engga": "tidak", + "kagak": "tidak", "kaga": "tidak", "ndak": "tidak", + "ngak": "tidak", + # Intensitas + "bgt": "banget", "bngt": "banget", "bget": "banget", "bgtt": "banget", + # Positif informal (hanya yang benar-benar positif) + "mantep": "mantap", "mntap": "mantap", + "kece": "keren", + "ancur": "hancur", "parahh": "parah", + # ── SENGAJA TIDAK DIOVERRIDE (vs versi lama): ──────── + # "mending" → TIDAK diubah ke "lebih baik" + # "mendingan" → TIDAK diubah ke "lebih baik" + # Alasan: lihat docstring di atas. + # + # "malah" → TIDAK dioverride ke "bahkan" + # Alasan: nuansa kritis 'malah' perlu dipertahankan. + # + # "sip" → TIDAK dioverride ke "baik" + # Alasan: "baik" terlalu kontekstual untuk lexicon positif. } norm_dict.update(DOMAIN_OVERRIDES) @@ -245,23 +283,22 @@ def _load_normalization() -> dict: # ─────────────────────────────────────────────────────────── # LOAD STOPWORDS DARI FILE -# File: indonesian-stopwords-complete.txt -# Format: satu kata per baris +# PERBAIKAN: Lindungi kata pola penting dari stopword removal # ─────────────────────────────────────────────────────────── def _load_stopwords() -> set: """ Muat daftar stopword dari file eksternal. - PROSES SETELAH MUAT FILE: - 1. Hapus KATA_SENTIMEN_PENTING dari daftar - → Agar "tidak", "belum", "sangat", dll. tidak ikut dibuang - 2. Tambahkan noise Twitter/sosmed yang memang harus dibuang - → "rt", "amp", sisa URL, suara tawa, partikel informal - - KENAPA DARI FILE? - File berisi 700+ stopword Indonesia yang lebih lengkap dan - terstandar dibanding daftar manual. Kita tidak perlu menambah/ - mengurangi secara manual kecuali untuk dua kategori di atas. + PERUBAHAN DARI VERSI SEBELUMNYA: + Selain melindungi KATA_SENTIMEN_PENTING, kini juga melindungi + KATA_POLA_PENTING agar pola kontekstual di sentiment_service.py + bisa bekerja dengan benar: + - 'mending' → penanda pola komparatif negatif + - 'daripada' → komponen "mending X daripada Y" + - 'ketimbang' → variasi daripada + - 'ngapain' → penanda kritik tersirat + - 'percuma' → penanda sia-sia/negatif + - 'begini' → "kebijakan begini" = kritik tersirat """ stopword_file = "indonesian-stopwords-complete.txt" base: set = set() @@ -273,7 +310,6 @@ def _load_stopwords() -> set: if word: base.add(word) except FileNotFoundError: - # Fallback minimal — cukup untuk tetap jalan st.warning( "⚠️ File stopword tidak ditemukan: " f"'{stopword_file}'. Menggunakan daftar minimal." @@ -286,24 +322,21 @@ def _load_stopwords() -> set: } # ── Langkah 1: Lindungi kata sentimen ──────────────── - # Beberapa kata sentimen penting ADA di file stopword - # (misal: "tidak", "belum", "sangat", "paling", "kurang"). - # Kita HAPUS dari stopword agar tidak ikut dibuang. for kata in KATA_SENTIMEN_PENTING: base.discard(kata) - # ── Langkah 2: Tambah noise Twitter/sosmed ──────────── - # Ini bukan stopword bahasa Indonesia biasa, tapi noise - # yang sangat sering muncul di tweet dan tidak bermakna. + # ── Langkah 2: Lindungi kata pola kontekstual ───────── + # Kata-kata ini diperlukan agar pola analisis sentimen + # bisa bekerja setelah stopword removal. + for kata in KATA_POLA_PENTING: + base.discard(kata) + + # ── Langkah 3: Tambah noise Twitter/sosmed ──────────── TWITTER_NOISE: set = { - # Artefak Twitter "rt", "amp", - # Sisa URL setelah cleaning (kadang lolos) "https", "http", "co", "pic", - # Suara tawa (tidak bermakna untuk sentimen) "wkwk", "wkwkwk", "wkwkwkwk", "haha", "hahaha", "hehe", "hihi", "huhu", "xixi", - # Partikel informal yang tidak bermakna "nih", "sih", "dong", "deh", "loh", "lah", "tuh", "kak", "gan", "bro", "sob", "min", } @@ -326,8 +359,6 @@ def _load_stemmer(): # ═══════════════════════════════════════════════════════════ # FUNGSI 5 TAHAP PREPROCESSING -# Setiap fungsi bertanggung jawab SATU tahap saja. -# Input & output setiap tahap dijelaskan di docstring. # ═══════════════════════════════════════════════════════════ def step1_case_folding(text: str) -> str: @@ -335,11 +366,6 @@ def step1_case_folding(text: str) -> str: TAHAP 1 — CASE FOLDING Input : teks asli (campuran huruf besar/kecil) Output: semua huruf jadi lowercase - - Kenapa pertama? - Agar tahap berikutnya (cleaning, normalisasi) bekerja - secara konsisten — regex dan dict lookup case-sensitive. - Contoh: "Gratis" → "gratis", "ONGKIR" → "ongkir" """ return str(text).lower() @@ -349,43 +375,25 @@ def step2_cleaning(text: str) -> str: TAHAP 2 — CLEANING Input : teks lowercase Output: teks bersih dari semua elemen noise - - Urutan pembersihan PENTING: - 1. URL dulu (sebelum @ dan # agar tidak salah potong) - 2. Mention (@username) - 3. Hashtag (#topik) - 4. Angka - 5. Emoji & simbol unicode - 6. Tanda baca - 7. Karakter non-latin (huruf Arab, Cina, dll.) - 8. Spasi berlebih """ - # 1. Hapus URL (http, https, www) text = re.sub(r"http\S+|www\S+|https\S+", "", text) - # 2. Hapus mention Twitter (@username) text = re.sub(r"@\w+", "", text) - # 3. Hapus hashtag (#topik) text = re.sub(r"#\w+", "", text) - # 4. Hapus angka dan digit text = re.sub(r"\d+", "", text) - # 5. Hapus emoji & simbol unicode (berbagai range) text = re.sub( r"[" - r"\U00010000-\U0010ffff" # Suplemen karakter unicode - r"\U0001F600-\U0001F64F" # Emotikon wajah - r"\U0001F300-\U0001F5FF" # Simbol & piktogram - r"\U0001F680-\U0001F6FF" # Transport & peta - r"\U0001F1E0-\U0001F1FF" # Bendera negara - r"\u2600-\u26FF" # Simbol campuran - r"\u2700-\u27BF" # Dingbats + r"\U00010000-\U0010ffff" + r"\U0001F600-\U0001F64F" + r"\U0001F300-\U0001F5FF" + r"\U0001F680-\U0001F6FF" + r"\U0001F1E0-\U0001F1FF" + r"\u2600-\u26FF" + r"\u2700-\u27BF" r"]+", "", text, flags=re.UNICODE ) - # 6. Hapus tanda baca (.,!?;: dll.) text = text.translate(str.maketrans("", "", string.punctuation)) - # 7. Hapus karakter non-latin (hanya sisakan huruf a-z dan spasi) text = re.sub(r"[^a-zA-Z\s]", "", text) - # 8. Normalisasi spasi berlebih → satu spasi, lalu strip text = re.sub(r"\s+", " ", text).strip() return text @@ -393,22 +401,11 @@ def step2_cleaning(text: str) -> str: def step3_normalization(text: str, norm_dict: dict) -> str: """ TAHAP 3 — NORMALISASI - Input : teks bersih (sudah case fold + cleaning) - norm_dict : kamus {slang: kata_baku} dari file + Input : teks bersih + norm_dict dari file Output: teks dengan slang/singkatan sudah diganti kata baku - Cara kerja: token per token (word by word). - Setiap token dicari di norm_dict. - Jika ada → ganti. Jika tidak ada → biarkan. - - Contoh: - "gk bs ongkir" → "tidak bisa ongkos kirim" - "mantep bgt" → "mantap sangat" - - Kenapa setelah Cleaning? - Karena slang di file ditulis dalam bentuk sudah lowercase - dan sudah tanpa tanda baca. Jika normalisasi dilakukan - sebelum cleaning, banyak entri tidak cocok. + PERUBAHAN: 'mending' tidak lagi dinormalisasi ke 'lebih baik'. + Lihat komentar di _load_normalization() untuk penjelasan. """ tokens = text.split() normalized = [norm_dict.get(token, token) for token in tokens] @@ -418,36 +415,24 @@ def step3_normalization(text: str, norm_dict: dict) -> str: def step4_stopword_removal(tokens: list, stopwords: set) -> list: """ TAHAP 4 — STOPWORD REMOVAL - Input : list token (hasil split dari teks ternormalisasi) - stopwords : set kata yang harus dibuang (dari file) + Input : list token + stopwords dari file Output: list token bersih - ATURAN PENYARINGAN (prioritas urutan): - 1. JAGA token yang ada di KATA_SENTIMEN_PENTING - → meskipun juga ada di stopwords, tetap disimpan - 2. BUANG token yang ada di stopwords - 3. BUANG token dengan panjang ≤ 2 karakter - → menghilangkan sisa noise seperti "rt", "yg", "di" - → PENGECUALIAN: token di KATA_SENTIMEN_PENTING tetap disimpan - walau ≤ 2 karakter (contoh: "ok" jika masuk sentimen) - - Kenapa setelah Normalisasi? - Agar "gak" yang sudah dinormalisasi jadi "tidak" tidak ikut - dibuang — "tidak" dilindungi di KATA_SENTIMEN_PENTING. + PERUBAHAN: Kata pola penting (mending, daripada, dll.) dilindungi + dari pembuangan melalui KATA_POLA_PENTING di _load_stopwords(). """ result = [] for token in tokens: - # Prioritas 1: selalu simpan jika kata sentimen penting if token in KATA_SENTIMEN_PENTING: result.append(token) continue - # Prioritas 2: buang jika stopword + if token in KATA_POLA_PENTING: + result.append(token) + continue if token in stopwords: continue - # Prioritas 3: buang jika terlalu pendek (noise) if len(token) <= 2: continue - # Lolos semua filter → simpan result.append(token) return result @@ -456,18 +441,8 @@ def step5_stemming(tokens: list, stemmer) -> list: """ TAHAP 5 — STEMMING Input : list token setelah stopword removal - stemmer : objek Sastrawi (atau None) Output: list token dalam bentuk kata dasar - Algoritma: Enhanced Confix Stripping (ECS) via Sastrawi - Contoh: - "pengiriman" → "kirim" - "pembatasan" → "batas" - "berlari" → "lari" - "makanan" → "makan" - - Jika stemmer None (Sastrawi tidak terinstal), token dikembalikan - apa adanya tanpa error. """ if stemmer is None: return tokens @@ -484,37 +459,14 @@ def full_preprocessing( norm_dict: dict, ) -> dict: """ - Jalankan 5 tahap preprocessing secara berurutan dan kembalikan - hasil setiap tahap sebagai dict (untuk ditampilkan di tabel). - - Parameter: - text : teks tweet asli - stopwords : set stopword (dari _load_stopwords) - stemmer : objek Sastrawi (dari _load_stemmer) - norm_dict : kamus normalisasi (dari _load_normalization) - - Return dict berisi: - setelah_casefolding : hasil Tahap 1 - setelah_cleaning : hasil Tahap 2 - setelah_normalisasi : hasil Tahap 3 - setelah_stopword : hasil Tahap 4 (joined string) - clean_text : hasil akhir Tahap 5 (joined string) - _tokens_clean : hasil Tahap 5 sebagai list (untuk analisis) + Jalankan 5 tahap preprocessing secara berurutan. + Return dict berisi hasil setiap tahap. """ - # Tahap 1 — Case Folding s1_fold = step1_case_folding(text) - - # Tahap 2 — Cleaning s2_clean = step2_cleaning(s1_fold) - - # Tahap 3 — Normalisasi (perlu norm_dict) s3_norm = step3_normalization(s2_clean, norm_dict) - - # Tahap 4 — Stopword Removal (split → filter → simpan sebagai list) s4_tokens = s3_norm.split() s4_filtered = step4_stopword_removal(s4_tokens, stopwords) - - # Tahap 5 — Stemming s5_stemmed = step5_stemming(s4_filtered, stemmer) return { @@ -523,7 +475,7 @@ def full_preprocessing( "setelah_normalisasi": s3_norm, "setelah_stopword": " ".join(s4_filtered), "clean_text": " ".join(s5_stemmed), - "_tokens_clean": s5_stemmed, # list, untuk Counter frekuensi kata + "_tokens_clean": s5_stemmed, } @@ -711,13 +663,13 @@ def _render_pipeline_steps(stemmer_ok: bool, norm_count: int, sw_count: int): "icon": "🔄", "color": "#16a34a", "dark": "#14532d", "bg": "linear-gradient(135deg,#f0fdf4,#dcfce7)", "border": "#86efac", "title": f'Normalisasi ✦ {norm_count:,} entri', - "desc": "Mengubah kata tidak baku, singkatan, dan slang menjadi kata baku (dari file).", + "desc": "Mengubah singkatan/slang ke kata baku. 'mending' TIDAK diubah ke 'lebih baik' (perbaikan konteks sentimen).", "items": [ "gk/ga/gak/kagak/ngga → tidak", - "bgt/bngt/bget → sangat", + "bgt/bngt/bget → banget", "ongkir → ongkos kirim", "mantep → mantap", - "free → gratis", + "⚠️ mending → mending (dijaga, bukan 'lebih baik')", f"Total: {norm_count:,} pasang slang→baku dimuat", ], }, @@ -726,13 +678,13 @@ def _render_pipeline_steps(stemmer_ok: bool, norm_count: int, sw_count: int): "icon": "🚫", "color": "#ea580c", "dark": "#7c2d12", "bg": "linear-gradient(135deg,#fff7ed,#ffedd5)", "border": "#fed7aa", "title": f'Stopword Removal ✦ {sw_count:,} kata', - "desc": "Membuang kata umum dari file; kata sentimen DIJAGA.", + "desc": "Membuang kata umum; kata sentimen & kata pola kontekstual DIJAGA.", "items": [ f"{sw_count:,} stopword dimuat dari file", "JAGA negasi: tidak, bukan, jangan, belum", "JAGA positif: keren, bagus, mantap, gratis", - "JAGA negatif: kecewa, buruk, gagal, mahal, mending, malah", - "JAGA intensitas: sangat, banget, sekali", + "JAGA negatif: kecewa, buruk, gagal, mahal", + "JAGA pola: mending, daripada, percuma, begini", "Hapus token ≤ 2 karakter (noise)", ], }, @@ -753,14 +705,12 @@ def _render_pipeline_steps(stemmer_ok: bool, norm_count: int, sw_count: int): }, ] - # Baris 1: 3 kartu pertama row1 = st.columns(3, gap="medium") for col, step in zip(row1, steps[:3]): _render_step_card(col, step) _gap("sm") - # Baris 2: 2 kartu terakhir (tengah agar simetris) _, col4, col5, _ = st.columns([0.5, 1, 1, 0.5], gap="medium") _render_step_card(col4, steps[3]) _render_step_card(col5, steps[4]) @@ -964,7 +914,6 @@ def _render_top_words_chart(df_c): else: all_words = " ".join(df_c["clean_text"].fillna("")).split() - # Filter minimum 3 karakter (konsisten dengan step4) filtered_words = [w for w in all_words if len(w) > 2] word_freq = Counter(filtered_words).most_common(20) @@ -1055,14 +1004,10 @@ def show(): unsafe_allow_html=True ) - # ── Muat resource preprocessing (sekali per session) ────── - # Semua tiga resource dimuat di sini, bukan di dalam loop, - # agar tidak memuat ulang setiap tweet. stemmer = _load_stemmer() stopwords = _load_stopwords() norm_dict = _load_normalization() - # ── Pipeline Overview ────────────────────────────────────── _section_header( "🔬 Alur NLP Pipeline — 5 Tahap Preprocessing", "Setiap tweet diproses berurutan melalui 5 tahap sebelum siap dianalisis sentimennya" @@ -1077,7 +1022,6 @@ def show(): _render_flow_arrow() _gap("md") - # ── Load data dari database ──────────────────────────────── try: df_all = pd.read_sql("SELECT * FROM tweets ORDER BY created_at DESC", engine) if df_all.empty: @@ -1100,9 +1044,6 @@ def show(): st.warning(f"⚠️ Tidak ada tweet dengan tanggal asli dalam periode {filter_label}.") return - # ── Cache preprocessing ──────────────────────────────────── - # Cache key: kombinasi mode + periode + jumlah tweet di DB - # Jika ada tweet baru → cache otomatis invalid → proses ulang total_tweets_in_db = get_tweet_count() latest_crawl_marker = get_latest_crawl_time() or "no-crawl" data_marker = (total_tweets_in_db, latest_crawl_marker) @@ -1112,7 +1053,6 @@ def show(): f"{start_date}_{end_date}_{total_tweets_in_db}_{latest_crawl_marker}" ) - # Bersihkan cache lama untuk mode/periode yang sudah tidak aktif for old_key in list(st.session_state.keys()): if old_key.startswith("pp5_") and old_key != cache_key: del st.session_state[old_key] @@ -1123,7 +1063,6 @@ def show(): with st.spinner("🧹 Menjalankan 5 tahap preprocessing…"): results = [] for _, row in df.iterrows(): - # Jalankan 5 tahap — norm_dict diteruskan sebagai parameter r = full_preprocessing( text = row["text"], stopwords = stopwords, @@ -1137,9 +1076,7 @@ def show(): results.append(r) df_c = pd.DataFrame(results) - # Buang baris yang clean_text-nya kosong setelah semua 5 tahap df_c = df_c[df_c["clean_text"].str.strip().str.len() > 0].copy() - # Reset index agar rapi df_c = df_c.reset_index(drop=True) st.session_state[cache_key] = df_c @@ -1149,7 +1086,6 @@ def show(): df_c = st.session_state[cache_key] stemmer_ok = st.session_state.get(cache_key + "_sw_ok", False) - # ── Statistik ────────────────────────────────────────────── removed = len(df) - len(df_c) _section_header( @@ -1163,7 +1099,6 @@ def show(): _render_live_example(df_c) _gap("lg") - # ── Tabel ────────────────────────────────────────────────── _section_header( "📋 Tabel Perbandingan Teks per Tahap", f"{len(df_c):,} tweet · {filter_label} — scroll horizontal untuk lihat semua kolom" @@ -1173,7 +1108,6 @@ def show(): df_c = df_c.copy() df_c["crawled_at"] = pd.NaT - # Kolom ditampilkan sesuai urutan pipeline disp = df_c[[ "tweet_id", "created_at", "crawled_at", "text_asli", @@ -1223,10 +1157,8 @@ def show(): _render_top_words_chart(df_c) _gap("lg") - # ── Simpan ke session state untuk halaman sentimen ───────── st.session_state["preprocessed_df"] = df_c - # ── Download ─────────────────────────────────────────────── st.markdown("""
= 2 → Positif), - Layer anti-bias diperketat agar prediksi lebih proporsional. - 3. NEGATION WINDOW DIPERLUAS — window 3 kata (sebelumnya 2) agar - "tidak terlalu bagus" tetap terdeteksi negasinya. - 4. PREPROCESSING IDENTIK dengan preprocessing_page.py (5 tahap). +sentiment_service.py — Hybrid Classifier (versi perbaikan v2) +================================================================ +PERBAIKAN UTAMA vs versi sebelumnya: + + MASALAH 1 — NORMALISASI MERUSAK KONTEKS SENTIMEN + 'mending' → 'lebih baik' (salah: di domain override) + Akibat: "mending ngurusin judol daripada ngurusin ongkir" + → "lebih baik ngurusin judol daripada..." + → lexicon tangkap 'baik' = POSITIF (SEHARUSNYA NEGATIF) + SOLUSI: Override 'mending' → 'mending' (biarkan apa adanya); + hapus 'mendingan' → 'lebih baik' dari domain override. + + MASALAH 2 — LEXICON TERLALU LUAS (KATA KONTEKSTUAL) + Kata-kata berikut dihapus dari LEXICON_POSITIF karena terlalu + kontekstual — maknanya bergantung penuh pada kalimat sekitar: + "baik" → "lebih baik X daripada Y" bukan pujian + "benar" → "itu benar" bisa netral + "penting" → "lebih penting" bukan pujian + "wajar" → "wajar aja" bisa netral + "perlu" → "perlu X" bukan pujian + "tepat" → bisa kontekstual + "jelas" → bisa kontekstual + "fair" → bisa kontekstual + "manfaat" → bisa kontekstual + SOLUSI: Hapus dari LEXICON_POSITIF, pindahkan ke list terpisah + yang tidak ikut skor lexicon otomatis. + + MASALAH 3 — POLA KOMPARATIF TIDAK DIKENALI + "mending X daripada Y", "lebih baik X daripada Y" = kritik implisit + SOLUSI: Tambahkan deteksi POLA_KOMPARATIF_NEGATIF yang memberi + skor negatif ketika pola ini ditemukan di teks. + + MASALAH 4 — POLA KRITIK TERSIRAT TIDAK DIKENALI + "tidak penting", "gak usah", "ngapain", "begini aja" = kritik implisit + SOLUSI: Tambahkan POLA_KRITIK_TERSIRAT yang memberi skor negatif + ketika pola ini ditemukan. + + MASALAH 5 — "pembatasan gratis" DIHITUNG POSITIF + "pembatasan gratis ongkir" → lexicon tangkap 'gratis' = POSITIF + padahal konteksnya adalah keluhan/informasi negatif. + SOLUSI: Jika 'gratis' didahului 'pembatasan' dalam window 3 kata, + tidak dihitung sebagai sinyal positif. + + MASALAH 6 — TWEET INFORMATIF DIKLASIFIKASI POSITIF/NEGATIF + "saya melihat berita mengenai pembatasan gratis ongkir" → NETRAL + SOLUSI: Deteksi KATA_INFORMATIF; jika tweet hanya berisi konteks + informatif tanpa kata sentimen eksplisit → dorong ke Netral. """ import re @@ -49,60 +85,78 @@ KATA_SENTIMEN_PENTING = { # ═══════════════════════════════════════════════════════════ -# LEXICON SENTIMEN -# Diperluas agar kata yang tidak ada di vocab TF-IDF tetap -# bisa berkontribusi melalui jalur lexicon scoring. +# LEXICON SENTIMEN (DIPERBAIKI — kata kontekstual dihapus) +# +# PRINSIP PEMILIHAN KATA LEXICON: +# Kata masuk lexicon HANYA jika bisa berdiri sendiri sebagai +# sinyal sentimen tanpa bergantung konteks kalimat di sekitarnya. +# +# DIHAPUS dari versi lama karena terlalu kontekstual: +# "baik", "benar", "penting", "tepat", "jelas", "transparan", +# "amanah", "wajar", "fair", "perlu", "manfaat", "kompetitif" # ═══════════════════════════════════════════════════════════ LEXICON_POSITIF = { - # Umum & informal - "bagus", "baik", "keren", "mantap", "mantep", "hebat", + # Apresiasi murni + "bagus", "keren", "mantap", "mantep", "hebat", "oke", "sip", "top", "jos", "goks", "kece", "mantul", + "terbaik", "cakep", "cucok", "gaskeun", "kuy", + # Dukungan / persetujuan "setuju", "dukung", "mendukung", "pro", "lanjut", "sepakat", + # Emosi positif "bangga", "senang", "suka", "puas", "gembira", "bahagia", - "berhasil", "sukses", "berjaya", "prestasi", "pencapaian", + "syukur", "alhamdulillah", + # Keberhasilan + "berhasil", "sukses", "berjaya", + # Kualitas SDM/institusi "andal", "handal", "gercep", "sigap", "tanggap", "tegas", "adil", "bijak", "bermanfaat", "berguna", "membantu", - "inovatif", "maju", "berkembang", "sejahtera", - "benar", "tepat", "jelas", "transparan", "amanah", "terpercaya", + "inovatif", "maju", "berkembang", "sejahtera", "terpercaya", + # Ekonomi / ongkir positif "untung", "gratis", "murah", "hemat", "terjangkau", - "terbaik", "luar biasa", - "cakep", "cucok", "gaskeun", "kuy", - "solusi", "manfaat", "menguntungkan", - "memuaskan", "membanggakan", "mengagumkan", - "sehat", "fair", "wajar", - "syukur", "alhamdulillah", - "saing", "kompetitif", - # Domain ongkir/ecommerce positif - "terjangkau", "hemat", "efisien", "mudah", "praktis", - "cepat", "aman", "terpercaya", "andalan", - # Dukungan kebijakan - "dukung", "setuju", "bagus", "tepat", "bijak", - "perlu", "penting", "benar", "wajar", "adil", + "efisien", "mudah", "praktis", "cepat", "aman", "andalan", + # Solusi + "solusi", "menguntungkan", "memuaskan", "membanggakan", + "mengagumkan", + # ─── DIHAPUS (terlalu kontekstual): ──────────────── + # "baik" → "lebih baik X daripada Y" bukan pujian langsung + # "benar" → kontekstual ("itu benar" bisa netral) + # "penting" → "lebih penting" bukan pujian + # "wajar" → netral kontekstual + # "perlu" → netral kontekstual + # "tepat" → kontekstual + # "jelas" → kontekstual + # "fair" → kontekstual + # "manfaat" → kontekstual + # "kompetitif", "saing" → kontekstual } LEXICON_NEGATIF = { - # Umum + # Penilaian buruk "buruk", "jelek", "parah", "rusak", "hancur", "ancur", "gagal", "ambruk", "terpuruk", "bangkrut", - "bohong", "tipu", "curang", "manipulasi", "korupsi", - "kebohongan", "penipuan", - "kecewa", "mending", "malah", "marah", "sedih", - "khawatir", "takut", "benci", "jijik", "muak", - "kesal", "frustrasi", "geram", "dongkol", - "mahal", "rugi", "merugikan", "rugikan", - "lambat", "lemot", "lelet", "ribet", "susah", - "sulit", "bermasalah", "ngaco", "ngasal", "gaje", "receh", - "tolol", "bodoh", "idiot", "goblok", - "mengecewakan", "menyebalkan", "menyusahkan", + "salah", "keliru", "gegabah", "sembarangan", "ngawur", + # Ketidakjujuran + "bohong", "tipu", "curang", "manipulasi", "korupsi", + "kebohongan", "penipuan", "hoax", "kibul", "monopoli", "licik", - # Domain ongkir negatif - "boros", "memberatkan", "menyulitkan", - "repot", "ribet", "ngeributin", "ribut", - # Kritik kebijakan - "salah", "keliru", "gegabah", "sembarangan", - "tidak jelas", "ngawur", "asal", + # Emosi negatif + "kecewa", "marah", "sedih", "khawatir", "takut", + "benci", "jijik", "muak", "kesal", "frustrasi", + "geram", "dongkol", + # Ekonomi / ongkir negatif + "mahal", "rugi", "merugikan", "rugikan", "overprice", + "lambat", "lemot", "lelet", "boros", + "memberatkan", "menyulitkan", + # Kesulitan / masalah + "ribet", "susah", "sulit", "bermasalah", "repot", + "ngeributin", + # Sifat mengecewakan + "mengecewakan", "menyebalkan", "menyusahkan", + # Kritik / penolakan + "mengeluh", "protes", "menolak", "tolak", "keberatan", + "diskriminasi", "zalim", } KATA_NEGASI = { @@ -112,11 +166,72 @@ KATA_NEGASI = { } +# ═══════════════════════════════════════════════════════════ +# POLA KONTEKSTUAL (BARU — deteksi kritik implisit) +# +# Pola-pola ini mendeteksi sentimen dari struktur kalimat, +# bukan hanya dari kata individual. Sangat penting untuk +# tweet berbahasa informal Indonesia. +# ═══════════════════════════════════════════════════════════ + +# Pola komparatif yang menandakan kritik/saran negatif tersirat +# Format: (regex_pattern, skor_negatif_tambahan) +POLA_KOMPARATIF_NEGATIF = [ + # "mending X daripada Y" — membandingkan, menyiratkan Y tidak layak + (r"\bmending\b.{1,80}\bdaripada\b", 2), + # "lebih baik X daripada Y" — sama dengan di atas + (r"\blebih baik\b.{1,80}\bdaripada\b", 1), + # "daripada X, mending Y" — variasi urutan + (r"\bdaripada\b.{1,50}\bmending\b", 1), + # "ketimbang urus ongkir, mending urus judol" + (r"\bketimbang\b.{1,60}\b(kebijakan|urus|ngurusin)\b", 1), +] + +# Pola kritik tersirat — frasa yang menyiratkan ketidaksetujuan +# meskipun tidak ada kata negatif eksplisit +POLA_KRITIK_TERSIRAT = [ + # "tidak penting / gak penting" — dismissif + (r"\b(tidak|tak|gak|ga|ngga|nggak)\b.{0,15}\bpenting\b", 1), + # "ngapain / buat apa / untuk apa" + konteks kebijakan + (r"\b(ngapain|buat apa|untuk apa|ngapain)\b.{1,50}\b(kebijakan|ongkir|aturan|regulasi)\b", 2), + # "gak usah / tidak usah / gak perlu" + (r"\b(gak|ga|tidak|tak|ngga)\b\s*(usah|perlu)\b", 1), + # "percuma / sia-sia / buang-buang" + (r"\b(percuma|sia-sia|buang-buang)\b", 2), + # "mending urusin yang lain / yang lebih penting" + (r"\bmending\b.{1,30}\b(urusin|urus)\b", 1), + # "kebijakan begini / aturan begini" — menyiratkan tidak setuju + (r"\b(kebijakan|aturan|regulasi)\b.{0,20}\bbegini\b", 1), + # "apa gunanya / apa manfaatnya" — retorikal negatif + (r"\bapa\b.{0,10}\b(guna|manfaat|untung)\b.{0,10}(nya|sih|ini)\b", 1), +] + +# Kata informatif — menunjukkan tweet berisi pelaporan/informasi netral +KATA_INFORMATIF = { + "berita", "melihat", "membaca", "mendengar", "mengetahui", + "laporan", "informasi", "kabar", "melaporkan", "dikabarkan", + "menurut", "dilaporkan", "diberitakan", "dikutip", "mengutip", +} + + # ═══════════════════════════════════════════════════════════ # LOAD NORMALISASI DARI FILE +# PERUBAHAN: Hapus override 'mending' → 'lebih baik' karena +# mengubah kata kritis negatif menjadi sinyal positif. # ═══════════════════════════════════════════════════════════ def _load_normalization() -> dict: + """ + Muat kamus normalisasi dari file eksternal. + + PERBAIKAN di versi ini: + - 'mending' dan 'mendingan' TIDAK lagi dioverride ke 'lebih baik' + karena mengakibatkan kata negatif/kritis menjadi sinyal positif + di lexicon scoring. Kata ini dibiarkan apa adanya agar POLA_KOMPARATIF + dan POLA_KRITIK dapat mendeteksinya. + - Override 'malah' dihapus — file normalisasi umum mengubah + 'malah' → 'bahkan' yang bisa mengubah konteks sentimen. + """ norm_file = "indonesian-normalisasi-slangword-complete.txt" norm_dict: dict = {} try: @@ -135,34 +250,67 @@ def _load_normalization() -> dict: except FileNotFoundError: pass - DOMAIN_OVERRIDES = { - "shopee": "shopee", "tokopedia": "tokopedia", "lazada": "lazada", - "tiktok": "tiktok", "bukalapak": "bukalapak", "blibli": "blibli", - "sicepat": "sicepat", "jne": "jne", "jnt": "jnt", - "anteraja": "anteraja", "ninja": "ninja", - "freeongkir": "gratis ongkos kirim", + # ── Override khusus domain ─────────────────────────────────────────────── + # Entri ini menimpa file generik. Perhatikan komentar DIHAPUS di bawah. + DOMAIN_OVERRIDES: dict = { + # Nama platform — pertahankan apa adanya + "shopee": "shopee", + "tokopedia": "tokopedia", + "lazada": "lazada", + "tiktok": "tiktok", + "bukalapak": "bukalapak", + "blibli": "blibli", + # Logistik + "sicepat": "sicepat", + "jne": "jne", + "jnt": "jnt", + "anteraja": "anteraja", + "ninja": "ninja", + # Ongkir & belanja + "freeongkir": "gratis ongkos kirim", "gratisongkir": "gratis ongkos kirim", - "ongkir": "ongkos kirim", "ongkr": "ongkos kirim", - "bykrm": "biaya kirim", "biayakirim": "biaya pengiriman", - "komdigi": "komdigi", "kemendag": "kementerian perdagangan", - "kominfo": "kementerian komunikasi", - "ecommerce": "e commerce", "marketplace": "marketplace", - "seller": "penjual", "buyer": "pembeli", "online": "online", - # Negasi tambahan - "gk": "tidak", "ga": "tidak", "gak": "tidak", - "nggak": "tidak", "ngga": "tidak", "tdk": "tidak", - "tak": "tidak", "enggak": "tidak", "engga": "tidak", - "kagak": "tidak", "kaga": "tidak", "ndak": "tidak", - "ngak": "tidak", + "ongkir": "ongkos kirim", + "ongkr": "ongkos kirim", + "bykrm": "biaya kirim", + "biayakirim": "biaya pengiriman", + # Kebijakan & lembaga + "komdigi": "komdigi", + "kemendag": "kementerian perdagangan", + "kominfo": "kementerian komunikasi", + # E-commerce umum + "ecommerce": "e commerce", + "marketplace": "marketplace", + "seller": "penjual", + "buyer": "pembeli", + "online": "online", + # Negasi informal — pastikan ditangkap + "gk": "tidak", "ga": "tidak", "gak": "tidak", + "nggak": "tidak", "ngga": "tidak", "tdk": "tidak", + "tak": "tidak", "enggak": "tidak", "engga": "tidak", + "kagak": "tidak", "kaga": "tidak", "ndak": "tidak", + "ngak": "tidak", # Intensitas - "bgt": "banget", "bngt": "banget", "bget": "banget", - "bgtt": "banget", - # Positif informal - "mantep": "mantap", "mntap": "mantap", - "bener": "benar", "beneran": "benar", - "kece": "keren", "sip": "baik", - # Negatif informal - "ancur": "hancur", "parahh": "parah", + "bgt": "banget", "bngt": "banget", "bget": "banget", "bgtt": "banget", + # Positif informal — hanya yang benar-benar positif + "mantep": "mantap", "mntap": "mantap", + "kece": "keren", + "ancur": "hancur", "parahh": "parah", + # ── SENGAJA TIDAK DIOVERRIDE (vs versi lama): ──────────────────────── + # "mending" → TIDAK diubah ke "lebih baik" + # Alasan: "mending X daripada Y" adalah ekspresi kritik. + # Mengubah ke "lebih baik" membuat lexicon menangkap 'baik' = POSITIF, + # padahal kalimatnya bermakna negatif/kritik. Biarkan "mending" apa + # adanya agar POLA_KOMPARATIF_NEGATIF bisa mendeteksinya. + # + # "mendingan" → TIDAK diubah ke "lebih baik" (alasan sama) + # + # "malah" → TIDAK dioverride. File normalisasi mengubah 'mlah'→'malah' + # yang sudah benar; 'malah' sendiri tidak perlu diubah ke 'bahkan' + # karena mengubah nuansa kritis. + # + # "sip" → TIDAK dioverride ke "baik". "sip" cukup dikenal dan + # berdiri sendiri sebagai apresiasi. "baik" sudah dihapus dari + # lexicon karena terlalu kontekstual. } norm_dict.update(DOMAIN_OVERRIDES) return norm_dict @@ -173,6 +321,15 @@ def _load_normalization() -> dict: # ═══════════════════════════════════════════════════════════ def _load_stopwords() -> set: + """ + Muat daftar stopword dari file eksternal. + + PERBAIKAN di versi ini: + - Pertahankan 'mending' dari stopword removal. Kata ini penting + sebagai penanda POLA_KOMPARATIF_NEGATIF dan POLA_KRITIK_TERSIRAT. + - Pertahankan 'daripada' dari stopword removal. Kata ini adalah + komponen kunci pola "mending X daripada Y". + """ stopword_file = "indonesian-stopwords-complete.txt" base: set = set() try: @@ -189,11 +346,26 @@ def _load_stopwords() -> set: "jika", "sudah", "telah", "jadi", "bisa", } - # Lindungi kata sentimen penting + # ── Lindungi kata sentimen penting ────────────────────────────────────── for kata in KATA_SENTIMEN_PENTING: base.discard(kata) - # Tambah noise Twitter + # ── Lindungi kata penanda pola kontekstual ────────────────────────────── + # Kata-kata ini diperlukan agar POLA_KOMPARATIF dan POLA_KRITIK bisa + # mendeteksi struktur kalimat dengan benar di teks yang sudah bersih. + KATA_POLA_PENTING: set = { + "mending", # penanda pola komparatif negatif + "mendingan", # variasi mending + "daripada", # komponen "mending X daripada Y" + "ketimbang", # variasi daripada + "ngapain", # penanda kritik tersirat + "percuma", # penanda sia-sia + "begini", # "kebijakan begini" = kritik tersirat + } + for kata in KATA_POLA_PENTING: + base.discard(kata) + + # ── Tambah noise Twitter/sosmed ───────────────────────────────────────── base.update({ "rt", "amp", "https", "http", "co", "pic", "wkwk", "wkwkwk", "wkwkwkwk", @@ -216,7 +388,7 @@ def _load_stemmer(): return None -# ── Inisialisasi global (dimuat sekali saat modul diimport) ─ +# ── Inisialisasi global ────────────────────────────────────────────────────── _STOPWORDS = _load_stopwords() _STEMMER = _load_stemmer() _NORM_DICT = _load_normalization() @@ -247,6 +419,7 @@ def _load_model(): # ═══════════════════════════════════════════════════════════ # 5-TAHAP PREPROCESSING PIPELINE +# IDENTIK dengan preprocessing_page.py # ═══════════════════════════════════════════════════════════ def _step1_case_folding(text: str) -> str: @@ -312,54 +485,104 @@ def preprocess_for_model(text: str) -> str: def preprocess_untuk_lexicon(text: str) -> str: - """Preprocessing ringan untuk lexicon matching (tanpa stemming).""" + """ + Preprocessing untuk lexicon matching. + PENTING: TIDAK distem dan TIDAK dihapus stopword-nya agar + pola kontekstual (mending, daripada, begini, dll.) tetap ada + dan bisa dideteksi oleh POLA_KOMPARATIF dan POLA_KRITIK. + """ s1 = _step1_case_folding(text) s2 = _step2_cleaning(s1) s3 = _step3_normalization(s2, _NORM_DICT) - return s3 + return s3 # Kembalikan setelah normalisasi saja — stopword & stem TIDAK dilakukan # ═══════════════════════════════════════════════════════════ -# LEXICON SCORER (dengan negation window diperluas ke 3) +# LEXICON SCORER (DIPERBAIKI — pola kontekstual + pembatasan) # ═══════════════════════════════════════════════════════════ def _hitung_skor_lexicon(teks_lexicon: str) -> dict: """ - Hitung skor sentimen via lexicon + negation handling. + Hitung skor sentimen via lexicon + pola kontekstual + negation handling. - Perubahan vs versi lama: - - Window negasi diperluas menjadi 3 kata (sebelumnya 2) - - Lexicon positif/negatif lebih luas (kata yang tidak ada di vocab TF-IDF) - - Return: {"positif": int, "negatif": int, "net": int} + PERUBAHAN UTAMA vs versi lama: + ───────────────────────────────────────────────────────────────────── + 1. POLA_KOMPARATIF_NEGATIF: "mending X daripada Y" → tambah skor negatif + 2. POLA_KRITIK_TERSIRAT: "tidak penting", "gak usah", dll. → skor negatif + 3. POLA 'pembatasan gratis': 'gratis' tidak dihitung positif jika + didahului 'pembatasan' dalam window 3 kata + 4. DETEKSI TWEET INFORMATIF: jika teks hanya berisi konteks informasi + tanpa kata sentimen eksplisit, tandai sebagai 'informatif' + 5. Window negasi tetap 3 kata (dari versi sebelumnya) + ───────────────────────────────────────────────────────────────────── + Return: {"positif": int, "negatif": int, "net": int, "informatif": bool} """ tokens = teks_lexicon.split() skor_pos = 0 skor_neg = 0 + # ── Tahap 1: Deteksi pola komparatif ────────────────────────────────── + for pola, bobot in POLA_KOMPARATIF_NEGATIF: + if re.search(pola, teks_lexicon): + skor_neg += bobot + + # ── Tahap 2: Deteksi pola kritik tersirat ───────────────────────────── + for pola, bobot in POLA_KRITIK_TERSIRAT: + if re.search(pola, teks_lexicon): + skor_neg += bobot + + # ── Tahap 3: Lexicon per token ──────────────────────────────────────── for i, token in enumerate(tokens): - # Cek negasi dalam window 3 kata sebelumnya + # Negation window: 3 kata sebelumnya ada_negasi = any( tokens[i - j] in KATA_NEGASI for j in range(1, 4) if i - j >= 0 ) + # Konteks pembatasan: 'gratis' setelah 'pembatasan' tidak = positif + ada_pembatasan = any( + tokens[i - j] == "pembatasan" + for j in range(1, 4) + if i - j >= 0 + ) if token in LEXICON_POSITIF: if ada_negasi: skor_neg += 1 + elif ada_pembatasan and token == "gratis": + # "pembatasan gratis ongkir" = konteks negatif/netral, + # bukan pujian terhadap 'gratis'. Lewati. + pass else: skor_pos += 1 + elif token in LEXICON_NEGATIF: if ada_negasi: skor_pos += 1 else: skor_neg += 1 + # ── Tahap 4: Deteksi tweet informatif ──────────────────────────────── + # Tweet informatif: mengandung kata pelaporan, TIDAK ada kata sentimen + # eksplisit, dan panjang teks tidak terlalu pendek. + token_set = set(tokens) + ada_info_kata = bool(token_set & KATA_INFORMATIF) + ada_sentimen_eksplisit = bool( + (token_set & LEXICON_POSITIF) | (token_set & LEXICON_NEGATIF) + ) + # Informatif jika: ada kata informatif + tidak ada sentimen eksplisit + # + skor negatif dari pola kecil (≤1, artinya cuma 'pembatasan') + is_informatif = ( + ada_info_kata + and not ada_sentimen_eksplisit + and skor_neg <= 1 + ) + return { - "positif": skor_pos, - "negatif": skor_neg, - "net": skor_pos - skor_neg, + "positif": skor_pos, + "negatif": skor_neg, + "net": skor_pos - skor_neg, + "informatif": is_informatif, } @@ -406,7 +629,7 @@ def _prediksi_model(teks_model: str): # ═══════════════════════════════════════════════════════════ -# HYBRID CLASSIFIER (diperkuat) +# HYBRID CLASSIFIER (DIPERBAIKI) # ═══════════════════════════════════════════════════════════ def _klasifikasi_hybrid( @@ -415,66 +638,75 @@ def _klasifikasi_hybrid( teks_lower: str, ) -> tuple: """ - Klasifikasi hybrid: sinyal lexicon + model NB 3-kelas. + Klasifikasi hybrid: sinyal lexicon + pola kontekstual + model NB. - PERUBAHAN vs versi lama: - ───────────────────────────────────────────────────────── - Layer 1 — Override Positif KUAT (net >= 2): - Confidence lebih tinggi karena lexicon lebih kuat. - Range: 0.65–0.92 + ALUR KEPUTUSAN: + ───────────────────────────────────────────────────────────────────── + Layer 0 — Override Informatif: + Jika skor['informatif'] = True DAN net mendekati 0 → Netral langsung. + Mencegah tweet berita/informatif terklasifikasi positif/negatif + karena kata domain (mis. 'gratis' dalam "berita mengenai gratis ongkir"). + + Layer 1a — Override Positif KUAT (net >= 2): + Sinyal lexicon + pola sangat kuat → Positif langsung. Layer 1b — Override Negatif KUAT (net <= -2): - Simetris dengan positif. - Range: 0.65–0.90 + Sinyal lexicon + pola sangat kuat → Negatif langsung. + CATATAN: Pola komparatif "mending X daripada Y" menambah net -2/-3 + sehingga tweet kritik implisit langsung terdeteksi di sini. - Layer 2 — Override Positif LEMAH (net == 1): - Diperlonggar: sekarang berlaku jika model tidak sangat - yakin negatif (threshold 0.70, sebelumnya 0.65). + Layer 2a — Override Positif LEMAH (net == 1): + Konsultasi model. Jika model tidak sangat yakin Negatif → Positif. Layer 2b — Override Negatif LEMAH (net == -1): - Simetris baru. Sebelumnya tidak ada. + Konsultasi model. Jika model tidak sangat yakin Positif → Negatif. Layer 3 — Fallback Model NB: - Anti-bias diperketat: - - Model Negatif + lexicon bersih (net >= 0) + conf < 0.65 - → turunkan ke Netral (threshold naik dari 0.70 ke 0.65) - - Model Positif + lexicon negatif kuat (net <= -1) + conf < 0.65 - → turunkan ke Netral + Anti-bias: + - Model Negatif + lexicon bersih (net >= 0) + conf < 0.65 → Netral + - Model Positif + lexicon negatif (net <= -1) + conf < 0.65 → Netral - Layer 4 — Ultimate Fallback: - Lexicon saja jika model tidak tersedia. - ───────────────────────────────────────────────────────── + Layer 4 — Ultimate Fallback (model tidak tersedia): + Gunakan sinyal lexicon saja. + ───────────────────────────────────────────────────────────────────── Return: (label: str, confidence: float) """ - net = skor["net"] - pos = skor["positif"] - neg = skor["negatif"] + net = skor["net"] + is_info = skor.get("informatif", False) - # ── Layer 1a: Positif KUAT ─────────────────────────────────────────────── + # ── Layer 0: Override tweet informatif ─────────────────────────────── + # Tweet yang hanya berisi pelaporan/informasi tanpa sentimen eksplisit + # dan net mendekati 0 → langsung Netral agar tidak salah klasifikasi. + if is_info and -1 <= net <= 1: + return ("Netral", 0.52) + + # ── Layer 1a: Positif KUAT ──────────────────────────────────────────── if net >= 2: conf = min(0.65 + (net * 0.05), 0.92) return ("Positif", round(conf, 3)) - # ── Layer 1b: Negatif KUAT ─────────────────────────────────────────────── + # ── Layer 1b: Negatif KUAT ──────────────────────────────────────────── + # Pola komparatif ("mending X daripada Y") memberi net -2 hingga -4, + # sehingga tweet kritik implisit langsung tertangkap di layer ini. if net <= -2: - conf = min(0.65 + (abs(net) * 0.05), 0.90) + conf = min(0.65 + (abs(net) * 0.05), 0.92) return ("Negatif", round(conf, 3)) - # ── Layer 2a: Positif LEMAH ────────────────────────────────────────────── - if net == 1 and pos >= 1: + # ── Layer 2a: Positif LEMAH ─────────────────────────────────────────── + if net == 1: model_result = _prediksi_model(teks_model) if model_result is not None: _, _, proba_dict = model_result neg_prob = proba_dict.get("Negatif", 0.0) - if neg_prob < 0.70: # diperlonggar dari 0.65 + if neg_prob < 0.70: conf = round(0.55 + (0.70 - neg_prob) * 0.30, 3) return ("Positif", min(conf, 0.82)) else: return ("Positif", 0.55) return ("Positif", 0.58) - # ── Layer 2b: Negatif LEMAH (baru) ─────────────────────────────────────── - if net == -1 and neg >= 1: + # ── Layer 2b: Negatif LEMAH ─────────────────────────────────────────── + if net == -1: model_result = _prediksi_model(teks_model) if model_result is not None: _, _, proba_dict = model_result @@ -486,7 +718,7 @@ def _klasifikasi_hybrid( return ("Negatif", 0.55) return ("Negatif", 0.58) - # ── Layer 3: Fallback Model NB 3-kelas ─────────────────────────────────── + # ── Layer 3: Fallback Model NB ──────────────────────────────────────── model_result = _prediksi_model(teks_model) if model_result is not None: label_norm, confidence, proba_dict = model_result @@ -503,7 +735,7 @@ def _klasifikasi_hybrid( return (label_norm, round(confidence, 3)) - # ── Layer 4: Ultimate Fallback ──────────────────────────────────────────── + # ── Layer 4: Ultimate Fallback ──────────────────────────────────────── if net > 0: return ("Positif", 0.55) elif net < 0: diff --git a/tweets-data/Error-30-05-2026_08-21-41.png b/tweets-data/Error-30-05-2026_08-21-41.png new file mode 100644 index 0000000000000000000000000000000000000000..3ddab50b98da0d74381bd9f7089dc0c99ac14baf GIT binary patch literal 4254 zcmeAS@N?(olHy`uVBq!ia0y~yU#KiDjWttl9P!CsJDrMnSo)#sPJf*j3$WD+%Q@c zj24fhb;D@IINB;0Z4!+(6S23Efi38O(f0CadwI0IJlb9!bnWG?%4I8oO;~r(SOCQZ p_y?d#|NkF7qH+kxU;`P+%<#gUW5K!N4KhFx22WQ%mvv4FO#o+H0uulL literal 0 HcmV?d00001 diff --git a/tweets-data/Error-30-05-2026_08-22-55.png b/tweets-data/Error-30-05-2026_08-22-55.png new file mode 100644 index 0000000000000000000000000000000000000000..3ddab50b98da0d74381bd9f7089dc0c99ac14baf GIT binary patch literal 4254 zcmeAS@N?(olHy`uVBq!ia0y~yU#KiDjWttl9P!CsJDrMnSo)#sPJf*j3$WD+%Q@c zj24fhb;D@IINB;0Z4!+(6S23Efi38O(f0CadwI0IJlb9!bnWG?%4I8oO;~r(SOCQZ p_y?d#|NkF7qH+kxU;`P+%<#gUW5K!N4KhFx22WQ%mvv4FO#o+H0uulL literal 0 HcmV?d00001 diff --git a/tweets-data/Error-30-05-2026_08-29-08.png b/tweets-data/Error-30-05-2026_08-29-08.png new file mode 100644 index 0000000000000000000000000000000000000000..3ddab50b98da0d74381bd9f7089dc0c99ac14baf GIT binary patch literal 4254 zcmeAS@N?(olHy`uVBq!ia0y~yU#KiDjWttl9P!CsJDrMnSo)#sPJf*j3$WD+%Q@c zj24fhb;D@IINB;0Z4!+(6S23Efi38O(f0CadwI0IJlb9!bnWG?%4I8oO;~r(SOCQZ p_y?d#|NkF7qH+kxU;`P+%<#gUW5K!N4KhFx22WQ%mvv4FO#o+H0uulL literal 0 HcmV?d00001 diff --git a/tweets-data/Error-30-05-2026_08-30-33.png b/tweets-data/Error-30-05-2026_08-30-33.png new file mode 100644 index 0000000000000000000000000000000000000000..3ddab50b98da0d74381bd9f7089dc0c99ac14baf GIT binary patch literal 4254 zcmeAS@N?(olHy`uVBq!ia0y~yU#KiDjWttl9P!CsJDrMnSo)#sPJf*j3$WD+%Q@c zj24fhb;D@IINB;0Z4!+(6S23Efi38O(f0CadwI0IJlb9!bnWG?%4I8oO;~r(SOCQZ p_y?d#|NkF7qH+kxU;`P+%<#gUW5K!N4KhFx22WQ%mvv4FO#o+H0uulL literal 0 HcmV?d00001 diff --git a/tweets-data/Error-30-05-2026_19-21-03.png b/tweets-data/Error-30-05-2026_19-21-03.png new file mode 100644 index 0000000000000000000000000000000000000000..37498374136a3486a3fb2105e267f659fbb9092e GIT binary patch literal 92336 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≈kFe(gAjwM5y-v4U37W|NZosg7Vcu^)W3sbB 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%0AOfB=1d%|^RRrf&G0=20_`@^9n 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 literal 0 HcmV?d00001 diff --git a/tweets-data/hasil_top.csv b/tweets-data/hasil_top.csv index d3f461c..73b8803 100644 --- a/tweets-data/hasil_top.csv +++ b/tweets-data/hasil_top.csv @@ -1,8 +1,10 @@ "conversation_id_str","created_at","favorite_count","full_text","id_str","image_url","in_reply_to_screen_name","lang","location","quote_count","reply_count","retweet_count","tweet_url","user_id_str","username" -"2058829602865451445","Mon May 25 08:36:43 +0000 2026","0","komdigi mending ngurusin aja tuh judol daripada ngurusin pembatasan gratis ongkir","2058829602865451445","","","in","","0","0","0","https://x.com/undefined/status/2058829602865451445","2046458899843170304", -"2058950111976386607","Mon May 25 16:35:34 +0000 2026","0","komdigi bagus sih ngeluarin kebijakan gratis ongkir kaya ini setuju","2058950111976386607","","","in","","0","0","0","https://x.com/undefined/status/2058950111976386607","2046458899843170304", "2058950559856832819","Mon May 25 16:37:21 +0000 2026","0","setuju bgt komdigi ngeluarin kebijakan gratis ongkir gini","2058950559856832819","","","in","","0","0","0","https://x.com/undefined/status/2058950559856832819","2046458899843170304", -"2060234400777064942","Fri May 29 05:38:53 +0000 2026","0","tadi pagi saya melihat berita mengenai pembatasan gratis ongkir oleh komdigi","2060234400777064942","","","in","","0","0","0","https://x.com/undefined/status/2060234400777064942","1814143201718247424", -"2058816188659192179","Mon May 25 07:43:24 +0000 2026","0","komdigi gajelas bikin kebijakan ongkir!","2058816188659192179","","","in","","0","0","0","https://x.com/undefined/status/2058816188659192179","1814143201718247424", +"2058829602865451445","Mon May 25 08:36:43 +0000 2026","0","komdigi mending ngurusin aja tuh judol daripada ngurusin pembatasan gratis ongkir","2058829602865451445","","","in","","0","0","0","https://x.com/undefined/status/2058829602865451445","2046458899843170304", +"2060580175084204231","Sat May 30 04:32:52 +0000 2026","0","komdigi gratis ongkir sangat banyak yang tidak setuju","2060580175084204231","","","in","","0","0","0","https://x.com/undefined/status/2060580175084204231","1814143201718247424", "2059619299309011403","Wed May 27 12:54:41 +0000 2026","0","komdigi ngeluarin kebijakan ongkir kaya gini ngapain dah","2059619299309011403","","","in","","0","0","0","https://x.com/undefined/status/2059619299309011403","1814143201718247424", +"2058950111976386607","Mon May 25 16:35:34 +0000 2026","0","komdigi bagus sih ngeluarin kebijakan gratis ongkir kaya ini setuju","2058950111976386607","","","in","","0","0","0","https://x.com/undefined/status/2058950111976386607","2046458899843170304", +"2060641816647790635","Sat May 30 08:37:48 +0000 2026","0","komdigi gk penting deh ngeluarin kebijakan ongkir begini mending tu urusin yang lebih penting!!","2060641816647790635","","","in","","0","0","0","https://x.com/undefined/status/2060641816647790635","1814143201718247424", +"2058816188659192179","Mon May 25 07:43:24 +0000 2026","0","komdigi gajelas bikin kebijakan ongkir!","2058816188659192179","","","in","","0","0","0","https://x.com/undefined/status/2058816188659192179","1814143201718247424", "2058816239112446387","Mon May 25 07:43:37 +0000 2026","0","komdigi gk penting buat kebijakan ongkir kaya gini","2058816239112446387","","","in","","0","0","0","https://x.com/undefined/status/2058816239112446387","1814143201718247424", +"2060234400777064942","Fri May 29 05:38:53 +0000 2026","0","tadi pagi saya melihat berita mengenai pembatasan gratis ongkir oleh komdigi","2060234400777064942","","","in","","0","0","0","https://x.com/undefined/status/2060234400777064942","1814143201718247424", diff --git a/tweets-data/hasil_top.old.csv b/tweets-data/hasil_top.old.csv index b245d79..004324b 100644 --- a/tweets-data/hasil_top.old.csv +++ b/tweets-data/hasil_top.old.csv @@ -1,8 +1,10 @@ "conversation_id_str","created_at","favorite_count","full_text","id_str","image_url","in_reply_to_screen_name","lang","location","quote_count","reply_count","retweet_count","tweet_url","user_id_str","username" +"2058950559856832819","Mon May 25 16:37:21 +0000 2026","0","setuju bgt komdigi ngeluarin kebijakan gratis ongkir gini","2058950559856832819","","","in","","0","0","0","https://x.com/undefined/status/2058950559856832819","2046458899843170304", "2058829602865451445","Mon May 25 08:36:43 +0000 2026","0","komdigi mending ngurusin aja tuh judol daripada ngurusin pembatasan gratis ongkir","2058829602865451445","","","in","","0","0","0","https://x.com/undefined/status/2058829602865451445","2046458899843170304", "2058950111976386607","Mon May 25 16:35:34 +0000 2026","0","komdigi bagus sih ngeluarin kebijakan gratis ongkir kaya ini setuju","2058950111976386607","","","in","","0","0","0","https://x.com/undefined/status/2058950111976386607","2046458899843170304", -"2058950559856832819","Mon May 25 16:37:21 +0000 2026","0","setuju bgt komdigi ngeluarin kebijakan gratis ongkir gini","2058950559856832819","","","in","","0","0","0","https://x.com/undefined/status/2058950559856832819","2046458899843170304", -"2060234400777064942","Fri May 29 05:38:53 +0000 2026","0","tadi pagi saya melihat berita mengenai pembatasan gratis ongkir oleh komdigi","2060234400777064942","","","in","","0","0","0","https://x.com/undefined/status/2060234400777064942","1814143201718247424", -"2058816188659192179","Mon May 25 07:43:24 +0000 2026","0","komdigi gajelas bikin kebijakan ongkir!","2058816188659192179","","","in","","0","0","0","https://x.com/undefined/status/2058816188659192179","1814143201718247424", "2059619299309011403","Wed May 27 12:54:41 +0000 2026","0","komdigi ngeluarin kebijakan ongkir kaya gini ngapain dah","2059619299309011403","","","in","","0","0","0","https://x.com/undefined/status/2059619299309011403","1814143201718247424", +"2060641816647790635","Sat May 30 08:37:48 +0000 2026","0","komdigi gk penting deh ngeluarin kebijakan ongkir begini mending tu urusin yang lebih penting!!","2060641816647790635","","","in","","0","0","0","https://x.com/undefined/status/2060641816647790635","1814143201718247424", +"2060580175084204231","Sat May 30 04:32:52 +0000 2026","0","komdigi gratis ongkir sangat banyak yang tidak setuju","2060580175084204231","","","in","","0","0","0","https://x.com/undefined/status/2060580175084204231","1814143201718247424", +"2058816188659192179","Mon May 25 07:43:24 +0000 2026","0","komdigi gajelas bikin kebijakan ongkir!","2058816188659192179","","","in","","0","0","0","https://x.com/undefined/status/2058816188659192179","1814143201718247424", "2058816239112446387","Mon May 25 07:43:37 +0000 2026","0","komdigi gk penting buat kebijakan ongkir kaya gini","2058816239112446387","","","in","","0","0","0","https://x.com/undefined/status/2058816239112446387","1814143201718247424", +"2060234400777064942","Fri May 29 05:38:53 +0000 2026","0","tadi pagi saya melihat berita mengenai pembatasan gratis ongkir oleh komdigi","2060234400777064942","","","in","","0","0","0","https://x.com/undefined/status/2060234400777064942","1814143201718247424",