图片来自网络少年壮志不言愁
劝君惜取少年时
贝叶斯定理:
贝叶斯定理是关于随机事件A和B的条件概率(或边缘概率)的一则定理。其中P(A|B)是在B发生的情况下A发生的可能性。关于贝叶斯理论的详细推理,可以参考这篇文章。
P(A丨B)=P(A)P(B丨A)/P(B)
小试牛刀
这里选择当当网书评价(好评、差评)应用贝叶斯分类算法,其中差评数据10w条,好评数据11w条,数据保存到trainset.csv数据下载链接
训练集中包括差评和好评数据共221968,其中包括无效数据及空行,后面将被清除
训练集第一行
header
包括两个字段rate
即评论正文和评论类型type
即差评与好评
1. 首先对抓取的数据清洗,删除空格
、\u3000
、 \xa0
等字符
def cleanTrianSet(filepath):
"""
清洗句子中空行、空格
目前采用将所有数据读取到内存,后续思考其他高效方式
"""
# 删除评论上面的 \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:]) # 更加优雅的方式 在这个问题中是比较快的方式
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
网友评论