朴素贝叶斯原理及python实现
朴素贝叶斯原理及python实现
朴素贝叶斯原理
如果你压根不知道贝叶斯是啥,建议你先读读如何理解贝叶斯以便更好地读懂本文。
朴素贝叶斯在分类问题中有很广泛的应用。具体是如何应用的呢?
老祖宗贝叶斯公式给出了答案—事件A发生了,是由事件B造成的概率为:
对于我们实际的问题:
给定数据集,其中为特征,为特征对应的标签,标签的取值集合为;这样的数据集通常是已知的,一个或一连串的特征对应一个标签,在大量的可观测的已知数据(训练集)给出后,突然来一个或好多数据(测试集),我们想知道这些未知应该属于哪个类,即:
(在为的条件下,为的概率)— 我们观测到了某个数据的特征,而且还知道了该数据属于每个类别的概率,我们只要找到最有可能(概率最大)属于的类别不就是这个数据的分类了?
那么问题来了,怎么算呢?— 套贝叶斯公式:
在已知数据集给出后,先验概率—的标签为的概率是很容易得到的(每个标签的总数除以总的标签数),但呢?
现实还是很骨感,这可是指数级数量的参数啊!怎么办???
我们可以假设特征是独立的,即每个特征之间互不影响,互相独立。这个假设也有点太强吧。对!就是这么强!这也是朴素贝叶斯的朴素之处。基于条件独立假设,我们刚刚的条件概率就可以表示为:
OK,现在先验概率和条件概率都有了,我们只需要将它带入中即可,带入得到:
终于算出来了,现在给定特征,我们就可以找到它最有可能属于哪个类了,我们只需要把属于每个类的概率算一下,然后找到概率最大的那个就可以了。
总结一下:
给定训练集和测试集,先提取特征,然后计算先验概率和条件概率。之后对于给定测试数据,计算一下属于每个类别的概率,然后返回概率最大的那个标签就完成了预测或分类。
朴素贝叶斯的python实现
实验数据用的是李航老师《统计学习方法》里的数据,当然,上面的很多东西参考了该书。
训练数据:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | |
S | M | M | S | S | S | M | M | L | L | L | M | M | L | L | |
-1 | -1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 |
测试数据:
给定输入第一个特征为,第二个特征为
实验结果:
预测结果为
import numpy as np
def judge(actual,prediction):
'''
该函数用于判断实际值和预测值是否一致
:param actual: 实际值
:param prediction: 预测值
:return: 如果实际值和预测值一致,返回为True,否则返回False
'''
return actual==prediction
def generate_data():
'''
该函数用于生成数据
:return: 生成好的数据,特征对应于标签
'''
feature=[(1,'S'),(1,'M'),(1,'M'),(1,'S'),(1,'S'),
(2,'S'),(2,'M'),(2,'M'),(2,'L'),(2,'L'),
(3,'L'),(3,'M'),(3,'M'),(3,'L'),(3,'L')]
label=[-1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1]
return feature,label
class bayes:
### bayes类,用于bayes相关
def transform(self,feature):
'''
对原始输入的特征进行相应的转换,以更好地进行模型训练
:param feature: 需要转换的特征
:return: 转换后的特征
'''
fea_transform=[]
for seq in feature:
for i in range(seq.__len__()):
try:
fea_transform[i].append(seq[i])
except:
fea_transform.append([])
fea_transform[i].append(seq[i])
return fea_transform
def train(self,feature,label):
'''
训练函数
:param feature: 特征集
:param label: 标签集
:return: 训练好的模型(相应的条件概率和先验概率)
'''
feature=np.array(self.transform(feature))
label=np.array(label)
classifier=set(label)
probability_classifier={}
probability_feature={}
feature_record={}
### 计算先验概率
for i in classifier:
probability_classifier[i]=label.tolist().count(i)/label.__len__()
for fea in range(feature.__len__()):
feature_record[fea]=set(feature[fea])
### 计算条件概率
for fea in range(feature.__len__()):
for f in feature_record[fea]:
for c in classifier:
position= np.where(label==c)### 找到分类为 c 的那些位置
numerator=feature[fea][position][feature[fea][position]==f].__len__()### 找到类别为 c,同时该特征为 f 的元素个数
denominator=feature[fea][label==c].__len__()
try:
probability_feature[(fea,c)][f]=numerator/denominator
except:
probability_feature[(fea,c)]={}
probability_feature[(fea,c)][f]=numerator/denominator
return probability_feature,probability_classifier
def predict(self,actual,model):
'''
预测函数
:param actual: 想要预测的实际值
:param model: 训练好的模型
:return: 预测结果
'''
actual=np.array(actual)
probability_feature,probability_classifier=model
prediction={}
for classifier in probability_classifier:
multi=1
for i in range(actual.__len__()):
multi*=probability_feature[(i,classifier)][actual[i]]
prediction[classifier]=probability_classifier[classifier]*multi
return max(prediction,key=prediction.get)
if __name__ == '__main__':
feature,label=generate_data()
bayes=bayes()
model=bayes.train(feature,label)
print("预测结果为:",bayes.predict([1,"S"],model))
运行结果:
才疏学浅,难免有错误和不当之处,欢迎交流批评指正!
同时有问题的话欢迎留言或邮箱联系(aaa@qq.com)。
Reference:
李航.《统计学习方法》[M].2012.3.北京:清华大学出版社,2019.5(重印):14-15.