""" Topic Modelling menggunakan LDA (Latent Dirichlet Allocation) untuk Teks Bahasa Indonesia """ # 1. Import library yang diperlukan import pandas as pd import numpy as np import re import matplotlib.pyplot as plt from pprint import pprint # NLP processing import nltk from nltk.tokenize import word_tokenize from Sastrawi.Stemmer.StemmerFactory import StemmerFactory # Gensim import gensim import gensim.corpora as corpora from gensim.models import CoherenceModel import pyLDAvis import pyLDAvis.gensim_models # Scikit-learn from sklearn.feature_extraction.text import CountVectorizer # Memastikan paket NLTK yang diperlukan sudah terunduh # nltk.download('punkt') # 2. Load dataset def load_data(file_path): """ Memuat data dari file CSV """ df = pd.read_csv(file_path, sep=';') return df # 3. Preprocessing text def preprocess_text(text): """ Preprocessing teks: - Mengubah ke lowercase - Menghapus emoji dan karakter khusus - Menghapus angka - Menghapus URL """ if isinstance(text, str): # Lowercase text = text.lower() # Hapus URL text = re.sub(r'https?://\S+|www\.\S+', '', text) # Hapus emoji dan karakter khusus text = re.sub(r'[^\w\s]', '', text) # Hapus angka text = re.sub(r'\d+', '', text) # Hapus multiple whitespace text = re.sub(r'\s+', ' ', text).strip() return text return "" # 4. Stopwords Bahasa Indonesia def get_stopwords(): """ Daftar stopwords Bahasa Indonesia """ stopwords = [ 'ada', 'adalah', 'adanya', 'adapun', 'agak', 'agaknya', 'agar', 'akan', 'akankah', 'akhir', 'akhiri', 'akhirnya', 'aku', 'akulah', 'amat', 'amatlah', 'anda', 'andalah', 'antar', 'antara', 'antaranya', 'apa', 'apaan', 'apabila', 'apakah', 'apalagi', 'apatah', 'artinya', 'asal', 'asalkan', 'atas', 'atau', 'ataukah', 'ataupun', 'awal', 'awalnya', 'bagai', 'bagaikan', 'bagaimana', 'bagaimanakah', 'bagaimanapun', 'bagi', 'bagian', 'bahkan', 'bahwa', 'bahwasanya', 'baik', 'bakal', 'bakalan', 'balik', 'banyak', 'bapak', 'baru', 'bawah', 'beberapa', 'begini', 'beginian', 'beginikah', 'beginilah', 'begitu', 'begitukah', 'begitulah', 'begitupun', 'bekerja', 'belakang', 'belakangan', 'belum', 'belumlah', 'benar', 'benarkah', 'benarlah', 'berada', 'berakhir', 'berakhirlah', 'berakhirnya', 'berapa', 'berapakah', 'berapalah', 'berapapun', 'berarti', 'berawal', 'berbagai', 'berdatangan', 'beri', 'berikan', 'berikut', 'berikutnya', 'berjumlah', 'berkali-kali', 'berkata', 'berkehendak', 'berkeinginan', 'berkenaan', 'berlainan', 'berlalu', 'berlangsung', 'berlebihan', 'bermacam', 'bermacam-macam', 'bermaksud', 'bermula', 'bersama', 'bersama-sama', 'bersiap', 'bersiap-siap', 'bertanya', 'bertanya-tanya', 'berturut', 'berturut-turut', 'bertutur', 'berujar', 'berupa', 'besar', 'betul', 'betulkah', 'biasa', 'biasanya', 'bila', 'bilakah', 'bisa', 'bisakah', 'boleh', 'bolehkah', 'bolehlah', 'buat', 'bukan', 'bukankah', 'bukanlah', 'bukannya', 'bulan', 'bung', 'cara', 'caranya', 'cukup', 'cukupkah', 'cukuplah', 'cuma', 'dahulu', 'dalam', 'dan', 'dapat', 'dari', 'daripada', 'datang', 'dekat', 'demi', 'demikian', 'demikianlah', 'dengan', 'depan', 'di', 'dia', 'diakhiri', 'diakhirinya', 'dialah', 'diantara', 'diantaranya', 'diberi', 'diberikan', 'diberikannya', 'dibuat', 'dibuatnya', 'didapat', 'didatangkan', 'digunakan', 'diibaratkan', 'diibaratkannya', 'diingat', 'diingatkan', 'diinginkan', 'dijawab', 'dijelaskan', 'dijelaskannya', 'dikarenakan', 'dikatakan', 'dikatakannya', 'dikerjakan', 'diketahui', 'diketahuinya', 'dikira', 'dilakukan', 'dilalui', 'dilihat', 'dimaksud', 'dimaksudkan', 'dimaksudkannya', 'dimaksudnya', 'diminta', 'dimintai', 'dimisalkan', 'dimulai', 'dimulailah', 'dimulainya', 'dimungkinkan', 'dini', 'dipastikan', 'diperbuat', 'diperbuatnya', 'dipergunakan', 'diperkirakan', 'diperlihatkan', 'diperlukan', 'diperlukannya', 'dipersoalkan', 'dipertanyakan', 'dipunyai', 'diri', 'dirinya', 'disampaikan', 'disebut', 'disebutkan', 'disebutkannya', 'disini', 'disinilah', 'ditambahkan', 'ditandaskan', 'ditanya', 'ditanyai', 'ditanyakan', 'ditegaskan', 'ditujukan', 'ditunjuk', 'ditunjuki', 'ditunjukkan', 'ditunjukkannya', 'ditunjuknya', 'dituturkan', 'dituturkannya', 'diucapkan', 'diucapkannya', 'diungkapkan', 'dong', 'dua', 'dulu', 'empat', 'enggak', 'enggaknya', 'entah', 'entahlah', 'guna', 'gunakan', 'hal', 'hampir', 'hanya', 'hanyalah', 'hari', 'harus', 'haruslah', 'harusnya', 'hendak', 'hendaklah', 'hendaknya', 'hingga', 'ia', 'ialah', 'ibarat', 'ibaratkan', 'ibaratnya', 'ibu', 'ikut', 'ingat', 'ingat-ingat', 'ingin', 'inginkah', 'inginkan', 'ini', 'inikah', 'inilah', 'itu', 'itukah', 'itulah', 'jadi', 'jadilah', 'jadinya', 'jangan', 'jangankan', 'janganlah', 'jauh', 'jawab', 'jawaban', 'jawabnya', 'jelas', 'jelaskan', 'jelaslah', 'jelasnya', 'jika', 'jikalau', 'juga', 'jumlah', 'jumlahnya', 'justru', 'kala', 'kalau', 'kalaulah', 'kalaupun', 'kalian', 'kami', 'kamilah', 'kamu', 'kamulah', 'kan', 'kapan', 'kapankah', 'kapanpun', 'karena', 'karenanya', 'kasus', 'kata', 'katakan', 'katakanlah', 'katanya', 'ke', 'keadaan', 'kebetulan', 'kecil', 'kedua', 'keduanya', 'keinginan', 'kelamaan', 'kelihatan', 'kelihatannya', 'kelima', 'keluar', 'kembali', 'kemudian', 'kemungkinan', 'kemungkinannya', 'kenapa', 'kepada', 'kepadanya', 'kesamaannya', 'keseluruhan', 'keseluruhannya', 'keterlaluan', 'ketika', 'khususnya', 'kini', 'kinilah', 'kira', 'kira-kira', 'kiranya', 'kita', 'kitalah', 'kok', 'kurang', 'lagi', 'lagian', 'lah', 'lain', 'lainnya', 'lalu', 'lama', 'lamanya', 'lanjut', 'lanjutnya', 'lebih', 'lewat', 'lima', 'luar', 'macam', 'maka', 'makanya', 'makin', 'malah', 'malahan', 'mampu', 'mampukah', 'mana', 'manakala', 'manalagi', 'masa', 'masalah', 'masalahnya', 'masih', 'masihkah', 'masing', 'masing-masing', 'mau', 'maupun', 'melainkan', 'melakukan', 'melalui', 'melihat', 'melihatnya', 'memang', 'memastikan', 'memberi', 'memberikan', 'membuat', 'memerlukan', 'memihak', 'meminta', 'memintakan', 'memisalkan', 'memperbuat', 'mempergunakan', 'memperkirakan', 'memperlihatkan', 'mempersiapkan', 'mempersoalkan', 'mempertanyakan', 'mempunyai', 'memulai', 'memungkinkan', 'menaiki', 'menambahkan', 'menandaskan', 'menanti', 'menanti-nanti', 'menantikan', 'menanya', 'menanyai', 'menanyakan', 'mendapat', 'mendapatkan', 'mendatang', 'mendatangi', 'mendatangkan', 'menegaskan', 'mengakhiri', 'mengapa', 'mengatakan', 'mengatakannya', 'mengenai', 'mengerjakan', 'mengetahui', 'menggunakan', 'menghendaki', 'mengibaratkan', 'mengibaratkannya', 'mengingat', 'mengingatkan', 'menginginkan', 'mengira', 'mengucapkan', 'mengucapkannya', 'mengungkapkan', 'menjadi', 'menjawab', 'menjelaskan', 'menuju', 'menunjuk', 'menunjuki', 'menunjukkan', 'menunjuknya', 'menurut', 'menuturkan', 'menyampaikan', 'menyangkut', 'menyatakan', 'menyebutkan', 'menyeluruh', 'menyiapkan', 'merasa', 'mereka', 'merekalah', 'merupakan', 'meski', 'meskipun', 'meyakini', 'meyakinkan', 'minta', 'mirip', 'misal', 'misalkan', 'misalnya', 'mula', 'mulai', 'mulailah', 'mulanya', 'mungkin', 'mungkinkah', 'nah', 'naik', 'namun', 'nanti', 'nantinya', 'nyaris', 'nyatanya', 'oleh', 'olehnya', 'pada', 'padahal', 'padanya', 'pak', 'paling', 'panjang', 'pantas', 'para', 'pasti', 'pastilah', 'penting', 'pentingnya', 'per', 'percuma', 'perlu', 'perlukah', 'perlunya', 'pernah', 'persoalan', 'pertama', 'pertama-tama', 'pertanyaan', 'pertanyakan', 'pihak', 'pihaknya', 'pukul', 'pula', 'pun', 'punya', 'rasa', 'rasanya', 'rata', 'rupanya', 'saat', 'saatnya', 'saja', 'sajalah', 'saling', 'sama', 'sama-sama', 'sambil', 'sampai', 'sampai-sampai', 'sampaikan', 'sana', 'sangat', 'sangatlah', 'satu', 'saya', 'sayalah', 'se', 'sebab', 'sebabnya', 'sebagai', 'sebagaimana', 'sebagainya', 'sebagian', 'sebaik', 'sebaik-baiknya', 'sebaiknya', 'sebaliknya', 'sebanyak', 'sebegini', 'sebegitu', 'sebelum', 'sebelumnya', 'sebenarnya', 'seberapa', 'sebesar', 'sebetulnya', 'sebisanya', 'sebuah', 'sebut', 'sebutlah', 'sebutnya', 'secara', 'secukupnya', 'sedang', 'sedangkan', 'sedemikian', 'sedikit', 'sedikitnya', 'seenaknya', 'segala', 'segalanya', 'segera', 'seharusnya', 'sehingga', 'seingat', 'sejak', 'sejauh', 'sejenak', 'sejumlah', 'sekadar', 'sekadarnya', 'sekali', 'sekali-kali', 'sekalian', 'sekaligus', 'sekalipun', 'sekarang', 'sekarang', 'sekecil', 'seketika', 'sekiranya', 'sekitar', 'sekitarnya', 'sekurang-kurangnya', 'sekurangnya', 'sela', 'selain', 'selaku', 'selalu', 'selama', 'selama-lamanya', 'selamanya', 'selanjutnya', 'seluruh', 'seluruhnya', 'semacam', 'semakin', 'semampu', 'semampunya', 'semasa', 'semasih', 'semata', 'semata-mata', 'semaunya', 'sementara', 'semisal', 'semisalnya', 'sempat', 'semua', 'semuanya', 'semula', 'sendiri', 'sendirian', 'sendirinya', 'seolah', 'seolah-olah', 'seorang', 'sepanjang', 'sepantasnya', 'sepantasnyalah', 'seperlunya', 'seperti', 'sepertinya', 'sepihak', 'sering', 'seringnya', 'serta', 'serupa', 'sesaat', 'sesama', 'sesampai', 'sesegera', 'sesekali', 'seseorang', 'sesuatu', 'sesuatunya', 'sesudah', 'sesudahnya', 'setelah', 'setempat', 'setengah', 'seterusnya', 'setiap', 'setiba', 'setibanya', 'setidak-tidaknya', 'setidaknya', 'setinggi', 'seusai', 'sewaktu', 'siap', 'siapa', 'siapakah', 'siapapun', 'sini', 'sinilah', 'soal', 'soalnya', 'suatu', 'sudah', 'sudahkah', 'sudahlah', 'supaya', 'tadi', 'tadinya', 'tahu', 'tahun', 'tak', 'tambah', 'tambahnya', 'tampak', 'tampaknya', 'tandas', 'tandasnya', 'tanpa', 'tanya', 'tanyakan', 'tanyanya', 'tapi', 'tegas', 'tegasnya', 'telah', 'tempat', 'tengah', 'tentang', 'tentu', 'tentulah', 'tentunya', 'tepat', 'terakhir', 'terasa', 'terbanyak', 'terdahulu', 'terdapat', 'terdiri', 'terhadap', 'terhadapnya', 'teringat', 'teringat-ingat', 'terjadi', 'terjadilah', 'terjadinya', 'terkira', 'terlalu', 'terlebih', 'terlihat', 'termasuk', 'ternyata', 'tersampaikan', 'tersebut', 'tersebutlah', 'tertentu', 'tertuju', 'terus', 'terutama', 'tetap', 'tetapi', 'tiap', 'tiba', 'tiba-tiba', 'tidak', 'tidakkah', 'tidaklah', 'tiga', 'tinggi', 'toh', 'tunjuk', 'turut', 'tutur', 'tuturnya', 'ucap', 'ucapnya', 'ujar', 'ujarnya', 'umum', 'umumnya', 'ungkap', 'ungkapnya', 'untuk', 'usah', 'usai', 'waduh', 'wah', 'wahai', 'waktu', 'waktunya', 'walau', 'walaupun', 'wong', 'yaitu', 'yakin', 'yakni', 'yang', 'yg' ] # Tambahkan stopwords khusus untuk dataset (dari analisis awal) additional_stopwords = ['ya', 'nya', 'yg', 'aja', 'gw', 'ga', 'udah', 'kek', 'gak', 'nya', 'nih', 'sih', 'kalo', 'eh', 'aku', 'kau', 'lo', 'lu', 'kan', 'kok', 'juga', 'udh', 'eh', 'ah', 'kk', 'wkwk', 'wkwkwk', 'haha', 'hahaha', 'bang', 'banget', 'emang'] stopwords.extend(additional_stopwords) return set(stopwords) # 5. Stemming def get_stemmer(): """ Mendapatkan stemmer bahasa Indonesia dari Sastrawi """ factory = StemmerFactory() return factory.create_stemmer() # 6. Preprocessing langkah-langkah def preprocess_data(df, text_column): """ Preprocessing data teks """ # Preprocessing teks df['clean_text'] = df[text_column].apply(preprocess_text) # Tokenisasi df['tokens'] = df['clean_text'].apply(word_tokenize) # Hapus stopwords stopwords = get_stopwords() df['tokens_without_stopwords'] = df['tokens'].apply( lambda tokens: [word for word in tokens if word not in stopwords and len(word) > 2] ) # Stemming stemmer = get_stemmer() df['stemmed_tokens'] = df['tokens_without_stopwords'].apply( lambda tokens: [stemmer.stem(word) for word in tokens] ) return df # 7. Membuat korpus untuk LDA def create_lda_corpus(df, tokens_column='stemmed_tokens'): """ Membuat korpus untuk LDA: - Dictionary - Bag of Words corpus """ # Buat dictionary id2word = corpora.Dictionary(df[tokens_column]) # Buat corpus corpus = [id2word.doc2bow(text) for text in df[tokens_column]] return corpus, id2word # 8. Membuat model LDA def create_lda_model(corpus, id2word, num_topics=5, passes=10): """ Membuat model LDA """ lda_model = gensim.models.ldamodel.LdaModel( corpus=corpus, id2word=id2word, num_topics=num_topics, random_state=42, passes=passes, alpha='auto', eta='auto' ) return lda_model # 9. Mengevaluasi model dengan coherence score def compute_coherence_score(model, corpus, texts, dictionary): """ Menghitung coherence score """ coherence_model = CoherenceModel( model=model, texts=texts, dictionary=dictionary, coherence='c_v' ) return coherence_model.get_coherence() # 10. Mencari jumlah topik optimal def find_optimal_topics(corpus, id2word, texts, start=2, limit=10, step=1): """ Mencari jumlah topik optimal berdasarkan coherence score """ coherence_values = [] model_list = [] for num_topics in range(start, limit, step): model = create_lda_model(corpus=corpus, id2word=id2word, num_topics=num_topics) model_list.append(model) coherence_model = CoherenceModel( model=model, texts=texts, dictionary=id2word, coherence='c_v' ) coherence_values.append(coherence_model.get_coherence()) # Plot coherence score plt.figure(figsize=(12, 6)) plt.plot(range(start, limit, step), coherence_values) plt.xlabel("Jumlah Topik") plt.ylabel("Coherence Score") plt.title("Coherence Score untuk Berbagai Jumlah Topik") plt.grid(True) plt.tight_layout() plt.savefig('coherence_score.png') # Temukan indeks dengan coherence score tertinggi max_index = coherence_values.index(max(coherence_values)) optimal_topics = range(start, limit, step)[max_index] return model_list[max_index], optimal_topics, coherence_values, 'coherence_score.png' # 11. Visualisasi model LDA def visualize_lda(lda_model, corpus, id2word): """ Visualisasi model LDA dengan pyLDAvis """ vis = pyLDAvis.gensim_models.prepare(lda_model, corpus, id2word) pyLDAvis.save_html(vis, 'lda_visualization.html') return 'lda_visualization.html' # 12. Format hasil model def format_topics_sentences(ldamodel, corpus, texts): """ Format hasil topic modeling """ # Init output - buat list untuk menampung data topics_data = [] # Get main topic in each document for i, row in enumerate(ldamodel[corpus]): row = sorted(row, key=lambda x: (x[1]), reverse=True) # Get the Dominant topic, Perc Contribution and Keywords for each document for j, (topic_num, prop_topic) in enumerate(row): if j == 0: # => dominant topic wp = ldamodel.show_topic(topic_num) topic_keywords = ", ".join([word for word, prop in wp]) # Simpan data dalam list topics_data.append((int(topic_num), round(prop_topic, 4), topic_keywords)) else: break # Buat DataFrame sekaligus dari list data sent_topics_df = pd.DataFrame(topics_data, columns=['Dominant_Topic', 'Perc_Contribution', 'Topic_Keywords']) # Tambahkan teks asli contents = pd.Series(texts) sent_topics_df = pd.concat([sent_topics_df, contents], axis=1) return sent_topics_df # 13. Fungsi untuk menyimpan dan memuat hasil processing def save_results(results, output_dir='output'): """ Menyimpan semua hasil processing ke dalam file CSV dan model """ import os # Buat direktori output jika belum ada if not os.path.exists(output_dir): os.makedirs(output_dir) # Simpan model LDA, dictionary, dan corpus results['model'].save(os.path.join(output_dir, 'lda_model')) results['id2word'].save(os.path.join(output_dir, 'id2word.dictionary')) corpora.MmCorpus.serialize(os.path.join(output_dir, 'corpus.mm'), results['corpus']) # Simpan dataframe hasil ke CSV results['df_topic_keywords'].to_csv(os.path.join(output_dir, 'topic_keywords.csv'), index=False) # Simpan informasi coherence score coherence_df = pd.DataFrame({ 'num_topics': list(range(2, 2 + len(results['coherence_values']))), 'coherence_score': results['coherence_values'] }) coherence_df.to_csv(os.path.join(output_dir, 'coherence_scores.csv'), index=False) # Simpan dataframe preprocessing jika tersedia if 'df_processed' in results: results['df_processed'].to_csv(os.path.join(output_dir, 'preprocessed_data.csv'), index=False) print(f"Semua hasil telah disimpan di direktori: {output_dir}") return output_dir def load_results(output_dir='output'): """ Memuat hasil yang telah disimpan sebelumnya """ import os results = {} # Muat model LDA, dictionary, dan corpus if os.path.exists(os.path.join(output_dir, 'lda_model')): results['model'] = gensim.models.ldamodel.LdaModel.load(os.path.join(output_dir, 'lda_model')) if os.path.exists(os.path.join(output_dir, 'id2word.dictionary')): results['id2word'] = corpora.Dictionary.load(os.path.join(output_dir, 'id2word.dictionary')) if os.path.exists(os.path.join(output_dir, 'corpus.mm')): results['corpus'] = corpora.MmCorpus(os.path.join(output_dir, 'corpus.mm')) # Muat dataframe hasil if os.path.exists(os.path.join(output_dir, 'topic_keywords.csv')): results['df_topic_keywords'] = pd.read_csv(os.path.join(output_dir, 'topic_keywords.csv')) # Muat informasi coherence score if os.path.exists(os.path.join(output_dir, 'coherence_scores.csv')): coherence_df = pd.read_csv(os.path.join(output_dir, 'coherence_scores.csv')) results['coherence_values'] = coherence_df['coherence_score'].tolist() results['optimal_topics'] = coherence_df.loc[coherence_df['coherence_score'].idxmax(), 'num_topics'] # Muat dataframe preprocessing if os.path.exists(os.path.join(output_dir, 'preprocessed_data.csv')): results['df_processed'] = pd.read_csv(os.path.join(output_dir, 'preprocessed_data.csv')) # Rekonstruksi kolom list dari string if 'tokens' in results['df_processed'].columns: results['df_processed']['tokens'] = results['df_processed']['tokens'].apply( lambda x: eval(x) if isinstance(x, str) else [] ) if 'tokens_without_stopwords' in results['df_processed'].columns: results['df_processed']['tokens_without_stopwords'] = results['df_processed']['tokens_without_stopwords'].apply( lambda x: eval(x) if isinstance(x, str) else [] ) if 'stemmed_tokens' in results['df_processed'].columns: results['df_processed']['stemmed_tokens'] = results['df_processed']['stemmed_tokens'].apply( lambda x: eval(x) if isinstance(x, str) else [] ) print(f"Hasil berhasil dimuat dari direktori: {output_dir}") return results def run_topic_modeling(file_path, text_column='text', save_intermediates=True, output_dir='output'): """ Menjalankan topic modeling """ print("Loading data...") df = load_data(file_path) print("Preprocessing data...") df_processed = preprocess_data(df, text_column) # Simpan hasil preprocessing jika diminta if save_intermediates: import os if not os.path.exists(output_dir): os.makedirs(output_dir) # Konversi kolom list menjadi string untuk disimpan ke CSV df_to_save = df_processed.copy() for col in ['tokens', 'tokens_without_stopwords', 'stemmed_tokens']: if col in df_to_save.columns: df_to_save[col] = df_to_save[col].apply(str) df_to_save.to_csv(os.path.join(output_dir, 'preprocessed_data.csv'), index=False) print(f"Data preprocessing disimpan di {os.path.join(output_dir, 'preprocessed_data.csv')}") print("Creating corpus...") corpus, id2word = create_lda_corpus(df_processed) # Simpan corpus dan dictionary jika diminta if save_intermediates: import os if not os.path.exists(output_dir): os.makedirs(output_dir) id2word.save(os.path.join(output_dir, 'id2word.dictionary')) corpora.MmCorpus.serialize(os.path.join(output_dir, 'corpus.mm'), corpus) print(f"Corpus dan dictionary disimpan di direktori {output_dir}") print("Finding optimal number of topics...") best_model, optimal_topics, coherence_values, coherence_plot = find_optimal_topics( corpus=corpus, id2word=id2word, texts=df_processed['stemmed_tokens'] ) print(f"Optimal number of topics: {optimal_topics}") print(f"Best coherence score: {max(coherence_values)}") # Simpan model jika diminta if save_intermediates: import os if not os.path.exists(output_dir): os.makedirs(output_dir) best_model.save(os.path.join(output_dir, 'lda_model')) # Simpan coherence scores coherence_df = pd.DataFrame({ 'num_topics': list(range(2, 2 + len(coherence_values))), 'coherence_score': coherence_values }) coherence_df.to_csv(os.path.join(output_dir, 'coherence_scores.csv'), index=False) print(f"Model LDA dan coherence scores disimpan di direktori {output_dir}") print("Visualizing LDA model...") vis_path = visualize_lda(best_model, corpus, id2word) print("Topics and their keywords:") topics = best_model.print_topics() pprint(topics) # Simpan topik dan kata kunci ke CSV if save_intermediates: import os if not os.path.exists(output_dir): os.makedirs(output_dir) topics_df = pd.DataFrame({ 'topic_id': [i for i, _ in topics], 'keywords': [keywords for _, keywords in topics] }) topics_df.to_csv(os.path.join(output_dir, 'topics_keywords.csv'), index=False) print(f"Topik dan kata kunci disimpan di {os.path.join(output_dir, 'topics_keywords.csv')}") # Format hasil df_topic_sents_keywords = format_topics_sentences( ldamodel=best_model, corpus=corpus, texts=df_processed['clean_text'] ) # Dominant topic distribution df_dominant_topic = df_topic_sents_keywords.reset_index() df_dominant_topic.columns = ['Document_No', 'Dominant_Topic', 'Topic_Perc_Contrib', 'Keywords', 'Text'] # Simpan hasil pemetaan dokumen ke topik if save_intermediates: df_dominant_topic.to_csv(os.path.join(output_dir, 'document_topics.csv'), index=False) print(f"Pemetaan dokumen ke topik disimpan di {os.path.join(output_dir, 'document_topics.csv')}") print("\nDominant Topic Distribution:") topic_counts = df_dominant_topic['Dominant_Topic'].value_counts().reset_index() topic_counts.columns = ['Topic_Num', 'Count'] print(topic_counts) # Simpan distribusi topik if save_intermediates: topic_counts.to_csv(os.path.join(output_dir, 'topic_distribution.csv'), index=False) print(f"Distribusi topik disimpan di {os.path.join(output_dir, 'topic_distribution.csv')}") # Plot distribusi topik plt.figure(figsize=(10, 6)) plt.bar(topic_counts['Topic_Num'], topic_counts['Count']) plt.xlabel('Topic Number') plt.ylabel('Count') plt.title('Distribution of Dominant Topics') plt.xticks(topic_counts['Topic_Num']) plt.grid(True, alpha=0.3) plt.tight_layout() plt.savefig(os.path.join(output_dir, 'topic_distribution.png')) results = { 'model': best_model, 'corpus': corpus, 'id2word': id2word, 'optimal_topics': optimal_topics, 'coherence_values': coherence_values, 'coherence_plot': coherence_plot, 'visualization': vis_path, 'topic_distribution': os.path.join(output_dir, 'topic_distribution.png'), 'df_topic_keywords': df_dominant_topic, 'df_processed': df_processed } print(f"\nSemua hasil telah disimpan di direktori: {output_dir}") return results if __name__ == "__main__": # Ganti dengan path file CSV yang sesuai results = run_topic_modeling("./src/review.csv", output_dir='./src/lda_output') print("Topic modeling completed successfully!") # Contoh cara memuat kembali hasil yang sudah disimpan # loaded_results = load_results('lda_output') # print(f"Loaded model with {loaded_results['optimal_topics']} topics")