朴素贝叶斯模型
基于贝叶斯定理与特征条件独立假设(该模型假设属性之间相互独立,在这种情况下NBC模型与其他分类相比具有最小的误差率)的分类条件,一种能够有效利用经验的分类模型。
NBC模型所需估计的参数很少,对缺失数据不敏感,算法也比较简单。
叶贝斯的贡献:创造了逆概率——按照经典概率理论,像是计算我考上清华的概率这样的问题,是不可理喻的,而叶贝斯模型的主要贡献就是能在这些方面预测概率.
叶贝斯模型的优势
经典统计学认为事件发生的概率就是当统计次数趋向于正无穷时该时间的概率,而叶贝斯模型能在事件发生之前就知晓其概率。
相关概率定义
先验概率:是指根据以往经验和分析得到的概率。
后验概率:是指得到“结果”的信息后重新修正概率。
两者的区别其实就是有没有外附条件
相关概率公式
全概率公式:
(本质上就是一个从原因推结果的过程)
逆概率公式:
条件概率公式:
事件A在B已经发生的情形下的概率称为A在B下的条件概率:
逆概率公式:
逆概率公式由叶贝斯推导并提出,我们一般把逆概率公式称为叶贝斯公式,这个公式可以看作是由结果推原因的过程。
以叶贝斯为理论基础的分类模型,我们一般称为朴素叶贝斯模型,朴素就朴素在于这个模型的每一个特征都是独立的。这是一个非常强的假设,在现实生活当中不会成立,因此,这也反应了叶贝斯模型的一个缺陷,但是独立的特征使得叶贝斯模型简单优良,有着较好的分类和预测能力。
对于独立的特征B1,B2,B3,B4…Bn,叶贝斯假设的形式化描述如下:
通俗易懂的讲就是算出在B特征下A又更可能了多少/不可能了多少
但是由于诸如样本不充分等原因,很容易造成概率等于0的情况发生,为此,拉普拉斯提出了一种简单有效的方法:给每个参考样本的频率后面都加上一,这种平滑方法就被称作拉普拉斯平滑。
具体应用:
还是从2012年美赛ICM里考虑,
这里我们采用2012年美赛c题ICM problem第一小题为例子:
您的主管为当前案例整理了一个类似网络的数据库,该数据库具有相同的结构,但范围稍大一些。调查人员有一些迹象表明,正在发生阴谋,从公司挪用资金,并使用互联网欺诈从与公司有业务往来的人的信用卡中窃取资金。她向您展示的案例 EZ 的小示例只有 10 个人(节点)、27 个链接(消息)、5 个主题、1 个可疑/阴谋主题、2 个已知阴谋者和 2 个已知的非共谋者。 到目前为止,新案例有 83 个节点、400 个链接(有些涉及 1 个以上的主题)、超过 21,000 个消息流量、15 个主题(3 个被认为可疑)、7 个已知的共谋者和 8 个已知的非共谋者。这些数据在随附的电子表格文件中给出:Names.xls、Topics.xls 和 Messages.xls。 Names.xls 包含节点号到上班族姓名的键。Topics.xls 包含 15 个主题编号的代码,以及主题的简短描述。由于安全和隐私问题,您的团队将不会拥有所有消息流量的直接转录。Messages.xls 提供传输消息的节点的链接以及消息包含的主题代码编号。多条消息最多包含三个主题。为了帮助可视化消息流量,图 2 中提供了人员和消息链接的网络模型。在这种情况下,消息的主题不会像图 1 中那样显示在图中。这些主题编号在文件 Messages.xls 中给出,并在 Topics.xls 中进行了描述。
要求 1:到目前为止,已知 Jean、Alex、Elsie、Paul、Ulf、Yao 和 Harvey 是阴谋者。此外,众所周知,Darlene、Tran、Jia、Ellin、Gard、Chris、Paige 和 Este 不是阴谋者。 三个已知的可疑消息主题是 7、11 和 13。文件中提供了有关主题的更多详细信息Topics.xls。 构建一个模型和算法,根据参与阴谋的可能性对 83 个节点进行优先级排序,并解释您的模型和指标。Jerome、Delores 和 Gretchen 是公司的高级经理。了解他们中的任何人是否参与了阴谋将非常有帮助。
在这个问题一当中我们可以看到三个可疑的主题是7、11、13,那我们就可以采取叶贝斯的思想,利用已知阴谋者和非阴谋者来对主题7、11、13诞生犯罪分子分别求可能然后归一化,作为权重,构建基于叶贝斯赋权出入链的PageRank模型,这种解法我认为是要优于利用TF-IDF理清语法成本然后通过层次分析法确定各主题与犯罪之间的关系,因为词语与犯罪的关系是人为确定的,而且在其中为了简化仅仅是以个别词来代替了整体主题。
在这里因为只提及了叶贝斯模型,我们就全用叶贝斯模型来解决,这样的坏处是体现不出中心人物具备更强的犯罪可能,好处是模型被简化了
import pandas as pd
# 读取Messages.xlsx文件
messages_df = pd.read_excel('Messages.xlsx')
# 阴谋者名单
conspirators = [18, 21, 7, 43, 54, 67, 49]
# 非阴谋者名单
non_conspirators = [48, 64, 65, 68, 74, 0, 2]
# 消息主题
suspicious_topics = [7, 11, 13]
# 过滤出与主题7、11、13相关的链
filtered_messages_df = messages_df[messages_df['Text topic 1'].isin(suspicious_topics)]
# 初始化计数器
conspirator_topic_counts = {topic: 0 for topic in suspicious_topics}
non_conspirator_topic_counts = {topic: 0 for topic in suspicious_topics}
topic_counts = {topic: 0 for topic in suspicious_topics}
# 遍历过滤后的消息数据,统计阴谋者和非阴谋者涉及的主题次数
for index, row in filtered_messages_df.iterrows():
start_node = row['Start node']
end_node = row['End node']
topic = row['Text topic 1']
topic_counts[topic] += 1 # 统计每个主题出现的次数
if start_node in conspirators or end_node in conspirators:
conspirator_topic_counts[topic] += 1
elif start_node in non_conspirators or end_node in non_conspirators:
non_conspirator_topic_counts[topic] += 1
# 计算 P(A|B) 使用拉普拉斯平滑方法
# P(A|B) = (A的频次 + 1) / (B条件下的总数)
P_A_given_B = {}
for topic in suspicious_topics:
total_count = conspirator_topic_counts[topic] + non_conspirator_topic_counts[topic]
P_A_given_B[topic] = (conspirator_topic_counts[topic] + 1) / total_count # 拉普拉斯平滑
# 计算 P(B)
total_messages = len(filtered_messages_df)
P_B = {topic: count / total_messages for topic, count in topic_counts.items()}
# 计算 P(A)
total_people = len(set(messages_df['Start node']).union(set(messages_df['End node'])))
P_A = len(conspirators) / total_people
# 计算 P(B|A)
P_B_given_A = {}
for topic in suspicious_topics:
P_B_given_A[topic] = (P_A_given_B[topic] * P_B[topic]) / P_A
# 读取Names.xlsx文件
names_df = pd.read_excel('Names.xlsx')
# 找到 Jerome、Delores 和 Gretchen 的编号
jerome_id = names_df[names_df['Name'] == 'Jerome']['Node #'].values[0]
delores_id = names_df[names_df['Name'] == 'Dolores']['Node #'].values[0]
gretchen_id = names_df[names_df['Name'] == 'Gretchen']['Node #'].values[0]
# 初始化每个人的 P(A|B) 为 0
P_A_given_B_individual = {
jerome_id: 0,
delores_id: 0,
gretchen_id: 0
}
# 遍历过滤后的消息数据,统计每个人涉及的主题次数
for index, row in filtered_messages_df.iterrows():
start_node = row['Start node']
end_node = row['End node']
topic = row['Text topic 1']
if start_node in [jerome_id, delores_id, gretchen_id] or end_node in [jerome_id, delores_id, gretchen_id]:
if start_node == jerome_id or end_node == jerome_id:
P_A_given_B_individual[jerome_id] += P_B_given_A[topic]
if start_node == delores_id or end_node == delores_id:
P_A_given_B_individual[delores_id] += P_B_given_A[topic]
if start_node == gretchen_id or end_node == gretchen_id:
P_A_given_B_individual[gretchen_id] += P_B_given_A[topic]
# 计算每个人的 P(A|B)
for person_id in P_A_given_B_individual:
P_A_given_B_individual[person_id] = (P_A_given_B_individual[person_id] * P_A) / sum(P_B.values())
# 打印结果
print("P(A|B) for Jerome:", P_A_given_B_individual[jerome_id])
print("P(A|B) for Dolores:", P_A_given_B_individual[delores_id])
print("P(A|B) for Gretchen:", P_A_given_B_individual[gretchen_id])
预测的结果和上次比较相近,但是由于本身假设上的缺陷没有办法很好的反映一个真实的概率
P(A|B) for Jerome: 1.2258241758241757
P(A|B) for Dolores: 1.6159340659340662
P(A|B) for Gretchen: 1.2258241758241757