樸素貝葉斯分類算法實踐

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

圖片來自網絡

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

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

小試牛刀

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

訓練集trainset.csv.png

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

1. 首先對抓取的數(shù)據(jù)清洗萧落,刪除空格践美、\u3000\xa0等字符

  def cleanTrianSet(filepath):
      """
      清洗句子中空行找岖、空格
      目前采用將所有數(shù)據(jù)讀取到內存陨倡,后續(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兴革,分詞結果如下圖

分詞后數(shù)據(jù)集.png

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

3.使用Word2Vec對分詞數(shù)據(jù)集訓練詞向量

參數(shù)設置說明

  • size=128: 設置詞向量維度為128,是指特征向量的維度蜜唾,默認為100杂曲。大的size需要更多的訓練數(shù)據(jù),但是效果會更好. 推薦值為幾十到幾百
  • 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.數(shù)據(jù)預處理

代碼模塊preprocessing.py

  • 代碼解析1

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

    這里構造一個詞嵌入矩陣用于存放每條評論的句子矩陣(句子矩陣由詞向量表示),其中212841是數(shù)據(jù)集評論數(shù)量朱转,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]將每一行數(shù)據(jù)放入詞嵌入矩陣embeddingMtx

  • 完整代碼如下

    import codecs
    import numpy as np
    import pickle
    from tools.utils import embedding_lookup
    
    np.set_printoptions(threshold=np.inf)
    # 將訓練文本數(shù)據(jù)轉換成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.訓練數(shù)據(jù)

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數(shù)據(jù)缅疟,并且使用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)

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

    # 測試數(shù)據(jù)
    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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末存淫,一起剝皮案震驚了整個濱河市耘斩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桅咆,老刑警劉巖括授,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異岩饼,居然都是意外死亡荚虚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門籍茧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來版述,“玉大人,你說我怎么就攤上這事寞冯】饰觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵吮龄,是天一觀的道長俭茧。 經常有香客問我,道長漓帚,這世上最難降的妖魔是什么恢恼? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮胰默,結果婚禮上场斑,老公的妹妹穿的比我還像新娘。我一直安慰自己牵署,他們只是感情好漏隐,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奴迅,像睡著了一般青责。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上取具,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天脖隶,我揣著相機與錄音,去河邊找鬼暇检。 笑死产阱,一個胖子當著我的面吹牛,可吹牛的內容都是我干的块仆。 我是一名探鬼主播构蹬,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼王暗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了庄敛?” 一聲冷哼從身側響起俗壹,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藻烤,沒想到半個月后绷雏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡怖亭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年涎显,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片依许。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡棺禾,死狀恐怖,靈堂內的尸體忽然破棺而出峭跳,到底是詐尸還是另有隱情膘婶,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布蛀醉,位于F島的核電站悬襟,受9級特大地震影響,放射性物質發(fā)生泄漏拯刁。R本人自食惡果不足惜脊岳,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垛玻。 院中可真熱鬧割捅,春花似錦、人聲如沸帚桩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽账嚎。三九已至莫瞬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郭蕉,已是汗流浹背疼邀。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留召锈,地道東北人旁振。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親规求。 傳聞我的和親對象是個殘疾皇子筐付,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容