1. 程式人生 > >LDA + SVM 文字分類

LDA + SVM 文字分類

關於LDA的一些理解

對於語料庫中的每篇文件,LDA定義瞭如下生成過程(generative process):

  1. 對每一篇文件,從主題分佈中抽取一個主題;
  2. 從上述被抽到的主題所對應的單詞分佈中抽取一個單詞;
  3. 重複上述過程直至遍歷文件中的每一個單詞。

P(worddocument)=P(wordtopic)×P(topicdocument)P(word|document) = P(word|topic)\times P(topic|document)

文件document中出現單詞word的概率 = 主題topic中出現word的概率 ×

\times document中出現topic的概率。

  • 以Topic作為中間層,可以通過當前的θd\theta dφt\varphi t得到P(worddocument)P(word|document),其中,P(topicdocument)P(topic|document)利用θd\theta d得到,P(wordtopic)P(word|topic)通過φt\varphi t得到。
  • 實際上,利用當前的θd\theta dφt\varphi t,我們可以為一個文件中的一個單詞計算它對應任意一個Topic時的P
    (Worddocument)P(Word|document)
    ,然後根據這些結果來更新這個詞對應的Topic。如果這個更新改變了這個單詞所對應的Topic,就會反過來影響θd\theta dφt\varphi t
公式背景:
  • 一個函式:Gamma函式

    • F(n)=0tx1etdtF(n) = \int^\infty_0 t^{x-1}e^{-t}dt
    • Gamma函式是階乘函式在實數上的推廣
  • 四個分佈:二項分佈、多項分佈、beta分佈、Dirichlet分佈

  • 一個概念和一個理念:共軛先驗和貝葉斯框架

    • 共軛分佈:後驗概率(posterior probability)\propto 似然函式(likelyhood function) $\times $先驗概率(prior probability)
  • 兩個模型:pLSA、LDA

  • 一個取樣:Gibbs取樣

sklean.decomposition.LatentDirichletAllocation

sklearn的LDA方法與引數說明:

class sklearn.decomposition.LatentDirichletAllocation(n_components = 10,doc_topic_prior = None,topic_word_prior = None,learning_method = None,learning_decay = 0.7,learning_offset = 10.0,max_iter = 10,batch_size = 128,evaluate_every = -1,total_samples = 1000000.0,perp_tol = 0.1,mean_change_tol = 0.001,max_doc_update_iter = 100,n_jobs = 1,verbose = 0,random_state = None,n_topics = None

n_components:int,optional(預設值= 10)

主題數量,老版本該引數名為n_topics

doc_topic_prior:float,optional(預設=無)

之前的文件主題分發theta。如果值為None,則預設為1 / n_components。在文獻中,這被稱為阿爾法。

topic_word_prior:float,optional(預設=無)

之前的主題詞分發beta。如果值為None,則預設為1 / n_components。在文獻中,這被稱為eta。

learning_method:‘batch’(批量更新)| ‘online’(線上更新),預設=‘online’

用於更新_component的方法。僅用於fit方法。通常,如果資料量很大,則線上更新將比批量更新快得多。預設學習方法將在0.20版本中更改為“批處理”。有效選項:

'batch':批量變分貝葉斯方法(Batch variational Bayes method)。每次EM更新都會使用所有訓練資料。
    舊的components_將在每次迭代中被覆蓋。
'online':線上變分貝葉斯方法(Online variational Bayes method)。在每次EM更新中,使用
    小批量的訓練資料來更新components_變數的遞增,學習率由learning_decay和learning_offset引數控制。

learning_decay:float,optional(預設值= 0.7)

它是線上學習方法中控制學習率的引數。該值應設定在(0.5,1.0)之間以保證漸近收斂。當值為0.0且batch_size為時 n_samples,更新方法與批量學習相同。在文獻中,這稱為kappa。

learning_offset:float,optional(預設值= 10.)

一個(正)引數,可以降低線上學習中的早期迭代。它應該大於1.0。在文獻中,這稱為tau_0。

max_iter:整數,可選(預設= 10)

最大迭代次數。

batch_size:int,optional(預設值= 128)

每次EM迭代中使用的文件數。僅用於線上學習。

evaluate_every:int,optional(預設值= 0)

多久評估一次困惑。僅用於fit方法。將其設定為0或負數,以便根本不評估訓練中的困惑。評估困惑可以幫助您檢查培訓過程中的收斂,但也會增加總培訓時間。評估每次迭代中的困惑可能會將訓練時間增加兩倍。

total_samples:int,optional(default = 1e6)

檔案總數。僅用於partial_fit方法。

perp_tol:float,optional(預設值= 1e-1)

批量學習中的困惑容忍度。僅在 evaluate_every大於0時使用。

mean_change_tol:float,optional(預設值= 1e-3)

在E步驟中停止更新文件主題分發的容差。

max_doc_update_iter:int(預設值= 100)

在E步驟中更新文件主題分發的最大迭代次數。

n_jobs:int,optional(預設值= 1)

在E步驟中使用的作業數。如果為-1,則使用所有CPU。對於 n_jobs-1以下,使用(n_cpus + 1 + n_jobs)。

verbose:int,optional(預設值= 0)

詳細程度。

random_state:int,RandomState例項或None,可選(預設=無)

如果是int,則random_state是隨機數生成器使用的種子; 如果是RandomState例項,則random_state是隨機數生成器; 如果沒有,隨機數生成器所使用的RandomState例項np.random。

方法
fit(X [,y]) 使用變分貝葉斯方法學習資料X的模型。
獲取此估算工具的引數。
線上VB與Mini-Batch更新。
perplexity(X [,doc_topic_distr,sub_sampling]) 計算資料X的近似困惑。
score(X [,y]) 計算近似對數似然值作為分數。
設定此估算器的引數。
根據擬合模型轉換資料X.
  • __init__n_components = 10doc_topic_prior = Nonetopic_word_prior = Nonelearning_method = Nonelearning_decay = 0.7learning_offset = 10.0max_iter = 10batch_size = 128evaluate_every = -1total_samples = 1000000.0perp_tol = 0.1mean_change_tol = 0.001max_doc_update_iter = 100n_jobs = 1verbose = 0random_state = Nonen_topics = None )[source]

  • fitXy =無)[來源]

    使用變分貝葉斯方法學習資料X的模型。當learning_method為“線上”時,請使用小批量更新。否則,請使用批量更新。引數:X:類似陣列或稀疏矩陣,shape =(n_samples,n_features)文件字矩陣。y:忽略了。return:self

  • fit_transformXy =無,*** fit_params* )[來源]

    適合資料,然後轉換它。使用可選引數fit_params使變換器適合X和y,並返回X的變換版本。引數:X:numpy陣列形狀[n_samples,n_features]訓練集。y:numpy陣列形狀[n_samples]目標值。返回:X_new:numpy形狀陣列[n_samples,n_features_new]變形陣列。

  • get_params深=真)[來源]

    獲取此估算工具的引數。引數:deep:布林值,可選如果為True,將返回此估計器的引數幷包含作為估算器的子物件。返回:params:將字串對映到任意字串對映到其值的引數名稱。

  • partial_fitXy =無)[來源]

    線上VB與Mini-Batch更新。引數:X:類似陣列或稀疏矩陣,shape =(n_samples,n_features)文件字矩陣。y:忽略了。return:self

  • perplexityXdoc_topic_distr =‘不贊成’sub_sampling = False )[來源]

    計算資料X的近似困惑。困惑定義為exp(-1。每個單詞的對數似然)版本0.19中已更改:已棄用doc_topic_distr*引數並將其忽略,因為使用者無法再訪問非標準化分佈引數:X:類似陣列或稀疏矩陣,[n_samples,n_features]文件字矩陣。doc_topic_distr:無或陣列,shape =(n_samples,n_components)文件主題分發。此引數已棄用,目前正在被忽略。從版本0.19開始不推薦使用。sub_sampling:bool是否進行二次取樣。返回:得分:漂浮困惑得分。

  • scoreXy =無)[來源]

    計算近似對數似然值作為分數。引數:X:類似陣列或稀疏矩陣,shape =(n_samples,n_features)文件字矩陣。y:忽略了。返回:得分:漂浮使用近似界限作為分數。

  • set_params(*** params* )[來源]

    設定此估算器的引數。該方法適用於簡單估計器以及巢狀物件(例如管道)。後者具有表單的引數,<component>__<parameter>以便可以更新巢狀物件的每個元件。return:self

  • transformX )[來源]

    根據擬合模型轉換資料X.在版本0.18中更改:doc_topic_distr現在已標準化引數:X:類似陣列或稀疏矩陣,shape =(n_samples,n_features)文件字矩陣。返回:doc_topic_distr:shape =(n_samples,n_components)X的文件主題分發。

例項1 : 使用LDA+SVM進行文字多分類

網上沒找到LDA與SVM結合的程式碼,我自己的實現方法如下,不知道用的正不正確,僅供參考。由於在比賽,暫不提供完整的參考程式碼。

Step 1. CV特徵提取
  • LDA模型學習時的訓練資料並不是一篇篇文字,而是Document-word matrix,它可以是array也可以是稀疏矩陣,維數是n_samples*n_features,其中n_features為詞(term)的個數。因此在訓練LDA主題模型前,需要先利用CountVectorizer統計詞頻並儲存
from sklearn.feature_extraction.text import CountVectorizer

# 構建總單詞矩陣
count_v0= CountVectorizer();  
counts_all = count_v0.fit_transform(all_text); #all_text為訓練集+測試集語料庫

# 構建訓練集單詞矩陣
count_v1= CountVectorizer(vocabulary=count_v0.vocabulary_)
counts_train = count_v1.fit_transform(train_texts)

# 構建測試集單詞矩陣
# count_v2 = CountVectorizer(vocabulary=count_v0.vocabulary_) 
# counts_test = count_v2.fit_transform(test_texts);  
Step 2. LDA構建詞模型(不太清楚這裡應該怎麼說?感覺依舊在做特徵工程)
  • 核心程式碼為三步:構建模型、擬合數據(fit)、根據擬合模型轉換資料(transform)。
from sklearn.decomposition import LatentDirichletAllocation
lda = LatentDirichletAllocation(n_components=n_component, max_iter=50, learning_method='batch')
X_train = lda.fit(counts_train).transform(counts_train)
# X_test = lda.fit(counts_test).transform(counts_test)
Step 3. 使用分類模型(SVC為例)
  • 把LDA構建好的詞模型輸入到分類器中即可。
svclf = SVC(kernel = 'linear') 
svclf.fit(x_train,y_train)  
preds = svclf.predict(x_test)
# ...

例項2 :使用LDA進行文字多分類

# 載入資料,使用sklearn自帶的fetch_20newsgroups資料集
from sklearn.datasets import fetch_20newsgroups
dataset = fetch_20newsgroups(shuffle=True, random_state=1,
                             remove=('headers', 'footers', 'quotes'))
n_samples=200
data_samples = dataset.data[:n_samples] #擷取需要的量,n_samples=2000

# CountVectorizer統計詞頻
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.externals import joblib  #也可以選擇pickle等儲存模型,請隨意
n_features=2500
#構建詞彙統計向量並儲存,僅執行首次
tf_vectorizer = CountVectorizer(max_df=0.95, min_df=2,
                                max_features=n_features,
                                stop_words='english')
tf = tf_vectorizer.fit_transform(data_samples)
joblib.dump(tf_vectorizer,'tf_Model.pkl',compress=3)

#==============================================================================
#得到儲存的tf_vectorizer,節省預處理時間
#from sklearn.externals import joblib
#tf_vectorizer = joblib.load('tf_Model.pkl')
#tf = tf_vectorizer.fit_transform(data_samples)
#==============================================================================

from sklearn.decomposition import LatentDirichletAllocation
n_topic = 10
n_topics = 30
lda = LatentDirichletAllocation(n_topics=n_topic, 
                                max_iter=50,
                                learning_method='batch')
lda.fit(tf) #tf即為Document_word Sparse Matrix

def print_top_words(model, feature_names, n_top_words):
    #列印每個主題下權重較高的term
    for topic_idx, topic in enumerate(model.components_):
        print ("Topic #%d:" % topic_idx)
        print (" ".join([feature_names[i] for i in topic.argsort()[:-n_top_words - 1:-1]]))
    #列印主題-詞語分佈矩陣
    print (model.components_)

n_top_words=20
tf_feature_names = tf_vectorizer.get_feature_names()
print_top_words(lda, tf_feature_names, n_top_words)

#print trained topic model
tf_feature_names = tf_vectorizer.get_feature_names()
for idx, topic in enumerate(lda.components_, start=1):
    print('Topic #%d' % idx)
    print("/".join([tf_feature_names[i] for i in topic.argsort ()[:-11:-1]]))   #列印(主題-詞彙)向量

lda.transform(tf)[0]  #列印(文章-主題)向量