介紹
你有沒有去過那種運營良好的圖書館?我總是對圖書館館員透過書名、內容或其他主題保持一切井井有條的方式印象深刻。但是如果你給他們數千本書,要求他們根據書的種類整理出來,他們很難在一天內完成這項任務,更不用說一小時!
但是,如果這些書以電子的形式出現,就難不倒你了,對吧?所有的整理會在幾秒之間完成,並且不需要任何人工勞動。自然語言處理(NLP)萬歲!
看看下面這段話:
你可以從高亮的詞語中總結出,這段話有三個主題(或概念)——主題1、主題2和主題3。一個良好的主題模型可以識別出相似的詞語並將它們放在一組或一個主題下。上述示例中最主要的主題是主題2,表明這段文字主要關於虛假影片。
是不是很好奇?太好了!在本文中,我們將學習一種叫做主題建模的文字挖掘方法。這是一種非常有用的提取主題的技術,在面對NLP挑戰時你會經常使用到它。
注意:我強烈建議您通讀這篇文章瞭解SVD和UMAP等定義。它們在本文中經常出現,因此對它們有基本的理解有助於鞏固這些概念。
目錄
1. 什麼是主題模型?
2. 何時使用主題建模?
3. 潛在語義分析(LSA)概述
4. 在Python中實現LSA
資料讀取和檢查
資料預處理
文件-詞項矩陣(Document-Term Matrix)
主題建模
主題視覺化
5. LSA的優缺點
6. 其他主題建模技術
什麼是主題模型?
主題模型可定義為一種在大量文件中發現其主題的無監督技術。這些主題本質上十分抽象,即彼此相關聯的詞語構成一個主題。同樣,在單個文件中可以有多個主題。我們暫時將主題模型理解為一個如下圖所示的黑盒子:
這個黑盒子(主題模型)將相似和相關的詞語聚整合簇,稱為主題。這些主題在文件中具有特定的分佈,每個主題都根據它包含的不同單詞的比例來定義。
何時使用主題建模?
回想一下剛才提到的將相似的書籍整理到一起的例子。現在假設你要對一些電子文件執行類似的任務。只要文件的數量不太多,你就可以手動完成。但是如果這些文件的數量非常多呢?
這就是NLP技術脫穎而出的地方。對於這個任務而言,主題建模非常適用。
主題建模有助於挖掘海量文字資料,查詢詞簇,文字之間的相似度以及發現抽象主題。如果這些理由還不夠引人注目,主題建模也可用於搜尋引擎,判斷搜尋欄位與結果的匹配程度。越來越有趣了,是不是?那麼,請繼續閱讀!
潛在語義分析(LSA)概述
所有語言都有自己的錯綜複雜和細微差別,比如一義多詞和一詞多義,這對機器而言很難捕捉(有時它們甚至也被人類誤解了!)。
例如,如下兩個句子:
1. I liked his last novel quite a lot.
2. We would like to go for a novel marketing campaign.
在第一個句子中,'novel' 指一本書,而在第二個句子中,它的含義是新奇的、新穎的。
我們能夠輕鬆地區分這些單詞,是因為我們可以理解這些詞背後的語境。但是,機器並不能捕捉到這個概念,因為它不能理解單詞的上下文。這就是潛在語義分析(LSA)發揮作用的地方,它可以利用單詞所在的上下文來捕捉隱藏的概念,即主題。
因此,簡單地將單詞對映到文件並沒有什麼用。我們真正需要的是弄清楚單詞背後的隱藏概念或主題。LSA是一種可以發現這些隱藏主題的技術。現在我們來深入探討下LSA的內部工作機制。
LSA的實施步驟
假設我們有m篇文件,其中包含n個唯一詞項(單詞)。我們希望從所有文件的文字資料中提取出k個主題。主題數k,必須由使用者給定。
生成一個m×n維的文件-詞項矩陣(Document-Term Matrix),矩陣元素為TF-IDF分數
然後,我們使用奇異值分解(SVD)把上述矩陣的維度降到k(預期的主題數)維
SVD將一個矩陣分解為三個矩陣。假設我們利用SVD分解矩陣A,我們會得到矩陣U,矩陣S和矩陣VT(矩陣V的轉置)
矩陣Uk(document-term matrix)的每個行向量代表相應的文件。這些向量的長度是k,是預期的主題數。代表資料中詞項的向量可以在矩陣Vk(term-topic matrix)中找到。
因此,SVD為資料中的每篇文件和每個詞項都提供了向量。每個向量的長度均為k。我們可以使用餘弦相似度的方法透過這些向量找到相似的單詞和文件。
在Python中實現LSA
是時候啟動Python並瞭解如何在主題建模問題中應用LSA了。開啟Python環境後,請按照如下步驟操作。
資料讀取和檢查
在開始之前,先載入需要的庫。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
pd.set_option("display.max_colwidth", 200)
在本文中,我們使用sklearn中的"20 Newsgroup"資料集,可從這裡下載,然後按照程式碼繼續操作。
from sklearn.datasets import fetch_20newsgroups
dataset = fetch_20newsgroups(shuffle=True, random_state=1, remove=('header','footers',quotes'))
documents = dataset.data
len(documents)
Output: 11,314
Dataset.target_names
['alt.atheism',
'comp.graphics',
'comp.os.ms-windows.misc',
'comp.sys.ibm.pc.hardware',
'comp.sys.mac.hardware',
'misc.forsale',
'rec.autos',
'rec.motorcycles',
'rec.sport.baseball',
'rec.sport.hockey',
'sci.crypt',
'sci.electronics',
'sci.med',
'sci.space',
'soc.religion.christian',
'talk.politics.guns',
'talk.politics.mideast',
'talk.politics.misc',
'talk.religion.misc']
該資料集包含分佈在20個不同新聞組中的11314篇文件。
資料預處理
首先,我們嘗試儘可能地清理文字資料。我們的想法是,使用正規表示式replace("[^a-zA-Z#]", " ")一次性刪除所有標點符號、數字和特殊字元,這個正規表示式可以替換除帶空格的字母之外的所有內容。然後刪除較短的單詞,因為它們通常並不包含有用的資訊。最後,將全部文字變為小寫,使得大小寫敏感失效。
news_df = pd.DataFrame({'document':documents})
# removing everything except alphabets
news_df['clean_doc'] = news_df['document'].str.replace("[^a-zA-Z#]", " ")
# removing short words
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: ' '.join([w for w in x.split() if len(w)>3]))
# make all the lowercase
news_df['clean_doc'] = news_df['clean_doc'].apply(lambda x: x.lower())
最好將文字資料中的停止詞刪除,因為它們十分混亂,幾乎不攜帶任何資訊。停止詞是指'it', 'they', 'am', 'been', 'about', 'because', 'while'之類的詞彙。
要從文件中刪除停止詞,我們必須對文字進行標記,將文字中的字串拆分為單個的標記或單詞。刪除完停止詞後,我們將標記重新拼接到一起。
from nltk.corpus import stopwords
stop_words = stopwords.words('english')
# tokenization
tokenized_doc = news_df['clean_doc'].apply(lambda x: x.split())
# remove stop-words
tokenized_doc = tokenized_doc.apply(lambda x: [item for item in x ifitem not in stop_words])
# de-tokenization
detokenized_doc = []
for i in range(len(news_df)):
t = ' '.join(tokenized_doc[i])
detokenized_doc.append(t)
news_df['clean_doc'] = detokenized_doc
文件-詞項矩陣(Document-Term Matrix)
這是主體建模的第一步。我們將使用sklearn的TfidfVectorizer來建立一個包含1000個詞項的文件-詞項矩陣。
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(stop_words='english',
max_features =1000, # keep top 1000 terms
max_df = 0.5,
smooth_idf = True)
X = vectorizer.fit_transform(news_df['clean_doc'])
X.shape # check shape of the document-term matrix
(11314, 1000)
我們也可以使用全部詞項來建立這個矩陣,但這回需要相當長的計算時間,並佔用很多資源。因此,我們將特徵的數量限制為1000。如果你有計算能力,建議嘗試使用所有詞項。
主題建模
下一步是將每個詞項和文字表示為向量。我們將使用文字-詞項矩陣,並將其分解為多個矩陣。我們將使用sklearn的TruncatedSVD來執行矩陣分解任務。
由於資料來自20個不同的新聞組,所以我們打算從文字資料中提取出20個主題。可以使用n_components引數來制定主題數量。
from sklearn.decomposition import TruncatedSVD
# SVD represent documents and terms in vectors
svd_model = TruncatedSVD(n_components=20, algorithm='randomized', n_iter=100, random_state=122)
svd_model.fit(X)
len(svd_model.components_)
20
svd_model的組成部分即是我們的主題,我們可以透過svd_model.components_來訪問它們。最後,我們列印出20個主題中前幾個最重要的單詞,看看我們的模型都做了什麼。
terms = vectorizer.get_feature_names()
for i, comp in enumerate(svd_model.components_):
terms_comp = zip(terms, comp)
sorted_terms = sorted(terms_comp, key=lambda x:x[1], reverse=True)[:7]
print("Topic "+str(i)+": ")
for t in sorted_terms:
print(t[0])
print(" ")
Topic 0: like know people think good time thanks
Topic 0: like know people think good time thanks
Topic 1: thanks windows card drive mail file advance
Topic 2: game team year games season players good
Topic 3: drive scsi disk hard card drives problem
Topic 4: windows file window files program using problem
Topic 5: government chip mail space information encryption data
Topic 6: like bike know chip sounds looks look
Topic 7: card sale video offer monitor price jesus
Topic 8: know card chip video government people clipper
Topic 9: good know time bike jesus problem work
Topic 10: think chip good thanks clipper need encryption
Topic 11: thanks right problem good bike time window
Topic 12: good people windows know file sale files
Topic 13: space think know nasa problem year israel
Topic 14: space good card people time nasa thanks
Topic 15: people problem window time game want bike
Topic 16: time bike right windows file need really
Topic 17: time problem file think israel long mail
Topic 18: file need card files problem right good
Topic 19: problem file thanks used space chip sale
主題視覺化
為了找出主題之間的不同,我們將其視覺化。當然,我們無法視覺化維度大於3的資料,但有一些諸如PCA和t-SNE等技術可以幫助我們將高維資料視覺化為較低維度。在這裡,我們將使用一種名為UMAP(Uniform Manifold Approximation and Projection)的相對較新的技術。
import umap
X_topics = svd_model.fit_transform(X)
embedding = umap.UMAP(n_neighbors=150, min_dist=0.5, random_state=12).fit_transform(X_topics)
plt.figure(figsize=(7,5))
plt.scatter(embedding[:, 0], embedding[:, 1],
c = dataset.target,
s = 10, # size
edgecolor='none'
)
plt.show()
如上所示,結果非常漂亮。每個點代表一個文件,顏色代表20個新聞組。我們的LSA模型做得很好。可以任意改變UMAP的引數來觀察其對影像的影響。
可在此找到本文的完整程式碼。
LSA的優缺點
如上所述,潛在語義分析非常有用,但是確實有其侷限性。因此,對LSA的優缺點都有充分的認識十分重要,這樣你就知道何時需要使用LSA,以及何時需要嘗試其他方法。
優點:
LSA快速且易於實施。
它的結果相當好,比簡單的向量模型強很多。
缺點:
因為它是線性模型,因此在具有非線性依賴性的資料集上可能效果不佳。
LSA假設文字中的詞項服從正態分佈,這可能不適用於所有問題。
LSA涉及到了SVD,它是計算密集型的,當新資料出現時難以更新。
其他主題建模技術
除了LSA,還有其他一些先進並有效的主題建模技術,如LDA(Latent Dirichlet Allocation)和Ida2Vec。我們有一篇關於LDA的精彩文章,你可以在這裡檢視。Ida2vec是一個基於word2vec單詞嵌入的更先進的主題建模技術。如果你想對它有更多瞭解,可以在下方的評論中留言,我們很樂意回答你的問題。
尾記
本文意於與大家分享我的學習經驗。主題建模是個非常有趣的話題,當你在處理文字資料集時會用到許多技巧和方法。因此,我敦促大家使用本文中的程式碼,並將其應用於不同的資料集。如果您對本文有任何疑問或反饋,請與我們聯絡。快樂地去挖掘文字吧!
原文標題:
Text Mining 101: A Stepwise Introduction to Topic Modeling using Latent Semantic Analysis (using Python)
原文連結:
https://www.analyticsvidhya.com/blog/2018/10/stepwise-guide-topic-modeling-latent-semantic-analysis/