少年壮志不言愁
劝君惜取少年时
贝叶斯定理:
贝叶斯定理是关于随机事件 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 即差评与好评
- 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对象
,分词结果如下图
- tools/jieba_split.py
同时将 label 写入 data/label.txt
参数设置说明
- #!/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 词嵌入文件,即保存了所有词的词向量
代码模块 preprocessing.py
这里构造一个词嵌入矩阵用于存放每条评论的句子矩阵(句子矩阵由词向量表示),其中 212841 是数据集评论数量,128 是词向量维度
- embeddingMtx = np.zeros((212841, 128), dtype = 'float32')
embedding_lookup()方法会在词向量中寻找对应词的向量,如果某个词没有在词向量文件中就在 [-0.5, 0.5] 之间随机生成 128 维的矩阵
- wordsEmbed = map(lambda word: embedding_lookup(word, embDict), words)
- def embedding_lookup(voc, embDict):
- embedding = embDict.get(voc, [random.uniform(-0.5, 0.5) for i in range(128)])
- return embedding
将每一行数据放入词嵌入矩阵 embeddingMtx 中
- embeddingMtx[count] = wordEmbeddingMtx[0]
- import codecs
- import numpy as np
- import pickle
- from tools.utils import embedding_lookup
- np.set_printoptions(threshold=np.inf)
- # 将训练文本数据转换成embedding词矩阵
- def build_embedding():
- # 词向量形式转变成字典
- 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, 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))
- embeddingMtx[count] = wordEmbeddingMtx[0]
- 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
- 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)
- # 读取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))
最终使用朴素贝叶斯分类器最终准确率在 73% 左右,分类效果还算不错 =。=
=========================12.25 更新 ========================
完整代码查看 rates_classify
来源: http://www.jianshu.com/p/e754d10f4fe6