Task5 樸素貝葉斯、SVM、LDA主題模型

任務

  1. 樸素貝葉斯
  • 樸素貝葉斯的原理

  • 利用樸素貝葉斯模型進行文本分類

  1. SVM模型
  • SVM的原理
  • 利用SVM模型進行文本分類
  1. LDA主題模型
  • pLSA、共軛先驗分布
  • LDA
  • 使用LDA生成主題特征,在之前特征的基礎上加入主題特征進行文本分類

樸素貝葉斯

  1. 樸素貝葉斯的原理

樸素貝葉斯被稱為樸素是因為引入了幾個假設:
貝葉斯公式如下:
P(B|A) = P(A|B)P(B) / P(A)
換成分類任務的表達式:
P(類別|特征) = P(特征|類別)P(類別) / P(特征)
1.每個詞都是獨立的特征
P(y_i|x) = P(X|y_i)p(y_i) = p(x_1, x_2,...,x_m|yi)P(y_i)
2.假設所有詞相互條件獨立
P(y_i|x) = p(x_1|y_i)p(x_2|y_i)...p(x_m|y_i)P(y_i)
樸素貝葉斯公式為:

  1. 樸素貝葉斯模型進行文本分類

樸素貝葉斯是單獨考量每一唯獨特征被分類的條件概率,進而綜合這些概率并對其所在的特征向量做出分類預測;
樸素貝葉斯的基本數據假設是:各個維度上的特征被分類的條件概率之間是相互獨立的,它經常被應用在文本分類中,包括互聯網新聞的分類,垃圾郵件的篩選
下面采用新聞分類為示例:

  • 首先獲取fetch_20newsgroups數據集中的所有數據, 并輸出數據共有多少條
from sklearn.datasets import fetch_20newsgroups

# 獲取數據
news = fetch_20newsgroups(subset='all')
# 輸出數據長度
print(len(news.data))
# 查看新聞類別
pprint(list(news.target_names))

可以看到數據共有18846篇文章,一共涉及到20種話題


數據集信息
  • 對數據進行預處理
    • 劃分數據集:20%的數據作為測試集
    • 文本特征向量化
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer 

def pre_news(data):
    '''
        數據預處理:
            劃分訓練集,測試集
            文本特征向量化
    '''
    # 隨機采樣20%作為測試集
    X_train, X_test, y_train, y_test = train_test_split(data.data, 
                                                        data.target,
                                                        test_size = 0.2,
                                                        random_state=33)
    # 文本特征向量化
    vec = CountVectorizer()
    X_train = vec.fit_transform(X_train)
    X_test = vec.transform(X_test)
    
    return X_train, X_test, y_train, y_test

# 數據預處理
X_train, X_test, y_train, y_test = pre_news(news)
  • 使用樸素貝葉斯進行訓練并預測
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report

def train_model_bayes(data, X_train, y_train, X_test, y_test):
    '''
        使用樸素貝葉斯進行訓練并預測
    '''
    clf = MultinomialNB()
    clf.fit(X_train, y_train)
    y_pre = clf.predict(X_test)
    
    # 獲取結果報告
    print('acc:', clf.score(X_test, y_test))
    print(classification_report(y_test, y_pre, target_names=data.target_names))
    return y_pre

# 使用樸素貝葉斯進行訓練
y_pre = train_model_bayes(news, X_train, y_train, X_test, y_test)

樸素貝葉斯模型被廣泛應用于海量互聯網分類任務中,其特點如下:
1.模型預測所需要的參數規模從冪指數量級向線性量級減少
2.對內存的消耗和計算時間大大減少
3.受強假設的影響,模型訓練時無法將各個特征之間的聯系考量在內,導致當特征關聯性較強時分類效果不佳

拓展:高斯模型、伯努利模型使用

  1. 高斯模型

高斯模型可以解決對連續型變量的處理的問題,高斯模型假設這些特征的所有屬于某個類別的觀測值符合高斯分布,使用方法如下:

from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import confusion_matrix

def correct_rate(predict_labels, y):
    # 查看預測對了幾個
    n = 0
    for i in range(len(predict_labels)):
        if (predict_labels[i] == y[i]):
            n = n + 1
    print('高斯貝葉斯:')
    # 輸出正確率
    print(n/499.0)
    
    return n
    

# 高斯貝葉斯
def train_model_GaussianNB():
    pass
    clf3 = GaussianNB()
    # 訓練模型
    clf3.fit(X[499:], y[499:])
    predict_labels = clf3.predict(X[0:499])
    n = correct_rate(predict_labels, y)
    # 混淆矩陣
    confusion_matrix(y[0:499], predict_labels)
  1. 伯努利模型

P(c)= 類c下文件總數/整個訓練樣本的文件總數
P(tk|c)=(類c下包含單詞tk的文件數+1)/(類c下包含的文件+2)

from sklearn.naive_bayes import BernoulliNB    
    
# 伯努利模型
def train_model_BernoulliNB():
    pass
    clf2 = BernoulliNB()
    clf2.fit(X[499:], y[499:])
    predict_labels = clf2.predict(X[0:499])
    n = correct_rate(predict_labels, y)
    # 混淆矩陣
    confusion_matrix(y[0:499], predict_labels)

補充:文本分類是作為離散型數據的。樸素貝葉斯用于很多方面,數據就會有連續和離散的,連續型時可用正態分布,還可用區間,將數據的各屬性分成幾個區間段進行概率計算,測試時看其屬性的值在哪個區間就用哪個條件概率。再有TF、TDIDF,這些只是描述事物屬性時的不同計算方法,例如文本分類時,可以用單詞在本文檔中出現的次數描述一個文檔,可以用出現還是沒出現即0和1來描述,還可以用單詞在本類文檔中出現的次數與這個單詞在剩余類出現的次數(降低此屬性對某類的重要性)相結合來表述。
https://blog.csdn.net/u013710265/article/details/72780520

SVM

  1. SVM原理

Svm(support Vector Mac)又稱為支持向量機,是一種二分類的模型,支持向量機可以分為線性核非線性兩大類。其主要思想為找到空間中的一個更夠將所有數據樣本劃開的超平面,并且使得本本集中所有數據到這個超平面的距離最短。
SVM算法原理參照:https://blog.csdn.net/d__760/article/details/80387432

  1. 利用SVM模型進行文本分類
  • 使用梯度下降法(SGD),用于判斷使用凸loss函數(convex loss function)的分類器(SVM或logistic回歸),當loss='hinge':求解線性SVM的分類器,使用方法如下:
    • 讀取數據并且對數據進行預處理,與上文貝葉斯使用同樣的方法,這里不過多贅述
    • 使用SVM進行新聞分類,并評價
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import classification_report
import numpy as np

def train_model_svm(data, X_train, X_test, y_train, y_test):
    '''
        SVM進行新聞分類
    '''
    svm_clf = SGDClassifier(loss='hinge',
                            penalty='l2',
                            alpha=8e-5,
                            max_iter=5,
                            random_state=50)
    svm_clf.fit(X_train, y_train)
    y_pre = svm_clf.predict(X_test)
    # 輸出準確率
    print('acc:', np.mean(y_test == y_pre))
    # 獲取結果報告
    print(classification_report(y_test, y_pre, target_names=data.target_names))

參數設置如下:https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html

  • 使用sklearn.svm.svc 進行中文文本分類
def train_model_svc(data, target_names, X_train, X_test, y_train, y_test):
    '''
        SVM進行新聞分類
    '''
    svm_clf = svm.SVC(C=10.0,           # 懲罰系數
                      cache_size=200,       # 緩沖大小,限制計算量大小
                      class_weight=None,        # 權重設置
                      coef0=0.0,            # 核函數常數,默認為0
                      decision_function_shape=None,         # 原始的SVM只適用于二分類問題
                      degree=3,         # 當指定kernel為'poly'時,表示選擇的多項式的最高次數,默認為三次多項式
                      gamma='auto',     # 核函數系數,默認是'auto',那么將會使用特征位數的倒數,即1 / n_features
                      kernel='rbf',     # 算法中采用的核函數類型, 默認的是"RBF",即徑向基核,也就是高斯核函數
                      max_iter=-1,      # 最大迭代次數,默認-1
                      probability=False,    # 是否使用概率估計,默認是False
                      random_state=None,    # 在使用SVM訓練數據時,要先將訓練數據打亂順序,用來提高分類精度,這里就用到了偽隨機序列。如果該參數給定的是一個整數,則該整數就是偽隨機序列的種子值
                      shrinking=True,       # 是否進行啟發式
                      tol=0.001,            # 殘差收斂條件,默認是0.0001
                      verbose=False)        # 是否啟用詳細輸出
    svm_clf.fit(X_train, y_train)
    y_pre = svm_clf.predict(X_test)
    # 輸出準確率
    print('acc:', np.mean(y_test == y_pre))
    # 獲取結果報告
    print(classification_report(y_test, y_pre, target_names=target_names))

參數設置如下:https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC

LDA主題模型

LDA是一種文檔主題生成模型,也稱為一個三層貝葉斯概率模型,包含詞、主題和文檔三層結構。
生成模型:我們認為一篇文章的每個詞都是通過“以一定概率選擇了某個主題,并從這個主題中以一定概率選擇某個詞語”這樣一個過程得到。文檔到主題服從多項式分布,主題到詞服從多項式分布。

LDA是一種非監督機器學習技術,可以用來識別大規模文檔集(document collection)或語料庫(corpus)中潛藏的主題信息。
* 采用了詞袋的方法,把每一篇文檔看做為一個詞頻向量;
* 每一篇文檔代表了一些主題所構成的一個概率分布,而每一個主題又代表了很多單詞所構成的一個概率分布。

  1. 使用LDA生成主題特征,在之前特征的基礎上加入主題特征進行文本分類
  • 加載lda中的數據
import lda.datasets

def load_data():
    '''
        加載lda中的數據
    '''
    X = lda.datasets.load_reuters()
    vocab = lda.datasets.load_reuters_vocab()
    titles = lda.datasets.load_reuters_titles()
    
    return X, vocab, titles

X, vocab, titles = load_data()
  • 指定主題,進行迭代
    #指定11個主題,500次迭代
    model = lda.LDA(random_state=1, n_topics=11, n_iter=1000)
    model.fit(X)
  • 查看主題-單詞分布
    # 主題單詞分布
    topic_word = model.topic_word_
    print('type(topic_word):{}'.format(type(topic_word)))
    print('shape:{}'.format(topic_word.shape))
  • 獲取每個topic下權重最高的10個單詞
    n = 10
    for i, topic_dist in enumerate(topic_word):
        topic_words = np.array(vocab)[np.argsort(topic_dist)][:-(n+1):-1]
        print('topic {}\n -{}'.format(i, ' '.join(topic_words)).encode('utf-8'))
  • 查看文檔主題分布
    #文檔主題分布:
    doc_topic = model.doc_topic_
    print("type(doc_topic): {}".format(type(doc_topic)))
    print("shape: {}".format(doc_topic.shape))
  • 輸入前10篇文章最可能的topic
    # 輸入前10篇文章最可能的topic
    for n in range(20):
        topic_most_pr = doc_topic[n].argmax()
        print('doc: {} topic: {}'.format(n, topic_most_pr))
  1. 利用gensim調用LDA
    • 首先讀取數據
    • 利用doc2bow將文本轉化為詞袋模型
    • 調用LDA模型并指定主題數量
    • 檢查結果
from gensim.test.utils import common_texts
from gensim.corpora.dictionary import Dictionary
from gensim.models import LdaModel

def train_model_lda_gensim():
    # 把文章轉成list
    common_dictionary = Dictionary(common_texts)
    print(type(common_texts))
    print(common_texts[0])
    
    # 把文本轉成詞袋形式
    common_corpus = [common_dictionary.doc2bow(text) for text in common_texts]
    
    # 調用lda模型,并指定10個主題
    lda = LdaModel(common_corpus, num_topics=10)
    # 檢查結果
    lda.print_topic(1, topn=2)
 

補充: 還可以對之前生成的lda模型用新語料庫去更新

    # 用新語料庫去更新
    # 能更新全部參數
    lda.update(other_corpus)
    #還能單獨更新主題分布, 輸入為之前的參數,其中rho指學習率
    lda.update_alpha(gammat, rho)
    #還能單獨更新詞分布
    lda.update_eta(lambdat, rho)

完整代碼見github

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。