一、数据集

我们有以下数据集,来记录15个西瓜的特征,其中,特征变量x1表示西瓜的某个特征,比如颜色特征:1表示青绿;2表示乌黑;3表示浅白;#特征变量x2用字符串表示西瓜的尺寸特征,'S’表示小,'M’表示中等,'L’表示大个;y表示西瓜的品质标签,1表示好瓜,-1表示坏瓜。
在这里插入图片描述

二、贝叶斯公式

我们可以使用贝叶斯公式来实现朴素贝叶斯分类器,并且输入新的样本数据,用来预测新样本的品质标签y。贝叶斯公式如下,里面有很多术语,在后面我会依次解释:
在这里插入图片描述

三、类先验概率(CPP)

我们可以通过(统计)计数的方法,来获得类先验 P ( c ) P(c) P(c)的概率分布如下:

在这里插入图片描述
从中可以,看出,好瓜类的比例是0.6,坏瓜类的比例是0.4。这个表其实就是类先验概率分布表ClassPriorProbability(CPP)。

四、预测先验概率(PPP)

同样的,我们也可以对x1/x2特征进行统计,得到预测子先验概率分布Predictor Prior Probability(PPP)如下:
在这里插入图片描述
在这里插入图片描述
从三、四两小节可以看到,先验概率其实是就是概率分布,只不过频率学派是基于大数据统计的,而贝叶斯学派是基于知识假设或者主观的。

五、似然(Likelyhood)

似然本质上是一种条件概率,表示在一个变量给定的情况下,另外一个随机变量出现的概率分布,比如本例中,我们就可以先给定类别的值y,先后给-1或者1,然后统计在这样的前提条件下两个特征x1、x2的概率分布,我们可以从下表直观地感受到似然概率的分布。
在这里插入图片描述
值得注意的是,PPP可以通过全概率公式,由似然表获得,全概率公式如下所示。
在这里插入图片描述

六、后验概率(Posterior Probablity)

后验概率其实就是我们最终的目标,也就是根据看到的特征来预测分类。我们可以通过以下的python代码来写一个NaiveBayes的类(class),训练给定的数据之后得到概率分布,然后用来进行预测。

基于简单的西瓜数据集,使用Bayes分类器对西瓜进行分类,直接上代码,具体的解释在代码中都注释了,特别要注意的是,这里的特征有多个,所以在计算的时候要考虑各个维度。因为我们认为各个维度之间是独立的,所以直接相乘就可以了,所以叫做朴素贝叶斯。

import numpy as np
import pandas as pd

class NaiveBayes():
	def __init__(self,X,y):
		self.X = X
		self.y = y
		self.N = len(y)
	def nb_fit(self,X,y):
		print('西瓜数据集如下所示:')
		print(X.join(y))
		#通过unique方法来提取分类的种类
		#在这个案例中,y只有两类1和-1,在其他的案例中,可能会有多分类标签
		classes = y[y.columns[0]].unique()
		#通过.counts函数来进行计数,求出每个类别出现的个数(即总数)
		class_count = y[y.columns[0]].value_counts()
		#通过计算每个类别中个数和综述的比例,就可以得到类先验(cpp)了
		#从此可以看出来,这个频率其实是训练样本中的频率
		#或者是说可以用来学习的数据的统计特征,或者叫做知识积累
		class_prior = class_count/self.N
		print(f'类(y)先验概率如下:\n{class_prior}')
		x1_count = X[X.columns[0]].value_counts()
		x2_count = X[X.columns[1]].value_counts()
		x1_class_prior = x1_count/self.N
		x2_class_prior = x2_count/self.N
		print('特征x1(颜色)的先验概率分布为:')
		print(x1_class_prior)
		print('特征x2(尺寸)的先验概率分布为:')
		print(x2_class_prior)
		x_prior = [x1_class_prior,x2_class_prior]
		prior = dict()
		#p_x_y表示联合概率分布,也就是每个(x,y)数据对出现的频率
		#根据联合概率,可以求出先验prior分布
		for col in X.columns:
			for j in classes:
				p_x_y = X[(y==j).values][col].value_counts()
				for i in p_x_y.index:
					prior[(col,i,j)] = p_x_y[i]/class_count[j]
		# print(f'有以下几个类:\n{classes}')
		# print(f'类先验概率如下:\n{class_prior}')
		print(prior)
		print(f'似然概率表如下:')
		print('   val  y   prob')	
		for i in prior:
			print(f'{i[0]:4}{i[1]:}{i[2]:4} : {prior[i]:<5.2}')	
		return classes,class_prior,prior,x_prior

	def predict(self,X_test):
		res = []
		#利用nb_fit获得数据集的类先验信息
		classes, class_prior, prior, x_prior = self.nb_fit(self.X, self.y)
		# print(prior)
		# for p in prior:
		# 	print(p)
		for c in classes:
			#求出类先验分布,也就是好瓜和坏瓜的概率
			p_y = class_prior[c]
			#初始化联合概率p_x_y
			p_x_y = 1
			#遍历测试集中的数据
			for i in X_test.items():
				#i是一个元祖,先转换为列表,然后和c进行拼接之后再变回一个三维的元祖
				#这个元祖可以作为prior的索引得到联合概率,取这个概率的最大值的argmax就是预测分类
				index = tuple(list(i)+[c])
				#如果特征为x1即颜色,那么要除颜色概率
				if i[0]=='x1':
					p_x_y *= prior[index]/x_prior[0][i[1]]
				elif i[0]=='x2':
					p_x_y *= prior[index]/x_prior[1][i[1]]
			# res.append(p_y*p_x_y/(x_prior[0][]*x_prior[1][]))
			res.append(p_y*p_x_y)
		print(res)
		return classes[np.argmax(res)]

#特征变量x1表示西瓜的某个特征,比如颜色特征:1表示青绿;2表示乌黑;3表示浅白
x1 = [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]
#特征变量x2用字符串表示西瓜的尺寸特征,'S'表示小,'M'表示中等,'L'表示大个
x2 = ['S','M','M','S','S','S','M','M','L','L','L','M','M','L','L']
#标签变量y表示西瓜的分类,-1表示是坏瓜,1表示是好瓜
y = [-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]
df = pd.DataFrame({'x1':x1,'x2':x2,'y':y})
# print(df.head())
#使用dataframe的索引技术提取特征的两列至特征变量X,提取标签列至特征变量y
X = df[['x1','x2']]
y = df[['y']]
##nb_fit函数
##输入数据集的X和y,即特征向量矩阵和标签向量y
##输出该数据集的分类列表classes、类先验分布(CPP)class_prior、先验分布prior

#在利用predict函数对其进行预测
# predictor = predict(X_test)

nb = NaiveBayes(X,y)
#我们随机选取一组测试数据X_test
X_test = {'x1': 2, 'x2': 'S'}
print(nb.predict(X_test))

我们看到,最终我们在测试集中给出了新的样本

X_test = {'x1': 2, 'x2': 'S'}

运行后最终被模型判定为-1,也就是模型认为这个是坏瓜。

更多推荐