一、贝叶斯定理简介
人对某一事件未来会发生的认知,大多取决于该事件或类似事件过去发生的频率。这就是贝叶斯定理的数学模型,它最早由数学家托马斯·贝叶斯提出。
贝叶斯生活在18世纪,他是一位牧师。1763年,他发表了论文《论有关机遇问题的求解》,提出了一种解决问题的框架思路,即通过不断增加信息和经验,逐步逼近真相或理解未知。这种思想奠定了贝叶斯理论的基础。
贝叶斯定理的过程可以归纳为:“过去经验”加上“新的证据”得到“修正后的判断”。它提供了一种将新观察到的证据和已有的经验结合起来进行推断的客观方法。
二、贝叶斯定理
2.1基本概念
先验概率:在考虑任何新证据之前,对事件发生的概率的初始估计。这是根据以往的经验或先前的知识得出的概率。
后验概率:在考虑了新证据之后,对事件发生的概率的修正估计。这是通过将先验概率与新证据结合起来,使用贝叶斯定理得出的概率。
条件概率:表示事件A在另一个事件B已经发生的条件下发生的概率,通常写作P(A|B),读作“A在给定B的条件下发生的概率”。
2.2计算公式
假设有随机事件A和B,它们的条件概率关系可以用以下数学公式表达
其中,事件A是要考察的目标事件,P(A)是事件A的初始概率,称为先验概率,它是根据一些先前的观测或者经验得到的概率。
B是新出现的一个事件,它会影响事件A。P(B)表示事件B发生的概率。
P(B|A)表示当A发生时B的概率,它是一个条件概率。
P(A|B)表示当B发生时A的概率(也是条件概率),它是我们要计算的后验概率,指在得到一些观测信息后某事件发生的概率。
2.3理解与应用
过去没有大数据,所以先验概率很难获得。这些年来,很多数据被人们积累下来,贝叶斯模型的运用领域也越来越广泛。
比如在一些语言翻译的网站、医疗诊断的仪器中,就会用到贝叶斯的统计方法。还有在电子邮件软件中,也集成了基于贝叶斯方法的垃圾邮件过滤功能。
贝叶斯定理告诉我们,即便获得了新的证据,也不要完全放弃初始的信念。新的证据会让我们对某些结果更有信心,或帮助我们修正初始信念的错误。
也就是说,我们既要关注新的证据,又不能忽略初始信念。新的证据很重要,因为初始信念可能是错的,这些证据可以用于做出修正。但同时,初始信念仍然是重要的基础,不能只根据新证据就草率地做出判断。
贝叶斯定理的应用,包括但不限于:
医学诊断:在医学中,贝叶斯定理可用于确定疾病的风险和诊断结果的准确性。医生可以根据患者的症状和检测结果,结合先验知识和条件概率,计算出患某种疾病的后验概率,从而做出更准确的诊断。
机器学习:在机器学习中,贝叶斯定理通常用于概率图模型和贝叶斯推断。例如,在朴素贝叶斯分类器中,我们使用贝叶斯定理来计算给定特征的情况下某个类别的后验概率,从而对新数据进行分类。
自然语言处理:在自然语言处理中,贝叶斯定理可以用于文本分类、情感分析等任务。通过将先验概率与文本中的单词或短语的出现频率结合起来,可以推断出文本所属的类别或情感倾向。
信号处理:在通信和信号处理领域,贝叶斯推断可用于解决噪声干扰下的信号恢复和通信问题。通过考虑先验概率和观测数据,可以推断出信号的真实值。
金融领域:在金融领域,贝叶斯定理可用于风险管理、投资组合优化和预测金融市场趋势。通过结合历史数据和先验知识,可以更准确地估计资产的风险和收益。
搜索引擎:贝叶斯推断在搜索引擎中也有应用,例如用于个性化搜索结果排序和相关性评分的计算。通过考虑用户的历史搜索行为和网页内容的特征,可以提高搜索结果的准确性和用户满意度。
这些只是贝叶斯定理在各个领域中的一些应用示例,它在实际问题中的应用非常广泛,并且不断在不同领域中发现新的应用场景。
三、朴素贝叶斯公式
朴素贝叶斯分类器的原理基于贝叶斯定理,即根据已知类别的数据来估计特征与类别之间的概率分布,然后使用这些概率来对新样本进行分类。
朴素贝叶斯算法是假设各个特征之间相互独立,也是朴素这词的意思。那么贝叶斯公式中P(X|Y)可写成
P(X|Y)=P(x1|Y)∗P(x2|Y)∗P(x3|Y)⋯∗P(xi|Y)
𝑃
(
𝑋
|
𝑌
)
=
𝑃
(
𝑥
1
|
𝑌
)
∗
𝑃
(
𝑥
2
|
𝑌
)
∗
𝑃
(
𝑥
3
|
𝑌
)
⋯
∗
𝑃
(
𝑥
𝑖
|
𝑌
)
具体地,设特征向量为 X=(X1,X2,X3,⋅⋅⋅,Xi)
𝑋
=
(
𝑋
1
,
𝑋
2
,
𝑋
3
,
⋅
⋅
⋅
,
𝑋
𝑖
)
,类别集合为 Y={Y1,Y2,⋅⋅⋅,Yi}
𝑌
=
{
𝑌
1
,
𝑌
2
,
⋅
⋅
⋅
,
𝑌
𝑖
}
,我们的目标是计算在给定特征向量 X的条件下,属于每个类别的概率 P(xi|Y)
𝑃
(
𝑥
𝑖
|
𝑌
)
,然后选择具有最大后验概率的类别作为样本的分类结果。
朴素贝叶斯公式:
P(Y|X)=P(x1|Y)∗P(x2|Y)∗P(x3|Y)⋯∗P(xi|Y)∗P(Y)P(X)
𝑃(𝑌
|
𝑋
)
=
𝑃
(
𝑥
1
|
𝑌
)
∗
𝑃
(
𝑥
2
|
𝑌
)
∗
𝑃
(
𝑥
3
|
𝑌
)
⋯
∗
𝑃
(
𝑥
𝑖
|
𝑌
)
∗
𝑃
(
𝑌
)
𝑃
(
𝑋
)
其中P(Y)
𝑃
(
𝑌
)
是类别Y的先验概率,P(xi|Y)
𝑃
(
𝑥
𝑖
|
𝑌
)
是在类别 Y下特征向量 X 的条件概率,P(X) 是特征向量 X 的边缘概率。由于 P(X) 对所有类别都是相同的,因此可以忽略掉。
朴素贝叶斯实现步骤
统计样本数据。
计算先验概率。
计算条件概率。
根据待预测样本所包含的特征,对不同类分别进行后验概率计算。
将每个类别下计算得到的后验概率进行比较,选择具有最大后验概率的类别作为预测结果。
四、实现
4.1处理数据集
将数据集分割成数据训练集和测试集
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.lines as mlines
#定义属性值
outlook = ["晴朗", "多云","雨天"]
Temperature = ["高温", "中温","低温"]
Humidity = ["高湿","一般"]
Wind = ["大", "小"]
PlayTennis=["是","否"]
Play = []
Play.append(outlook)
Play.append(Temperature)
Play.append(Humidity)
Play.append(Wind)
Play.append(PlayTennis)
#数据集
data = [ ["晴朗","高温","高湿","小","否"],
["晴朗","高温","高湿","大","否"],
["多云","高温","高湿","小","是"],
["雨天","中温","高湿","小","是"],
["雨天","低温","一般","小","是"],
["雨天","低温","一般","大","否"],
["多云","低温","一般","大","是"],
["晴朗","中温","高湿","小","否"],
["晴朗","低温","一般","小","是"],
["雨天","中温","一般","小","是"],
["晴朗","中温","一般","大","是"],
["多云","中温","高湿","大","是"],
["晴朗","高温","一般","小","是"],
["多云", "高温", "一般", "小", "是"],
["雨天","中温","高湿","大","否"],
["晴朗","中温","高湿","大","否"]
]
length = len(data)
#划分数据集,将1-12条作为训练数据集,13-16作为测试数据集
train = data[:12]
print("训练数据集")
for i in range(len(train)):
print(train[i])
test= data[12:]
print("测试数据集")
for i in range(len(test)):
print(test[i])
结果:
这是分割后的数据集
4.2统计特征的总数量
计算特征的数量
def total(data):
count = {} # 初始化一个空字典,用于存储特征值的频次
for i in range(len(data)):
feature = data[i][4] # 获取当前样本的第五个特征值
# 检查特征值是否已经存在于字典中,如果不存在,则初始化计数为0
if feature not in count:
count[feature] = 0
# 将特征值对应的计数加1
count[feature] += 1
return count # 返回特征值及其对应的频次字典
print()
print(total(data))
print()
结果:
4.3计算先验概率
计算数据集中各个类别的先验概率。在计算先验概率时,采用了拉普拉斯平滑来避免概率为零的情况。最后,将各个类别的先验概率存储在字典 rates 中,并返回该字典。
# 计算先验概率
def rates(data):
y = total(data) # 统计各类别的样本数
rates = {} # 初始化字典,用于存储各类别的先验概率
for label in y.keys():
# 计算先验概率
priori_prob = (y[label] + 1) / (len(train) + 2)
rates[label] = priori_prob # 将先验概率存储到字典中
return rates # 返回各类别的先验概率字典
rate = rates(train) # 调用rates函数计算先验概率
print(rate) # 打印各类别的先验概率
4.4计算条件概率
通过特征值出现的次数和不同类别的各自的总次数,计算条件概率。
# 计算特征值出现的次数
def count_sj(a, Play):
for i in range(len(Play)):
if a in Play[i]:
return len(Play[i])
# 计算给定结果下各个特征值的似然概率(条件概率)
def likelihold_prob(data):
# 计算各个结果的频次
y = total(data)
likelihold = {} # 用于存储各个结果下特征值的似然概率
for i, c in y.items():
attr_prob = {} # 临时存储各个特征值的概率
# 遍历数据集
for j in range(len(data)):
# 如果样本的结果等于当前结果
if data[j][4] == i:
# 统计各个特征值出现的次数
for attr in range(4):
if data[j][attr] not in attr_prob:
attr_prob[data[j][attr]] = 0
attr_prob[data[j][attr]] += 1
# 计算似然概率
for keys, values in attr_prob.items():
# 计算sj,即在特征值出现的条件下,结果为当前结果的样本数量
sj = count_sj(keys, Play)
# 使用拉普拉斯平滑计算似然概率
attr_prob[keys] = (values + 1) / (c + sj)
likelihold[i] = attr_prob # 将结果添加到likelihold字典中
return likelihold # 返回各个结果下特征值的似然概率字典
# 调用likelihold_prob函数计算似然概率
likelihold = likelihold_prob(train)
# 输出结果为“否”的部分
print("结果为“否”的似然概率:")
for attr, prob in LikeHold['否'].items():
print(f"{attr}: {prob}")
# 输出结果为“是”的部分
print("\n结果为“是”的似然概率:")
for attr, prob in LikeHold['是'].items():
print(f"{attr}: {prob}")
结果:
4.5计算后验概率,并输出最好的标签
def bestL(prior_probabilities, likelihoods, instance):
# 初始化后验概率为1,防止出现0的情况
posterior_probabilities = {label: 1 for label in prior_probabilities}
# 计算后验概率
for label in prior_probabilities:
for feature in instance:
# 如果特征在该标签的似然概率中存在,则乘以该概率
if feature in likelihoods[label]:
posterior_probabilities[label] *= likelihoods[label][feature]
# 乘以先验概率
for label in prior_probabilities:
posterior_probabilities[label] *= prior_probabilities[label]
# 根据后验概率选择预测结果
predicted_label = max(posterior_probabilities, key=posterior_probabilities.get)
return predicted_label
# 测试
test1 = ['雨天', '低温', '一般', '小', '是']
print(bestL(rate, LikeHold, test1))
4.6预测
预测其实就是前面的计算先验概率、计算条件概率、计算后验概率选择最好标签的函数运用起来
def predict(data, test):
# 计算先验概率
prior_probabilities = cal_base_rates(data)
# 计算条件概率
likelihoods = likelihold_prob(data)
best_labels = []
# 对测试集中的每个实例进行预测
for instance in test:
# 获取当前实例的预测标签
predicted_label = bestL(prior_probabilities, likelihoods, instance)
# 将预测标签添加到结果列表中
best_labels.append(predicted_label)
return best_labels
# 测试
labels = predict(data, test)
print(labels)
结果:
由多个数据,显示出预测的结果
4.7模型评估
根据之前的代码做出来模型评估,在这就不描述了,其实发现每次的评估都很差,就蛮弄一下。
def CaculatePR(y_test, y_prep):
precision = [] # 存储的Precision值
recall = [] # 存储Recall值
y_score = np.array(y_prep) # 转换为NumPy数组
y_test2 = np.array(y_test) # 转换为NumPy数组
sorted_train_data = y_score.argsort()[::-1] # 将预测从高到低排序,返回索引
num_positives = np.sum(y_test2 == 1) # 统计样本中实际正例的数量
# 遍历每个样本
for i in range(len(y_test2)):
num_real = 0 # 用于计算当前的真实正例数量
num_guess = i + 1 # 当前的预测正例数量
# 在前i个样本中计算真实正例的数量
for j in range(0, i + 1):
index = sorted_train_data[j]
if y_test2[index] == 1: # 如果该样本为真实正例
num_real += 1 # 增加真实正例的数量
precision_value = float(num_real / num_guess) # 计算Precision
recall_value = float(num_real / num_positives) # 计算Recall
precision.append(precision_value) # 将Precision加入列表
recall.append(recall_value) # 将Recall加入列表
return precision, recall
def CaculateROC(y_test, y_preps):
fpr = [] # 存储的假正率
tpr = [] # 存储的真正率
y_prep = np.array(y_preps) # 转换为NumPy数组
y_test2 = np.array(y_test) # 转换为NumPy数组
sortedTraindata = y_prep.argsort()[::-1] # 将预测按照得分从高到低排序,返回索引
num_positives = np.sum(y_test2 == 1) # 统计样本中实际正例的数量
num_negatives = len(y_test2) - num_positives # 统计样本中实际负例的数量
# 遍历每个样本
for i in range(len(y_test2)):
tp = 0 # 用于统计真正例的数量
num_guess = i + 1 # 假设为真的数量
# 在前i个样本中计算真正例的数量
for j in range(0, i + 1):
a = sortedTraindata[j]
if y_test2[a] == 1:
tp += 1 # 如果预测为真实正例,则增加真正例的数量
fp = num_guess - tp # 计算假正例的数量
fpr_value = float(fp / num_negatives) # 计算假正率(FPR)
tpr_value = float(tp / num_positives) # 计算真正率(TPR)
fpr.append(fpr_value)
tpr.append(tpr_value)
return fpr, tpr
def transfrom(label):
list = [1 if value == '否' else 0 for value in label]
return list
features = ['天气','温度','湿度','风力']
label2=transfrom(label)
labels = [row[-1] for row in test]
print(labels)
label3=transfrom(labels)
precision, recall=CaculatePR(label3, label2)
pr_auc=np.trapz(precision, recall)
#plt.subplot(1,2,1)
plt.plot(precision, recall, lw=2, color='darkorange', label='PR curve (AUC = %0.2f)' % pr_auc)
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall curve')
plt.legend(loc="lower right")
plt.show()
fpr, tpr = CaculateROC(label3, label2)
roc_auc = np.trapz(fpr, tpr)
#plt.subplot(1,2,2)
plt.plot(fpr, tpr, color='red', lw=2, label='ROC (AUC = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc='lower right')
plt.show()
e/details/138707835
五、总结
5.1 朴素贝叶斯优缺点
优点:
对待预测样本进行预测,过程简单速度快
对于多分类问题也同样有效,复杂度也不会有大程度地上升。
在分布独立这个假设成立的情况下,贝叶斯的分类效果很好,会略胜于逻辑回归,我们需要的样本量也更少一点。
对于类别类的输入特征变量,效果非常好。对于数值型变量特征,我们默认它符合正态分布
缺点:
如果测试集中的一个类别变量特征在训练集里面没有出现过,那么概率就是0,预测功能就将失效,平滑技术可以解决这个问题
朴素贝叶斯中有分布独立的假设前提,但是在现实生活中,这个条件很难满足。
应用:
文本分类:朴素贝叶斯算法在文本分类领域具有广泛的应用,如垃圾邮件过滤、新闻分类、情感分析等。
情感分析:通过分析文本中的词汇和语法结构,朴素贝叶斯算法可以判断文本所表达的情感倾向,如积极、消极或中性。
垃圾邮件过滤:朴素贝叶斯算法可以有效地识别并过滤垃圾邮件,减少用户的干扰和损失。
5.2 小结
通过此次实验,深刻了解并掌握朴素贝叶斯的算法原理和基本流程,实验过程中也出现了各种错误,对该分类器有了深刻理解。总的来说,朴素贝叶斯算法是一个简单、易于实现、效果不错的分类算法,希望未来我还能学习更多关于机器学习算法的知识。