樸素貝葉斯分類算法實踐

少年壯志不言愁
勸君惜取少年時

圖片來自網絡

貝葉斯定理:
貝葉斯定理是關于隨機事件A和B的條件概率(或邊緣概率)的一則定理。其中P(A|B)是在B發(fā)生的情況下A發(fā)生的可能性。關于貝葉斯理論的詳細推理,可以參考這篇文章

P(A丨B)=P(A)P(B丨A)/P(B)

小試牛刀

這里選擇當當網書評價(好評、差評)應用貝葉斯分類算法,其中差評數據10w條,好評數據11w條,數據保存到trainset.csv數據下載鏈接

訓練集trainset.csv.png

訓練集中包括差評和好評數據共221968,其中包括無效數據及空行,后面將被清除
訓練集第一行header包括兩個字段rate即評論正文和評論類型type即差評與好評

1. 首先對抓取的數據清洗,刪除空格\u3000\xa0等字符

  def cleanTrianSet(filepath):
      """
      清洗句子中空行、空格
      目前采用將所有數據讀取到內存,后續(xù)思考其他高效方式
      """
      # 刪除評論上面的 \n
      fileDf = pd.read_csv(filepath, keep_default_na=False)
      fileDf["rate"] = fileDf["rate"].apply(lambda x: x.replace("\n", ""))
      linelist = fileDf.values.tolist()
      filelines = [ _[0] + "," + _[-1] for _ in linelist]
      cleaned_lines = map(lambda x: x.translate({ord('\u3000'): '', ord('\r'): '', ord('\xa0'): None,
                                                  ord(' '): None}), filelines[1:])  # 更加優(yōu)雅的方式 在這個問題中是比較快的方式
      return cleaned_lines  # 返回一個map對象

2. 使用開源分詞工具jieba分詞對正負面語料進行分詞,分詞過程中刪除了空行等。分詞代碼tools/jieba_split.py,分詞結果如下圖

分詞后數據集.png

同時將label寫入data/label.txt
label.txt.png

3.使用Word2Vec對分詞數據集訓練詞向量

參數設置說明

  • size=128: 設置詞向量維度為128,是指特征向量的維度,默認為100。大的size需要更多的訓練數據,但是效果會更好. 推薦值為幾十到幾百
  • window=12:訓練窗口設置為12,即考慮一個詞前五個詞和后五個詞的影響
  • min_count=10:詞頻小于該值的詞就會被舍棄
  • sg:設置訓練算法,默認為0,對應CBOW算法;sg=1則采用skip-gram算法。
#!/usr/bin/env python
# -*-coding:utf-8-*-
"""
@Time: 17-11-20 
@author: xhades
@version: v0.1
"""
from gensim.models import word2vec

sentence = word2vec.Text8Corpus('../data/splited_words.txt')
model = word2vec.Word2Vec(sentence, size=128, min_count=10, sg=1, window=12, workers=8)
model.wv.save_word2vec_format("../data/embedding.txt", binary=False, )
model.save("../Model/word2vec.model")

形成embedding.txt詞嵌入文件,即保存了所有詞的詞向量

4.數據預處理

代碼模塊preprocessing.py

  • 代碼解析1

    embeddingMtx = np.zeros((212841, 128), dtype='float32')
    

    這里構造一個詞嵌入矩陣用于存放每條評論的句子矩陣(句子矩陣由詞向量表示),其中212841是數據集評論數量,128是詞向量維度

  • 代碼解析2

     wordsEmbed = map(lambda word: embedding_lookup(word, embDict), words)
    

    embedding_lookup()方法會在詞向量中尋找對應詞的向量,如果某個詞沒有在詞向量文件中就在[-0.5, 0.5]之間隨機生成128維的矩陣

    def embedding_lookup(voc, embDict):
        embedding = embDict.get(voc, [random.uniform(-0.5, 0.5) for i in range(128)])
        return embedding
    
  • 代碼解析3
    最后通過embeddingMtx[count][i] = wordEmbeddingMtx[i]將每一行數據放入詞嵌入矩陣embeddingMtx

  • 完整代碼如下

    import codecs
    import numpy as np
    import pickle
    from tools.utils import embedding_lookup
    
    np.set_printoptions(threshold=np.inf)
    # 將訓練文本數據轉換成embedding詞矩陣
    def build_embedding():
        max_sequence_length = 30
        # 詞向量形式轉變成字典
        with open("data/embedding.txt") as embFile:
            embLines = embFile.readlines()
        embDict = {_.strip("\n").split(" ")[0]: _.strip("\n").split(" ")[1:] for _ in embLines[1:]}
    
        # 加載splited  word文件
        fileData = codecs.open("data/splited_words.txt", "r", encoding="utf-8")
    
        # embedding文件
        embeddingMtx = np.zeros((212841, max_sequence_length, 128), dtype='float32')
        count = 0
        fileLine = fileData.readline()
    
        while fileLine:
            fileLine = fileLine.strip()
    
            if fileLine:
                words = fileLine.split(" ")
                # 對應詞向量列表
                wordsEmbed = map(lambda word: embedding_lookup(word, embDict), words)
                # 列表轉成矩陣, 序列化寫入文件
                wordEmbeddingMtx = np.matrix(list(wordsEmbed))
    
                # 獲得句子真實長度
                actual_sequence_length = wordEmbeddingMtx.shape[0]
                if actual_sequence_length <= max_sequence_length:
                    epochs = actual_sequence_length
                else:
                    epochs = max_sequence_length
    
                for i in range(epochs):
                    embeddingMtx[count][i] = wordEmbeddingMtx[i]
                fileLine = fileData.readline()
                count += 1
                continue
    
            fileLine = fileData.readline()
        fileData.close()
        print("End.....")
        # print(embeddingMtx)
        with open("Res/char_embedded.pkl", "wb") as file_w:
            pickle.dump(embeddingMtx, file_w)
    

5.訓練數據

sklearn中,提供了3中樸素貝葉斯分類算法:GaussianNB(高斯樸素貝葉斯)、MultinomialNB(多項式樸素貝葉斯)、BernoulliNB(伯努利樸素貝葉斯)

我這里主要選擇使用伯努利模型的貝葉斯分類器來進行短評分類。

并且按照7:3的比例劃分訓練集和測試集

import numpy as np
from numpy import array, argmax, reshape
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from sklearn.naive_bayes import BernoulliNB
import pickle

np.set_printoptions(threshold=np.inf)


# 訓練集測試集 3/7分割
def train(xFile, yFile):
    with open(xFile, "rb") as file_r:
        X = pickle.load(file_r)
    # print(X.shape)
    X = reshape(X, (212841, -1))  # reshape一下 (212841, 30*128)
    # 讀取label數據,并且使用LabelEncoder對label進行編號
    with open(yFile, "r") as yFile_r:
        labelLines = [_.strip("\n") for _ in yFile_r.readlines()]
    values = array(labelLines)
    labelEncoder = LabelEncoder()
    integerEncoded = labelEncoder.fit_transform(values)
    integerEncoded = integerEncoded.reshape(len(integerEncoded), 1)
    # print(integerEncoded)

    # 獲得label 編碼
    Y = integerEncoded.reshape(212841, )
    X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=42)

    # 訓練數據
    clf = BernoulliNB()
    clf.fit(X_train, Y_train)

    # 測試數據
    predict = clf.predict(X_test)
    count = 0
    for p, t in zip(predict, Y_test):
        if p == t:
            count += 1
    print("Accuracy is:", count/len(Y_test))

最終使用樸素貝葉斯分類器最終準確率在71%左右,分類效果還算不錯=。=

=========================12.25更新========================

  • 添加決策樹分類代碼 dtClf.py 分類準確率 89.1%+

完整代碼查看rates_classify

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容