赞
踩
任务一:使用朴素贝叶斯过滤垃圾邮件。现有50封电子邮件,25封在ham文件夹中,25封在spam文件夹中,试基于朴素贝叶斯分类器原理,用Python编程实现对垃圾邮件和正常邮件的分类。采用交叉验证方式并且输出分类的错误率及分类错误的文档。
任务二:MNIST数据集基于朴素贝叶斯分类器的手写识别。数据集可以在官网上下载(我没有搜过官网),分别得到训练集图片,训练集标签,测试集图片,测试集标签
train-images-idx3-ubyte.gz: training set images (9912422 bytes)
train-labels-idx1-ubyte.gz: training set labels (28881 bytes)
t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)
t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)
MNIST数据集的读取和图片特征提取的代码已经给出
任务三:使用朴素贝叶斯对电影评论分类。该数据集是IMDB电影数据集的一个子集,已经划分好了测试集和训练集,训练集包括25000条电影评论,测试集也有25000条,该数据集已经经过预处理,将每条评论的具体单词序列转化为词库里的整数序列,其中每个整数代表该单词在词库里的位置。例如,整数104代表该单词是词库的第104个单词。为实验简单,词库仅仅保留了10000个最常出现的单词,低频词汇被舍弃。每条评论都具有一个标签,0表示为负面评论,1表示为正面评论。train_data.txt、train_labels.txt、test_data.txt已给出,未给出测试集的标签
先复习一下什么是贝叶斯吧。概率论里面学了一个贝叶斯定理
P
(
c
∣
x
)
=
P
(
x
∣
c
)
×
P
(
c
)
P
(
x
)
P(c|\mathbf{x} )=\frac{P(\mathbf{x}|c)\times P(c)}{P(\mathbf{x})}
P(c∣x)=P(x)P(x∣c)×P(c)
还学了个极大似然估计
朴素贝叶斯就是假设各属性独立,有
P
(
c
∣
x
)
=
P
(
c
)
P
(
x
)
∏
i
=
1
d
P
(
x
i
∣
c
)
P(c|\mathbf{x} )=\frac{ P(c)}{P(\mathbf{x})} \prod_{i=1}^{d}P(x_{i}|c)
P(c∣x)=P(x)P(c)∏i=1dP(xi∣c)
其中
P
(
x
i
∣
c
)
P(x_{i}|c)
P(xi∣c)是可以根据训练集得到的,
P
(
x
)
P(\mathbf{x})
P(x)没有用不需要考虑,
P
(
c
)
P(c)
P(c)也可以得到。所以朴素贝叶斯就根据这些概率,对新数据进行预测,得到最大的
P
(
c
∣
x
)
P(c|\mathbf{x} )
P(c∣x)就将其判别为c类,即
h
n
b
(
x
)
=
a
r
g
m
a
x
P
(
c
)
∏
i
=
1
d
P
(
x
i
∣
c
)
h_{nb}(\mathbf{x} ) = argmax P(c)\prod_{i=1}^{d}P(x_{i}|c)
hnb(x)=argmaxP(c)∏i=1dP(xi∣c)
总之朴素贝叶斯就是先把各种概率算出来然后带进去算出最大的概率
代码中已经给出了词袋模型对数据进行预处理的方法。所以要做的工作就是批量对50个txt文本进行处理,生成词袋模型向量,计算概率,进行预测。只粘贴核心代码算了,不想再多按几次cv了
def spamtest(): dataset = [] # 文档向量的集合 classlist = [] # 类标签列表 errorindex = [] for i in range(1, 26): # i取值1-25,是因为每个文件夹的文件名为1-25 # 交叉放入向量集合 listoftokens = textParse(open('./ham/{}.txt'.format(str(i)), 'r').read()) # 23.txt中®符号无法被gbk编码读取,直接用空格代替 dataset.append(listoftokens) classlist.append(1) listoftokens = textParse(open('./spam/{}.txt'.format(str(i)), 'r').read()) dataset.append(listoftokens) classlist.append(0) vocablist = createVocabList(dataset) # print(vocablist) file = open('vocablist.txt', 'wb') pickle.dump(vocablist, file) file.close() train_indexset = list(range(50)) test_indexset = [] for i in range(10): # 从训练集里随机删掉10个放到测试集 ranindex = np.random.randint(0, len(train_indexset)) test_indexset.append(train_indexset[ranindex]) del train_indexset[ranindex] train_mat = [] train_class = [] for index in train_indexset: train_mat.append(bagOfWords2VecMN(vocablist, dataset[index])) train_class.append(classlist[index]) px_c0, px_c1, pc1 = train(train_mat, train_class) file = open('threerate.txt', 'wb') pickle.dump([px_c0, px_c1, pc1], file) file.close() errorcount = 0 for testindex in test_indexset: test_mat = bagOfWords2VecMN(vocablist, dataset[testindex]) if classify(test_mat, px_c0, px_c1, pc1) != classlist[testindex]: errorcount += 1 errorindex.append(testindex) return errorcount/len(test_indexset), set(errorindex)
def train(train_mat, train_class): textnum = len(train_mat) wordnum = len(train_mat[0]) # print(train_class) pc1 = sum(train_class) / textnum # 初始化时,分子分母都已经有了1和2,这样做是拉普拉斯修正的方法,防止缺失值的影响 p0num = np.ones(wordnum) p1num = np.ones(wordnum) p0demo = 2 p1demo = 2 for i in range(textnum): if train_class[i] == 1: p1num += train_mat[i] p1demo += sum(train_mat[i]) else: p0num += train_mat[i] p0demo += sum(train_mat[i]) # 条件概率的计算,用log防止溢出 px_c1 = np.log(p1num/p1demo) px_c0 = np.log(p0num/p0demo) return px_c0, px_c1, pc1
def classify(testset, px_c0, px_c1, pc1):
# 这里计算用testset * px_c 的原因是,testset是一个向量,这个向量为单词出现的次数,如果单词没有出现则为0
p1 = sum(testset * px_c1) + np.log(pc1)
p0 = sum(testset * px_c0) + np.log(1-pc1)
if p1 > p0:
return 1
else:
return 0
任务二更加简单,只需要算概率,然后预测就好了。因为数据集文件比较大,可以考虑用pickle库把某些关键性而且很大的东西序列化保存下来,下次再运行的时候就快很多了。
贴一下核心代码
def train(train_mat, trainlabels):
train_class = trainlabels[:]
imgnum = len(train_mat)
matlen = len(train_mat[0])
pinum = np.ones((10, matlen))
pidemo = np.ones(10) * 2
px_c = np.zeros((10, matlen))
for i in range(imgnum):
pinum[train_class[i]] += train_mat[i]
pidemo[train_class[i]] += sum(train_mat[i])
for i in range(10):
px_c[i] = np.log(pinum[i]/pidemo[i])
return px_c
def classify(testset, px_c, log_pc):
pi = [0] * 10
for i in range(10):
pi[i] = sum(testset * px_c[i]) + log_pc[i]
# pi = list(pi)
return pi.index(max(pi))
直接用任务一的代码就好了=_=
贝叶斯网络学的时候我就感觉有点像马尔可夫,还是有点意思的东西,虽然编程作业没有做,但是手写作业做了,考试也考了,值得学一下了解了解
一晚上又被我浪费完了。。。本来写这个应该不会花很多时间的。。。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。