文章目录
注:转载请标明原文出处链接:https://xiongyiming.blog.csdn.net/article/details/96833174
1 朴素贝叶斯简介
贝叶斯分类算法是统计学的一种概率分类方法,朴素贝叶斯(Naive Bayesian)分类是贝叶斯分类中最简单的一种。其分类原理就是利用贝叶斯公式根据某特征的先验概率计算出其后验概率,然后选择具有最大后验概率的类作为该特征所属的类。之所以称之为”朴素”,是因为贝叶斯分类只做最原始、最简单的假设:所有的特征之间是统计独立的。
2 条件概率与全概率公式
条件概率(conditional probability),指在已知事件B发生的情况下,事件A发生的概率,用 P ( A ∣ B ) P(\left. A \right|B) P(A∣B)来表示。
根据上图可知:在已知事件B发生的情况下,事件A发生的概率就是
P
(
A
∩
B
)
P(A \cap B)
P(A∩B)除以
P
(
B
)
P(B)
P(B)。
(1)
P
(
A
∣
B
)
=
P
(
A
∩
B
)
P
(
B
)
P(\left. A \right|B) = {{P(A \cap B)} \over {P(B)}} \tag{1}
P(A∣B)=P(B)P(A∩B)(1)
(2)
P
(
A
∩
B
)
=
P
(
A
∣
B
)
P
(
B
)
P(A \cap B) = P(\left. A \right|B)P(B) \tag{2}
P(A∩B)=P(A∣B)P(B)(2)同理可得:
(3)
P
(
A
∩
B
)
=
P
(
B
∣
A
)
P
(
A
)
P(A \cap B) = P(\left. B \right|A)P(A) \tag{3}
P(A∩B)=P(B∣A)P(A)(3)则
(4)
P
(
A
∣
B
)
P
(
B
)
=
P
(
B
∣
A
)
P
(
A
)
P(\left. A \right|B)P(B) = P(\left. B \right|A)P(A) \tag{4}
P(A∣B)P(B)=P(B∣A)P(A)(4)
(5)
P
(
A
∣
B
)
=
P
(
B
∣
A
)
P
(
A
)
P
(
B
)
P(\left. A \right|B) = {{P(\left. B \right|A)P(A)} \over {P(B)}} \tag{5}
P(A∣B)=P(B)P(B∣A)P(A)(5)
对于全概率公式,如果事件
{
A
1
,
A
2
,
…
,
A
n
}
\left\{ {{A_1},{A_2}, \ldots ,{A_n}} \right\}
{A1,A2,…,An}构成一个完备事件且都有正概率,那么对于任意一个事件B则有:
(6)
P
(
B
)
=
P
(
B
A
1
)
+
P
(
B
A
2
)
+
…
+
P
(
B
A
n
)
=
P
(
B
∣
A
1
)
P
(
A
1
)
+
P
(
B
∣
A
2
)
P
(
A
2
)
+
…
+
P
(
B
∣
A
n
)
P
(
A
n
)
P(B) = P(B{A_1}) + P(B{A_2}) + \ldots + P(B{A_n}) = P(\left. B \right|{A_1})P({A_1}) + P(\left. B \right|{A_2})P({A_2}) + \ldots + P(\left. B \right|{A_n})P({A_n}) \tag{6}
P(B)=P(BA1)+P(BA2)+…+P(BAn)=P(B∣A1)P(A1)+P(B∣A2)P(A2)+…+P(B∣An)P(An)(6) 则有
(7)
P
(
B
)
=
∑
i
=
1
n
P
(
B
∣
A
i
)
P
(
A
i
)
P(B) = \sum\limits_{i = 1}^n {P(\left. B \right|{A_i})P({A_i})} \tag{7}
P(B)=i=1∑nP(B∣Ai)P(Ai)(7)
3 贝叶斯推断
根据条件概率和全概率公式,可以得到贝叶斯公式如下
(8)
P
(
A
∣
B
)
=
P
(
A
)
P
(
B
∣
A
)
P
(
B
)
P(\left. A \right|B) = P(A){{P(\left. B \right|A)} \over {P(B)}} \tag{8}
P(A∣B)=P(A)P(B)P(B∣A)(8)
(9)
P
(
A
i
∣
B
)
=
P
(
A
i
)
P
(
B
∣
A
i
)
∑
i
=
1
n
P
(
B
∣
A
i
)
P
(
A
i
)
P(\left. {{A_i}} \right|B) = P({A_i}){{P(\left. B \right|{A_i})} \over {\sum\nolimits_{i = 1}^n {P(\left. B \right|{A_i})P({A_i})} }} \tag{9}
P(Ai∣B)=P(Ai)∑i=1nP(B∣Ai)P(Ai)P(B∣Ai)(9)
P
(
A
)
P(A)
P(A) 称为先验概率(prior probability),即在B事件发生之前,我们对A事件概率的一个判断;
P
(
A
∣
B
)
P(\left. A \right|B)
P(A∣B) 称为后验概率(posterior probability),即在B事件发生之后,我们对A事件概率的重新评估;
P
(
B
∣
A
)
/
P
(
B
)
P(\left. B \right|A)/P(B)
P(B∣A)/P(B) 称为可能性函数(Likely hood),这是一个调整因子,使得预估概率更接近真实概率。
所以条件概率可以理解为:后验概率 = 先验概率 × 调整因子
如果"可能性函数">1,意味着"先验概率"被增强,事件A的发生的可能性变大;
如果"可能性函数"=1,意味着B事件无助于判断事件A的可能性;
如果"可能性函数"<1,意味着"先验概率"被削弱,事件A的可能性变小。
4 引例
下面举一个例子来说明朴素贝叶斯,如下表所示的是嫁/不嫁 的二分类问题,最终嫁不嫁有前面几个属性(颜值,性格,上进否)来决定,那么现在给出一个不知道标签的样本(某个男生属性:帅 性格不好,不上进)求女生看到该男生 嫁还是不嫁? 概率又是如何?
根据贝叶斯公式
P
(
A
∣
B
)
=
P
(
A
)
P
(
B
∣
A
)
P
(
B
)
P(\left. A \right|B) = P(A){{P(\left. B \right|A)} \over {P(B)}}
P(A∣B)=P(A)P(B)P(B∣A) 我们将上述的问题转化成任务的表达式
按照朴素贝叶斯的求解,我们的任务可以转换为计算
计算出上面的概率就可以得出结果嫁还是不嫁。
根据贝叶斯公式可知
分母的计算用到的是全概率公式:
P
(
B
)
=
∑
i
=
1
n
P
(
B
∣
A
i
)
P
(
A
i
)
P(B) = \sum\limits_{i = 1}^n {P(\left. B \right|{A_i})P({A_i})}
P(B)=i=1∑nP(B∣Ai)P(Ai)
则
由表中的数据计算可以得到:
对于类别“嫁”的贝叶斯分子为:
对于类别“不嫁”的贝叶斯分子为:
最终结果为:
不嫁(60%) > 嫁( 40%),则该女生选择不嫁。
5 朴素贝叶斯算法分类
在scikit-learn中,一共有3个朴素贝叶斯的分类算法。分别是GaussianNB,MultinomialNB和BernoulliNB。
(1) GaussianNB
GaussianNB就是先验为高斯分布(正态分布)的朴素贝叶斯,假设每个标签的数据都服从简单的正态分布。
(10)
P
(
X
j
=
x
j
∣
Y
=
C
k
)
=
1
2
π
σ
k
2
exp
(
−
(
x
j
−
μ
k
)
2
2
σ
k
2
)
P(\left. {{X_j} = {x_j}} \right|Y = {C_k}) = {1 \over {\sqrt {2\pi \sigma _k^2} }}\exp \left( { - {{{{({x_j} - {\mu _k})}^2}} \over {2\sigma _k^2}}} \right) \tag{10}
P(Xj=xj∣Y=Ck)=2πσk21exp(−2σk2(xj−μk)2)(10)
其中 C k {C_k} Ck为 Y Y Y的第 k k k类的类别。 μ k {\mu _k} μk和 σ k 2 \sigma _k^2 σk2为需要从训练集估计的值。
下面用scikit-learn简单实现一下GaussianNB
#导入包
from numpy import *
import pandas as pd
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
#导入数据集
from sklearn import datasets
iris=datasets.load_iris()
#切分数据集
# train_data:被划分的样本特征集
# train_target:被划分的样本标签
# test_size:如果是浮点数,在0-1之间,表示样本占比;如果是整数的话就是样本的数量
# random_state:是随机数的种子。
# 随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。
# 但填0或不填,每次都会不一样。
# 随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:
# 种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。
Xtrain, Xtest, ytrain, ytest = train_test_split(iris.data,iris.target,random_state=12)
print("Xtrain=",Xtrain)
print("ytrain=",ytrain)
print("Xtest=",Xtest)
print("ytest=",ytest)
# GaussianNB 建模
clf = GaussianNB()
clf.fit(Xtrain, ytrain)
#在测试集上执行预测,proba导出的是每个样本属于某类的概率
clf.predict(Xtest) # 预测样本的分类
clf.predict_proba(Xtest) # 预测样本对应类别的概率
#测试准确率
predict_accuracy=accuracy_score(ytest, clf.predict(Xtest))
print("predict_accuracy=",predict_accuracy)
运行结果
(2) MultinomialNB
MultinomialNB就是先验为多项式分布的朴素贝叶斯。它假设特征是由一个简单多项式分布生成的。多项分布可以描述各种类型样本出现次数的概率,因此多项式朴素贝叶斯非常适合用于描述出现次数或者出现次数比例的特征。
该模型常用于文本分类,特征表示的是次数,例如某个词语的出现次数。
多项式分布公式如下:
(11)
P
(
X
j
=
x
j
l
∣
Y
=
C
k
)
=
x
j
l
+
λ
m
k
+
n
λ
P(\left. {{X_j} = {x_{jl}}} \right|Y = {C_k}) = {{{x_{jl}} + \lambda } \over {{m_k} + n\lambda }} \tag{11}
P(Xj=xjl∣Y=Ck)=mk+nλxjl+λ(11) 其中,
P
(
X
j
=
x
j
l
∣
Y
=
C
k
)
P(\left. {{X_j} = {x_{jl}}} \right|Y = {C_k})
P(Xj=xjl∣Y=Ck)是第
k
k
k个类别的第j维特征的第l个取值条件概率。
m
k
{m_k}
mk是训练集中输出为第
k
k
k类的样本个数。
λ
\lambda
λ为一个大于0的常数,
λ
\lambda
λ通常取1,即为拉普拉斯平滑。
(3) BernoulliNB
BernoulliNB就是先验为伯努利分布的朴素贝叶斯。假设特征的先验概率为二元伯努利分布,即如下式:
(12)
P
(
X
j
=
x
j
l
∣
Y
=
C
k
)
=
P
(
j
∣
Y
=
C
k
)
x
j
l
+
(
1
−
P
(
j
∣
Y
=
C
k
)
(
1
−
x
j
l
)
)
P(\left. {{X_j} = {x_{jl}}} \right|Y = {C_k}) = P(\left. j \right|Y = {C_k}){x_{jl}} + \left( {1 - P(\left. j \right|Y = {C_k})\left( {1 - {x_{jl}}} \right)} \right) \tag{12}
P(Xj=xjl∣Y=Ck)=P(j∣Y=Ck)xjl+(1−P(j∣Y=Ck)(1−xjl))(12)
其中,
l
l
l只有两种取值,
x
j
l
{x_{jl}}
xjl只能取值为0或1。
在伯努利模型中,每个特征的取值是布尔型的,即true和false,或者1和0。在文本分类中,就是一个特征有没有在一个文档中出现。
一般来说:
- 如果样本特征的分布大部分是连续值,使用GaussianNB会比较好;
- 如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适;
- 如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。
6 朴素贝叶斯算法优缺点
优点:在数据少的情况下仍然有效,可以处理多类别问题
缺点:对于输入数据的准备方式较为敏感;
适用数据类型:标称型数据。
7 实验
7.1 鸢尾花分类实验
应用GaussianNB对鸢尾花数据集进行分类。
1 导入数据集
2 切分训练集和测试集
3 构建高斯朴素贝叶斯分类器
4 测试模型预测效果
#导入包
import numpy as np
import pandas as pd
import random
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import random
# 1导入数据集
from sklearn import datasets
dataSet =pd.read_csv('iris.txt',header = None)
dataSet.head()
print("dataSet.shape=",dataSet.shape)
# 2切分训练集和测试集
import random
"""
randSplit函数功能:随机切分训练集和测试集
参数说明:
dataSet:输入的数据集
rate:训练集所占比例
返回:切分好的训练集和测试集
"""
def randSplit(dataSet, rate):
l = list(dataSet.index) #提取出索引
random.shuffle(l) #随机打乱索引
dataSet.index = l #将打乱后的索引重新赋值给原数据集
n = dataSet.shape[0] #总行数
m = int(n * rate) #训练集的数量
train = dataSet.loc[range(m), :] #提取前m个记录作为训练集
test = dataSet.loc[range(m, n), :] #剩下的作为测试集
dataSet.index = range(dataSet.shape[0]) #更新原数据集的索引
test.index = range(test.shape[0]) #更新测试集的索引
return train, test
train,test= randSplit(dataSet, 0.8)
print("train.shape=",train.shape)
print("test.shape=",test.shape)
# 3构建高斯朴素贝叶斯分类器
def gnb_classify(train,test):
labels = train.iloc[:,-1].value_counts().index #提取训练集的标签种类
mean =[] #存放每个类别的均值
std =[] #存放每个类别的方差
result = [] #存放测试集的预测结果
for i in labels:
item = train.loc[train.iloc[:, -1] == i, :] # 分别提取出每一种类别
m = item.iloc[:, :-1].mean() # 当前类别的平均值
s = np.sum((item.iloc[:, :-1] - m) ** 2) / (item.shape[0]) # 当前类别的方差
mean.append(m) # 将当前类别的平均值追加至列表
std.append(s) # 将当前类别的方差追加至列表
means = pd.DataFrame(mean, index=labels) # 变成DF格式,索引为类标签
stds = pd.DataFrame(std, index=labels) # 变成DF格式,索引为类标签
for j in range(test.shape[0]):
iset = test.iloc[j, :-1].tolist() # 当前测试实例
iprob = np.exp(-1 * (iset - means) ** 2 / (stds * 2)) / (np.sqrt(2 * np.pi * stds)) # 正态分布公式
prob = 1 # 初始化当前实例总概率
for k in range(test.shape[1] - 1): # 遍历每个特征
prob *= iprob[k] # 特征概率之积即为当前实例概率
cla = prob.index[np.argmax(prob.values)] # 返回最大概率的类别
result.append(cla)
test['predict'] = result
acc = (test.iloc[:, -1] == test.iloc[:, -2]).mean() # 计算预测准确率
print(f'模型预测准确率为{acc}')
return test
# 4. 测试模型预测效果
# 将切分好的训练集和测试集带入模型,查看模型预测结果
# 运行10次查看预测效果
for i in range(10):
train,test= randSplit(dataSet, 0.8)
gnb_classify(train,test)
运行结果
7.2 文档分类实验
朴素贝叶斯一个很重要的应用就是文本分类,所以我们以在线社区留言为例。为了不影响社区的发展,我们要屏蔽侮辱性的言论,所以要构建一个快速过滤器,如果某条留言使用了负面或者侮辱性的语言,那么就将该留言标志为内容不当。过滤这类内容是一个很常见的需求。对此问题建立两个类型:侮辱类和非侮辱类,使用1和0分别表示。
我们把文本看成单词向量或者词条向量,也就是说将句子转换为向量。考虑出现所有文档中的单词,再决定将哪些单词纳入词汇表或者说所要的词汇集合,然后必须要将每一篇文档转换为词汇表上的向量。简单起见,我们先假设已经将本文切分完毕,存放到列表中,并对词汇向量进行分类标注。
所用到的函数
loadDataSet:创建实验数据集
createVocabList:生成词汇表
setOfWords2Vec:生成词向量
get_trainMat:所有词条向量列表
trainNB:朴素贝叶斯分类器训练函数
classifyNB:朴素贝叶斯分类器分类函数
testingNB:朴素贝叶斯测试函数
from numpy import *
def loadDataSet():
postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0,1,0,1,0,1] #1 is abusive, 0 not
return postingList,classVec
def createVocabList(dataSet):
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) #union of the two sets
return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else: print ("the word: %s is not in my Vocabulary!" % word)
return returnVec
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = ones(numWords); p1Num = ones(numWords) #change to ones()
p0Denom = 2.0; p1Denom = 2.0 #change to 2.0
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = log(p1Num/p1Denom) #change to log()
p0Vect = log(p0Num/p0Denom) #change to log()
return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + log(pClass1) #element-wise mult
p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
def bagOfWords2VecMN(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] += 1
return returnVec
def testingNB():
listOPosts,listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses))
testEntry = ['love', 'my', 'dalmation']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid', 'garbage']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
def textParse(bigString): #input is big string, #output is word list
import re
listOfTokens = re.split(r'\W*', bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
def spamTest():
docList=[]; classList = []; fullText =[]
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(1)
wordList = textParse(open('email/ham/%d.txt' % i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)#create vocabulary
trainingSet = range(50); testSet=[] #create test set
for i in range(10):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]; trainClasses = []
for docIndex in trainingSet:#train the classifier (get probs) trainNB0
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet: #classify the remaining items
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1
print ("classification error",docList[docIndex])
print ('the error rate is: ',float(errorCount)/len(testSet))
#return vocabList,fullText
def calcMostFreq(vocabList,fullText):
import operator
freqDict = {}
for token in vocabList:
freqDict[token]=fullText.count(token)
sortedFreq = sorted(freqDict.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedFreq[:30]
def localWords(feed1,feed0):
import feedparser
docList=[]; classList = []; fullText =[]
minLen = min(len(feed1['entries']),len(feed0['entries']))
for i in range(minLen):
wordList = textParse(feed1['entries'][i]['summary'])
docList.append(wordList)
fullText.extend(wordList)
classList.append(1) #NY is class 1
wordList = textParse(feed0['entries'][i]['summary'])
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)#create vocabulary
top30Words = calcMostFreq(vocabList,fullText) #remove top 30 words
for pairW in top30Words:
if pairW[0] in vocabList: vocabList.remove(pairW[0])
trainingSet = range(2*minLen); testSet=[] #create test set
for i in range(20):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
trainMat=[]; trainClasses = []
for docIndex in trainingSet:#train the classifier (get probs) trainNB0
trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam = trainNB0(array(trainMat),array(trainClasses))
errorCount = 0
for docIndex in testSet: #classify the remaining items
wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount += 1
print ('the error rate is: ',float(errorCount)/len(testSet))
return vocabList,p0V,p1V
def getTopWords(ny,sf):
import operator
vocabList,p0V,p1V=localWords(ny,sf)
topNY=[]; topSF=[]
for i in range(len(p0V)):
if p0V[i] > -6.0 : topSF.append((vocabList[i],p0V[i]))
if p1V[i] > -6.0 : topNY.append((vocabList[i],p1V[i]))
sortedSF = sorted(topSF, key=lambda pair: pair[1], reverse=True)
print ("SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**")
for item in sortedSF:
print (item[0])
sortedNY = sorted(topNY, key=lambda pair: pair[1], reverse=True)
print ("NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**")
for item in sortedNY:
print (item[0])
from numpy import *
import bayes
# 所用到的函数
# loadDataSet:创建实验数据集
# createVocabList:生成词汇表
# setOfWords2Vec:生成词向量
# get_trainMat:所有词条向量列表
# trainNB:朴素贝叶斯分类器训练函数
# classifyNB:朴素贝叶斯分类器分类函数
# testingNB:朴素贝叶斯测试函数
# 导入数据
listOposts, listClass=bayes.loadDataSet()
print(listOposts)
myVocabList=bayes.createVocabList(listOposts)
print(myVocabList)
# 训练数据
trainMat=[]
for postinDoc in listOposts:
trainMat.append(bayes.setOfWords2Vec(myVocabList, postinDoc))
# p0V:非侮辱类的条件概率数组
# p1V:侮辱类的条件概率数组
# pAb:文档属于侮辱类的概率
p0V, p1V, pAb=bayes.trainNB0(trainMat,listClass)
print(p0V)
print(p1V)
print(pAb)
# 测试
bayes.testingNB()
运行结果
参考资料
[1] 机器学习实战. 人民邮电出版社.
[2] 机器学习, 北京: 清华大学出版社, 2016年1月
[3] 机器学习(西瓜书). 公式推导解析
[4] https://live.bilibili.com/14988341