https://blog.csdn.net/qq_39422642/article/details/78730662
這篇文章主要給一些不太喜歡數學的朋友們的,其中基本沒有用什么數學公式。
目錄
目錄
直觀理解主題模型
LDA的通俗定義
LDA分類原理
LDA的精髓
主題模型的簡單應用-希拉里郵件門
1.直觀理解主題模型
聽名字應該就知道他講的是什么?假如有一篇文章text,通過里面的詞,來確定他是什么類型的文章,如果文章中出現很多體育類的詞,比如,籃球,足球之類的,那么主題模型就會把它划分為體育類的文章。
因為主題模型涉及比較多的數學推導,所以我們先用一個小栗子,理解它要做的事。假設有這么一個場景:
一個資深HR收到一份應聘算法工程師的簡歷,他想僅僅通過簡歷來看一下這個人是大牛,還是彩筆,他是怎么判斷呢?
他的一般做法就是拿到這份簡歷,看這個人的簡歷上寫的內容包括了什么?
在此之前呢,他也一定是接觸了很多算法工程師的面試,他根據這些招進來的人判斷,一個大牛,有可能是:
穿條紋襯衫
曾在BAT就職
做過大型項目
這個HR就會看這個面試者是不是穿條紋襯衫,有沒有在BAT就職過,做過什么牛逼的項目,如果都滿足條件,那這個HR就會判斷這個人應該是大牛,如果他只是穿條紋襯衫,沒做過什么拿得出手的項目,那就要猶豫一下了,因為他是彩筆的可能性比較大。
這個例子和主題模型的關系可以用這個圖表示:
在LDA眼里,相當於是詞袋,每個袋子里都有一堆詞,用的時候就只管檢測這些詞出現與否就OK了。
在LDA眼里,相當於是詞袋,每個袋子里都有一堆詞,用的時候就只管檢測這些詞出現與否就OK了。
用公式可以表示成:P(大牛|特征,簡歷)=此特征在大牛中出現的次數大牛擁有的所有特征 X 此簡歷屬於大牛的特征個數P(大牛|特征,簡歷)=此特征在大牛中出現的次數大牛擁有的所有特征 X 此簡歷屬於大牛的特征個數
2.LDA的通俗定義
什么是LDA?
它是一種無監督的貝葉斯模型。
是一種主題模型,它可以將文檔集中的每篇文檔按照概率分布的形式給出。
是一種無監督學習,在訓練時不需要手工標注的訓練集,需要的是文檔集和指定主題的個數。
是一種典型的詞袋模型,它認為一篇文檔是由一組詞組成的集合,詞與詞之間沒有順序和先后關系。
它主要的優點就是可以對每個主題,都找出一些詞來描述它。
3.LDA分類原理
先前詳細寫過貝葉斯模型的原理以及它所代表的思想,詳細請戳:神奇的貝葉斯思想,這里只簡單說一下它的原理,用在這里的意思是:P(大牛|簡歷)=P(大牛)P(簡歷|大牛)∑P(大牛)P(簡歷|大牛)P(大牛|簡歷)=P(大牛)P(簡歷|大牛)∑P(大牛)P(簡歷|大牛)經過一系列推導,可以得到這樣一個鏈式的關系:P(詞 | 文檔)=P(詞 | 主題)P(主題 | 文檔)P(詞 | 文檔)=P(詞 | 主題)P(主題 | 文檔)也就是:詞→主題→文檔詞→主題→文檔這樣的關系。
同一主題下,某個詞出現的概率,以及同一文檔下,某個主題出現的概率,兩個概率的乘積,可以得到某篇文檔出現某個詞的概率,我們在訓練的時候,調整這兩個分布就可以了。
由此可以定義LDA的生成過程:
對每篇文檔,在主題分布中抽取一個主題;(相當於左圖)
對抽到的主題所對應的單詞分布中隨機抽取一個單詞;(在右圖中抽)
重復上述過程直至遍歷整篇文檔中的每個單詞
經過以上三步,就可以看一下兩個分布的乘積,是否符合給定文章的分布,以此來調整。
稍微具體點講: (w代表單詞;d代表文檔;t代表主題; 大寫代表總集合,小寫代表個體。)
D中每篇文檔d看作個單詞序列: <w1,w2,...,wn><w1,w2,...,wn>,wi表示第i個單詞。
D中每篇文檔d看作個單詞序列: <w1,w2,...,wn><w1,w2,...,wn>,wi表示第i個單詞。
D中涉及的所有不同單詞組成一個詞匯表大集合V (vocabulary),LDA以文檔集合D作為輸入,希望訓練出的兩個結果向量 (假設形成k個topic,V中共有m個詞):
結果向量1:對每個D中的文檔d,對應到不同主題的概率θdθd:<pt1,...,ptk><pt1,...,ptk>其中ptipti表示d對應k個主題中第i個主題的概率,計算的方法也很簡單:pti=d中有多少個詞是第i個主題也有的d中所有詞的總數pti=d中有多少個詞是第i個主題也有的d中所有詞的總數
結果向量2:對每個T中的主題tT中的主題t,生成不同單詞的概率向量ϕtϕt:<pw1,...,pwm><pw1,...,pwm>其中pwipwi表示主題tt生成V中第i個單詞的概率。計算方法:pwi=主題t對應到V中第i個單詞出現的次數主題t下的所有單詞總數pwi=主題t對應到V中第i個單詞出現的次數主題t下的所有單詞總數
4.LDA的精髓
說了那么多,其實LDA的核心,仍然是這個公式:
P(詞 | 文檔)=P(詞 | 主題)P(主題 | 文檔)P(詞 | 文檔)=P(詞 | 主題)P(主題 | 文檔)用表達式如下:P(w|d)=P(w|t)∗P(t|d)P(w|d)=P(w|t)∗P(t|d)其實就是以主題為中間層,通過前面的兩個向量(θdθd,ϕtϕt),分別給出P(w|t),P(t|d)P(w|t),P(t|d),它的學習過程可以表示為:
LDA算法開始時,先隨機地給θdθd,ϕtϕt賦值(對所有的d和t)
針對特定的文檔dsds中的第i單詞wiwi,如果令該單詞對應的主題為tjtj,可以把 上述公式改寫為:Pj(wi|ds)=P(wi|tj)∗P(tj|ds)Pj(wi|ds)=P(wi|tj)∗P(tj|ds)
枚舉T中的主題,得到所有的pj(wi|ds)pj(wi|ds).然后可以根據這些概率值的結果為dsds中的第i個單詞wiwi選擇一個主題,最簡單的就是取令Pj(wi|ds)Pj(wi|ds)概率最大的主題 tj tj。
如果dsds中的第i個單詞wiwi在這里選擇了一個與原先不同的主題,就會對θdθd,ϕtϕt有影響,他們的影響反過來影響對上面提到的p(w|d)p(w|d)的計算。
對文檔集D中的所有文檔d中的所有w進行一次p(w|d)p(w|d)計算,並重新選擇主題看成是一次迭代。迭代n次之后就可收斂到LDA所需要的分類結果了。
5.主題模型的簡單應用-希拉里郵件門
我們如果不想要具體了解具體的數學公式推導,理解到這里就差不多了,重點是學會怎么使用?
我們用希拉里郵件門那個案例,看一下應該怎么使用gensim來進行郵件分類。
from gensim import corpora, models, similarities
import gensim
import numpy as np
import pandas as pd
import re
import gensim
import numpy as np
import pandas as pd
import re
df = pd.read_csv("../input/HillaryEmails.csv")
# 原郵件數據中有很多Nan的值,直接扔了。
df = df[['Id','ExtractedBodyText']].dropna()
# 原郵件數據中有很多Nan的值,直接扔了。
df = df[['Id','ExtractedBodyText']].dropna()
df.head()1234567891011
數據樣式:
做一個簡單的預處理:
def clean_email_text(text):
text = text.replace('\n'," ")
text = re.sub('-'," ",text)
text = re.sub(r"\d+/\d+/\d+", "", text) #日期,對主體模型沒什么意義
text = re.sub(r"[0-2]?[0-9]:[0-6][0-9]", "", text) #時間,沒意義
text = re.sub(r"[\w]+@[\.\w]+", "", text) #郵件地址,沒意義
text = re.sub(r"/[a-zA-Z]*[:\//\]*[A-Za-z0-9\-_]+\.+[A-Za-z0-9\.\/%&=\?\-_]+/i", "", text) #網址,沒意義
pure_text = ''
for letter in text:
if letter.isalpha() or letter ==' ':
pure_text += letter
text = ' '.join(word for word in pure_text.split() if len(word)>1)
return text
text = text.replace('\n'," ")
text = re.sub('-'," ",text)
text = re.sub(r"\d+/\d+/\d+", "", text) #日期,對主體模型沒什么意義
text = re.sub(r"[0-2]?[0-9]:[0-6][0-9]", "", text) #時間,沒意義
text = re.sub(r"[\w]+@[\.\w]+", "", text) #郵件地址,沒意義
text = re.sub(r"/[a-zA-Z]*[:\//\]*[A-Za-z0-9\-_]+\.+[A-Za-z0-9\.\/%&=\?\-_]+/i", "", text) #網址,沒意義
pure_text = ''
for letter in text:
if letter.isalpha() or letter ==' ':
pure_text += letter
text = ' '.join(word for word in pure_text.split() if len(word)>1)
return text
docs = df['ExtractedBodyText']
docs = docs.apply(lambda x :clean_email_text(x))
1234567891011121314151617
docs = docs.apply(lambda x :clean_email_text(x))
1234567891011121314151617
看一下處理成啥樣的:
docs.head(2).values1
處理成一個一個詞了
即:[[一條郵件字符串],[另一條郵件字符串],...][[一條郵件字符串],[另一條郵件字符串],...]
手寫的停用詞,這還有各色的別人寫好的停用詞:stopwords
stoplist = ['very', 'ourselves', 'am', 'doesn', 'through', 'me', 'against', 'up', 'just', 'her', 'ours',
'couldn', 'because', 'is', 'isn', 'it', 'only', 'in', 'such', 'too', 'mustn', 'under', 'their',
'if', 'to', 'my', 'himself', 'after', 'why', 'while', 'can', 'each', 'itself', 'his', 'all', 'once',
'herself', 'more', 'our', 'they', 'hasn', 'on', 'ma', 'them', 'its', 'where', 'did', 'll', 'you',
'didn', 'nor', 'as', 'now', 'before', 'those', 'yours', 'from', 'who', 'was', 'm', 'been', 'will',
'into', 'same', 'how', 'some', 'of', 'out', 'with', 's', 'being', 't', 'mightn', 'she', 'again', 'be',
'by', 'shan', 'have', 'yourselves', 'needn', 'and', 'are', 'o', 'these', 'further', 'most', 'yourself',
'having', 'aren', 'here', 'he', 'were', 'but', 'this', 'myself', 'own', 'we', 'so', 'i', 'does', 'both',
'when', 'between', 'd', 'had', 'the', 'y', 'has', 'down', 'off', 'than', 'haven', 'whom', 'wouldn',
'should', 've', 'over', 'themselves', 'few', 'then', 'hadn', 'what', 'until', 'won', 'no', 'about',
'any', 'that', 'for', 'shouldn', 'don', 'do', 'there', 'doing', 'an', 'or', 'ain', 'hers', 'wasn',
'weren', 'above', 'a', 'at', 'your', 'theirs', 'below', 'other', 'not', 're', 'him', 'during', 'which']123456789101112
'couldn', 'because', 'is', 'isn', 'it', 'only', 'in', 'such', 'too', 'mustn', 'under', 'their',
'if', 'to', 'my', 'himself', 'after', 'why', 'while', 'can', 'each', 'itself', 'his', 'all', 'once',
'herself', 'more', 'our', 'they', 'hasn', 'on', 'ma', 'them', 'its', 'where', 'did', 'll', 'you',
'didn', 'nor', 'as', 'now', 'before', 'those', 'yours', 'from', 'who', 'was', 'm', 'been', 'will',
'into', 'same', 'how', 'some', 'of', 'out', 'with', 's', 'being', 't', 'mightn', 'she', 'again', 'be',
'by', 'shan', 'have', 'yourselves', 'needn', 'and', 'are', 'o', 'these', 'further', 'most', 'yourself',
'having', 'aren', 'here', 'he', 'were', 'but', 'this', 'myself', 'own', 'we', 'so', 'i', 'does', 'both',
'when', 'between', 'd', 'had', 'the', 'y', 'has', 'down', 'off', 'than', 'haven', 'whom', 'wouldn',
'should', 've', 'over', 'themselves', 'few', 'then', 'hadn', 'what', 'until', 'won', 'no', 'about',
'any', 'that', 'for', 'shouldn', 'don', 'do', 'there', 'doing', 'an', 'or', 'ain', 'hers', 'wasn',
'weren', 'above', 'a', 'at', 'your', 'theirs', 'below', 'other', 'not', 're', 'him', 'during', 'which']123456789101112
分詞:
texts = [[word for word in doc.lower().split() if word not in stoplist] for doc in doclist]
texts[0]
當然還可以用包,比如jieba,bltk.
得到的就是一篇文檔一個詞袋。
texts = [[word for word in doc.lower().split() if word not in stoplist] for doc in doclist]
texts[0]
當然還可以用包,比如jieba,bltk.
得到的就是一篇文檔一個詞袋。
建立預料庫:每個單詞用數字索引代替,得到一個數組。
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]12
corpus = [dictionary.doc2bow(text) for text in texts]12
得到:
這個列表告訴我們,第14(從0開始是第一)個郵件中,一共6個有意義的單詞(經過我們的文本預處理,並去除了停止詞后)
這個列表告訴我們,第14(從0開始是第一)個郵件中,一共6個有意義的單詞(經過我們的文本預處理,並去除了停止詞后)
其中,36號單詞出現1次,505號單詞出現1次,以此類推。。。
接着,我們終於可以建立模型了:
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20)
lda.print_topic(10, topn=5)12
lda.print_topic(10, topn=5)12
得到第10號分類中,最常見的單詞是:
‘0.007*kurdistan + 0.006*email + 0.006*see + 0.005*us + 0.005*right’
把五個主題打出來看一下:
lda.print_topics(num_topics=5,num_words =6)1
有空可以練一下gesim:
gensim使用指南
gensim使用指南
詳細的推導:數學公式版下一篇文章介紹
參考:七月在線
原文鏈接:https://blog.csdn.net/qq_39422642/article/details/78730662
原文鏈接:https://blog.csdn.net/qq_39422642/article/details/78730662