少年壯志不言愁
勸君惜取少年時
貝葉斯定理:
貝葉斯定理是關于隨機事件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ù)下載鏈接
訓練集中包括差評和好評數(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
兴革,分詞結果如下圖
同時將label寫入
data/label.txt
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