本文約2700字,建議閱讀5分鐘
本文為大家介紹了主題建模的概念、LDA算法的原理,示例了如何使用Python建立一個基礎的LDA主題模型,並使用pyLDAvis對主題進行可視化。
引言主題建模包括從文檔術語中提取特徵,並使用數學結構和框架(如矩陣分解和奇異值分解)來生成彼此可區分的術語聚類(cluster)或組,這些單詞聚類繼而形成主題或概念。主題建模是一種對文檔進行無監督分類的方法,類似於對數值數據進行聚類。這些概念可以用來解釋語料庫的主題,也可以在各種文檔中一同頻繁出現的單詞之間建立語義聯繫。發現數據集中隱藏的主題;
將文檔分類到已經發現的主題中;
使用分類來組織/總結/搜索文檔。
潛在語義索引(Latent semantic indexing)
潛在狄利克雷分配(Latent Dirichlet Allocation,LDA)
非負矩陣分解(Non-negative matrix factorization,NMF)
在本文中,我們將重點討論如何使用Python進行LDA主題建模。具體來說,我們將討論:什麼是潛在狄利克雷分配(LDA, Latent Dirichlet allocation)?潛在狄利克雷分配(LDA, Latent Dirichlet allocation)是一種生成概率模型(generative probabilistic model),該模型假設每個文檔具有類似於概率潛在語義索引模型的主題的組合。簡而言之,LDA背後的思想是,每個文檔可以通過主題的分布來描述,每個主題可以通過單詞的分布來描述。LDA算法如何工作?注意:LDA不關心文檔中單詞的順序。通常,LDA使用詞袋特徵(bag-of-word feature)表示來代表文檔。1. 對於每個文檔,隨機將每個單詞初始化為K個主題中的一個(事先選擇K個主題);3. 考慮所有其他單詞及其主題分配,以概率P(T | D)´ P(W | T) 將單詞W與主題T重新分配。LDA主題模型的圖示如下。
下圖直觀地展示了每個參數如何連接回文本文檔和術語。假設我們有M個文檔,文檔中有N個單詞,我們要生成的主題總數為K。圖中的黑盒代表核心算法,它利用前面提到的參數從文檔中提取K個主題。如何使用Python建立LDA主題模型我們將使用Gensim包中的潛在狄利克雷分配(LDA)。首先,我們需要導入包。核心包是re、gensim、spacy和pyLDAvis。此外,我們需要使用matplotlib、numpy和panases以進行數據處理和可視化。1. import re2. import numpy as np3. import pandas as pd4. from pprint import pprint5. 6. # Gensim7. import gensim8. import gensim.corpora as corpora9. from gensim.utils import simple_preprocess10. from gensim.models import CoherenceModel11. 12. # spacy for lemmatization13. import spacy14. 15. # Plotting tools16. import pyLDAvis17. import pyLDAvis.gensim # don't skip this18. import matplotlib.pyplot as plt19. %matplotlib inline20. 21. # Enable logging for gensim - optional22. import logging23. logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.ERROR)24. 25. import warnings26. warnings.filterwarnings("ignore",category=DeprecationWarning)像am/is/are/of/a/the/but/…這樣的詞不包含任何關於「主題」的信息。因此,作為預處理步驟,我們可以將它們從文檔中移除。要做到這一點,我們需要從NLT導入停用詞。還可以通過添加一些額外的單詞來擴展原始的停用詞列表。1. # NLTK Stop words2. from nltk.corpus import stopwords3. stop_words = stopwords.words('english')4. stop_words.extend(['from', 'subject', 're', 'edu', 'use'])在本教程中,我們將使用20個新聞組數據集,其中包含來自20個不同主題的大約11k個新聞組帖子。這可以作為newsgroups.json獲得。1. # Import Dataset2. df = pd.read_json('https://raw.githubusercontent.com/selva86/datasets/master/newsgroups.json')3. print(df.target_names.unique())4. df.head()在我們開始主題建模之前,需要清理數據集。首先,刪除電子郵件連結、多餘的空格和換行符。1. # Convert to list2. data = df.content.values.tolist()3. 4. # Remove Emails5. data = [re.sub('\S*@\S*\s?', '', sent) for sent in data]6. 7. # Remove new line characters8. data = [re.sub('\s+', ' ', sent) for sent in data]9. 10. # Remove distracting single quotes11. data = [re.sub("\'", "", sent) for sent in data]12. 13. pprint(data[:1])讓我們把每個句子標記成一個單詞列表,去掉標點符號和不必要的字符。1. def sent_to_words(sentences):2. for sentence in sentences:3. yield(gensim.utils.simple_preprocess(str(sentence), deacc=True)) # deacc=True removes punctuations4. 5. data_words = list(sent_to_words(data))6. 7. print(data_words[:1])創建二元(Bigram)模型和三元(Trigram)模型1. # Build the bigram and trigram models2. bigram = gensim.models.Phrases(data_words, min_count=5, threshold=100) # higher threshold fewer phrases.3. trigram = gensim.models.Phrases(bigram[data_words], threshold=100) 4. 5. # Faster way to get a sentence clubbed as a trigram/bigram6. bigram_mod = gensim.models.phrases.Phraser(bigram)7. trigram_mod = gensim.models.phrases.Phraser(trigram)8. 9. # See trigram example10. print(trigram_mod[bigram_mod[data_words[0]]])刪除停用詞(stopword),建立二元模型和詞形還原(Lemmatize)在這一步中,我們分別定義了函數以刪除停止詞、建立二元模型和詞形還原,並且依次調用了這些函數。
1. # Define functions for stopwords, bigrams, trigrams and lemmatization2. def remove_stopwords(texts):3. return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts]4. 5. def make_bigrams(texts):6. return [bigram_mod[doc] for doc in texts]7. 8. def make_trigrams(texts):9. return [trigram_mod[bigram_mod[doc]] for doc in texts]10. 11. def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']):12. """https://spacy.io/api/annotation"""13. texts_out = []14. for sent in texts:15. doc = nlp(" ".join(sent)) 16. texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags])17. return texts_out
1. # Remove Stop Words2. data_words_nostops = remove_stopwords(data_words)3. 4. # Form Bigrams5. data_words_bigrams = make_bigrams(data_words_nostops)6. 7. # Initialize spacy 'en' model, keeping only tagger component (for efficiency)8. # python3 -m spacy download en9. nlp = spacy.load('en', disable=['parser', 'ner'])10. 11. # Do lemmatization keeping only noun, adj, vb, adv12. data_lemmatized = lemmatization(data_words_bigrams, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV'])13. 14. print(data_lemmatized[:1])Gensim為文檔中的每個單詞創建一個唯一的id,但是在此之前,我們需要創建一個字典和語料庫作為模型的輸入。1. # Create Dictionary2. id2word = corpora.Dictionary(data_lemmatized)3. 4. # Create Corpus5. texts = data_lemmatized6. 7. # Term Document Frequency8. corpus = [id2word.doc2bow(text) for text in texts]9. 10. # View11. print(corpus[:1])現在我們準備進入核心步驟,使用LDA進行主題建模。讓我們開始建立模型。我們將建立20個不同主題的LDA模型,其中每個主題都是關鍵字的組合,每個關鍵字在主題中都具有一定的權重(weightage)。1. # Build LDA model2. lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,3. id2word=id2word,4. num_topics=20, 5. random_state=100,6. update_every=1,7. chunksize=100,8. passes=10,9. alpha='auto',10. per_word_topics=True)我們可以可視化每個主題的關鍵詞和每個關鍵詞的權重(重要性)。1. # Print the Keyword in the 10 topics2. pprint(lda_model.print_topics())3. doc_lda = lda_model[corpus]計算模型困惑度(Perplexity)和一致性分數(Coherence Score)模型困惑度是對概率分布或概率模型預測樣本好壞的一種度量。主題一致性通過測量主題中得分高的單詞之間的語義相似度來衡量單個主題的得分。簡而言之,它們提供了一種方便的方法來判斷一個給定的主題模型有多好。1. # Compute Perplexity2. print('\nPerplexity: ', lda_model.log_perplexity(corpus)) # a measure of how good the model is. lower the better.3. 4. # Compute Coherence Score5. coherence_model_lda = CoherenceModel(model=lda_model, texts=data_lemmatized, dictionary=id2word, coherence='c_v')6. coherence_lda = coherence_model_lda.get_coherence()7. print('\nCoherence Score: ', coherence_lda)現在,我們可以檢查生成的主題和相關的關鍵詞。最好的方法是使用pyLDAvis可視化我們的模型。pyLDAvis旨在幫助用戶在一個適合文本數據語料庫的主題模型中解釋主題。它從擬合好的的線性判別分析主題模型(LDA)中提取信息,以實現基於網絡的交互式可視化。1. # Visualize the topics2. pyLDAvis.enable_notebook()3. vis = pyLDAvis.gensim.prepare(lda_model, corpus, id2word)4. vis簡要地解釋一下結果:左手邊的每個氣泡代表一個話題。氣泡越大,該主題就越盛行。根據經驗,一個好的主題模型會有大的、不重疊的氣泡。我們也可以點擊右邊的側邊工具條,以調整阿爾法(alpha)參數。結語主題建模是自然語言處理的主要應用之一。本文的目的是解釋什麼是主題建模,以及如何在實際使用中實現潛在狄利克雷分配(LDA)模型。
為此,我們深入研究了LDA的原理,使用Gensim包中的LDA構建了一個基礎的主題模型,並使用pyLDAvis對主題進行了可視化。希望您喜歡該文並有所收穫。
References:Jelodar, H., Wang, Y., Yuan, C. et al. Latent Dirichlet allocation (LDA) and topic modeling: models, applications, a survey. Multimed Tools Appl 78, 15169–15211 (2019). https://doi.org/10.1007/s11042-018-6894-4https://jovian.ai/outlink?url=https%3A%2F%2Fdoi.org%2F10.1007%2Fs11042-018-6894-4D. Sarkar, Text Analytics with Python. A Practical Real-World Approach to Gaining Actionable Insights from Your Datahttps://www.machinelearningplus.com/nlp/topic-modeling-gensim-python/https://jovian.ai/outlink?url=https%3A%2F%2Fwww.machinelearningplus.com%2Fnlp%2Ftopic-modeling-gensim-python%2Fhttps://towardsdatascience.com/topic-modelling-in-python-with-nltk-and-gensim-4ef03213cd21https://jovian.ai/outlink?url=https%3A%2F%2Ftowardsdatascience.com%2Ftopic-modelling-in-python-with-nltk-and-gensim-4ef03213cd21https://towardsdatascience.com/end-to-end-topic-modeling-in-python-latent-dirichlet-allocation-lda-35ce4ed6b3e0https://jovian.ai/outlink?url=https%3A%2F%2Ftowardsdatascience.com%2Fend-to-end-topic-modeling-in-python-latent-dirichlet-allocation-lda-35ce4ed6b3e0https://towardsdatascience.com/latent-dirichlet-allocation-lda-9d1cd064ffa2https://towardsdatascience.com/light-on-math-machine-learning-intuitive-guide-to-latent-dirichlet-allocation-437c81220158http://blog.echen.me/2011/08/22/introduction-to-latent-dirichlet-allocation/譯者簡介:劉思婧,清華大學新聞系研一在讀,數據傳播方向。文理兼愛,有點小情懷的數據愛好者。希望結識更多不同專業、不同專長的夥伴,拓寬眼界、優化思維、日日自新。版權聲明:本號內容部分來自網際網路,轉載請註明原文連結和作者,如有侵權或出處有誤請和我們聯繫。
合作請加QQ:365242293
數據分析(ID : ecshujufenxi )網際網路科技與數據圈自己的微信,也是WeMedia自媒體聯盟成員之一,WeMedia聯盟覆蓋5000萬人群。