用PythonMatplotlib动态拆解贝叶斯公式从概率迷雾到可视化直觉当第一次接触贝叶斯定理时很多人会被那些抽象的概率符号弄得晕头转向。P(H|E)、P(E|H)、先验、后验...这些术语就像一堵高墙把我们对概率的直觉挡在外面。但如果我们换一种方式——用代码和图形来呈现这个过程一切突然变得清晰可见。这就是为什么Python和Matplotlib成为理解贝叶斯定理的绝佳工具它们能把数学公式转化为可以交互、可以调整的动态可视化过程。1. 环境准备与基础概念可视化在开始之前确保你的Python环境已经安装了以下库pip install matplotlib numpy贝叶斯定理的核心在于理解三个关键概率先验概率P(H)在观察到新证据前假设成立的概率似然概率P(E|H)假设成立时观察到该证据的概率后验概率P(H|E)观察到证据后假设成立的概率让我们用图书馆管理员和农民的经典案例来构建可视化。假设农民与图书馆管理员的比例是20:140%的图书馆管理员符合温顺有条理的描述10%的农民符合这一描述import numpy as np import matplotlib.pyplot as plt # 设置参数 total_farmers 200 total_librarians 10 p_librarian 0.4 # 管理员中符合描述的概率 p_farmer 0.1 # 农民中符合描述的概率 # 计算符合描述的人数 described_librarians total_librarians * p_librarian described_farmers total_farmers * p_farmer2. 构建韦恩图展示概率关系韦恩图是展示集合关系的绝佳工具。我们可以用Matplotlib绘制一个动态的韦恩图来展示这些概率关系from matplotlib_venn import venn2 plt.figure(figsize(10,6)) venn venn2(subsets(total_farmers, total_librarians, described_farmers), set_labels(农民, 图书管理员)) venn.get_label_by_id(11).set_text(f{described_farmers}\n符合描述) venn.get_label_by_id(10).set_text(f{total_farmers-described_farmers}\n农民) venn.get_label_by_id(01).set_text(f{total_librarians}\n图书管理员) plt.title(职业分布与性格特征关系) plt.show()这个可视化清晰地展示了左侧大圆代表200位农民右侧小圆代表10位图书管理员重叠区域代表符合温顺有条理描述的人群关键观察尽管图书管理员中符合描述的比例更高但绝对人数上农民更多。这就是贝叶斯思维的核心——既要考虑比例也要考虑基数。3. 动态计算后验概率现在让我们编写一个函数动态计算后验概率并可视化计算过程def bayes_visualization(total_f, total_l, p_f, p_l): # 计算各部分人数 described_f total_f * p_f described_l total_l * p_l total_described described_f described_l # 计算后验概率 posterior described_l / total_described # 可视化 fig, ax plt.subplots(1, 2, figsize(14,6)) # 左侧职业分布 ax[0].bar([农民, 图书管理员], [total_f, total_l], color[green, purple]) ax[0].set_title(总体职业分布) # 右侧符合描述的人群分布 ax[1].bar([农民, 图书管理员], [described_f, described_l], color[green, purple]) ax[1].set_title(f符合描述的人群分布\nP(管理员|描述){posterior:.2f}) plt.tight_layout() return posterior # 使用示例 posterior_prob bayes_visualization(total_farmers, total_librarians, p_farmer, p_librarian)这段代码会生成两个并排的柱状图左侧显示农民和图书管理员的总体数量右侧显示符合描述的两类人群数量并在标题中直接显示计算得到的后验概率4. 交互式参数探索为了更深入理解各参数如何影响后验概率我们可以创建一个交互式可视化from ipywidgets import interact def interactive_bayes(total_farmers200, total_librarians10, p_farmer0.1, p_librarian0.4): posterior bayes_visualization(total_farmers, total_librarians, p_farmer, p_librarian) print(f后验概率P(管理员|描述){posterior:.4f}) interact(interactive_bayes, total_farmers(50,500,10), total_librarians(1,50,1), p_farmer(0.01,1.0,0.01), p_librarian(0.01,1.0,0.01))这个交互式工具允许你调整农民和图书管理员的总体数量两类人群中符合描述的概率 实时观察这些变化如何影响最终的后验概率。5. 面积图展示概率更新过程贝叶斯定理的本质是概率的更新过程。我们可以用面积图来形象展示这一更新def probability_flow(total_f, total_l, p_f, p_l): described_f total_f * p_f described_l total_l * p_l total_described described_f described_l # 创建图形 fig, ax plt.subplots(figsize(10,6)) # 绘制先验概率 ax.barh([先验], [total_l], colorpurple, alpha0.3) ax.barh([先验], [total_f], left[total_l], colorgreen, alpha0.3) # 绘制似然概率 ax.barh([似然], [described_l], colorpurple, alpha0.6) ax.barh([似然], [described_f], left[described_l], colorgreen, alpha0.6) # 绘制后验概率 ax.barh([后验], [described_l], colorpurple) ax.barh([后验], [described_f], left[described_l], colorgreen) # 添加标注 ax.text(total_l/2, 0, fP(H){total_l/(total_ftotal_l):.2f}, hacenter, vacenter) ax.text(described_l/2, 1, fP(E|H){p_l:.2f}, hacenter, vacenter) ax.text(described_l described_f/2, 1, fP(E|¬H){p_f:.2f}, hacenter, vacenter) ax.text(described_l/2, 2, fP(H|E){described_l/total_described:.2f}, hacenter, vacenter) ax.set_xlim(0, max(total_f, total_l)) ax.set_title(贝叶斯概率更新流程) plt.show() probability_flow(total_farmers, total_librarians, p_farmer, p_librarian)这个面积图清晰地展示了先验概率不考虑任何描述时的职业分布似然概率考虑描述后的分布变化后验概率最终的条件概率结果6. 从具体案例到通用公式通过前面的可视化我们已经对贝叶斯定理有了直观理解。现在让我们把这些具体数字抽象为通用公式def bayes_theorem(p_H, p_E_given_H, p_E_given_notH): p_notH 1 - p_H p_E p_H * p_E_given_H p_notH * p_E_given_notH p_H_given_E (p_H * p_E_given_H) / p_E return p_H_given_E # 计算通用案例 p_H 10/210 # 先验概率 p_E_given_H 0.4 # 似然概率 p_E_given_notH 0.1 # p_H_given_E bayes_theorem(p_H, p_E_given_H, p_E_given_notH) print(f通用贝叶斯公式计算结果: P(H|E) {p_H_given_E:.4f})这个通用函数可以计算任何符合贝叶斯定理的场景。为了更好理解各参数的关系我们可以绘制一个三维曲面图from mpl_toolkits.mplot3d import Axes3D # 创建网格 p_H_values np.linspace(0.01, 0.99, 50) ratio_values np.linspace(0.1, 10, 50) # P(E|H)/P(E|¬H) P_H, Ratio np.meshgrid(p_H_values, ratio_values) P_H_given_E (P_H * Ratio) / (P_H * Ratio (1 - P_H)) # 绘制3D曲面 fig plt.figure(figsize(12,8)) ax fig.add_subplot(111, projection3d) surf ax.plot_surface(P_H, Ratio, P_H_given_E, cmapviridis) ax.set_xlabel(先验概率 P(H)) ax.set_ylabel(似然比 P(E|H)/P(E|¬H)) ax.set_zlabel(后验概率 P(H|E)) ax.set_title(贝叶斯定理参数关系曲面) fig.colorbar(surf, shrink0.5, aspect5) plt.show()这个三维可视化展示了x轴先验概率P(H)y轴似然比(证据在假设成立和不成立时的概率比)z轴得到的后验概率P(H|E)7. 实际应用案例垃圾邮件过滤让我们看一个实际应用场景——垃圾邮件过滤。假设所有邮件中5%是垃圾邮件垃圾邮件中出现免费一词的概率是50%正常邮件中出现免费一词的概率是10%# 参数设置 p_spam 0.05 p_free_given_spam 0.5 p_free_given_notspam 0.1 # 计算 p_free p_spam * p_free_given_spam (1-p_spam) * p_free_given_notspam p_spam_given_free (p_spam * p_free_given_spam) / p_free print(f当邮件包含免费时是垃圾邮件的概率: {p_spam_given_free:.2%})我们可以扩展这个例子可视化不同词语对垃圾邮件判断的影响# 定义不同词语的似然概率 words { 免费: (0.5, 0.1), 赚钱: (0.4, 0.05), 会议: (0.1, 0.2), 报告: (0.15, 0.3) } # 计算每个词语的后验概率 results {} for word, (p_w_given_spam, p_w_given_ham) in words.items(): p_w p_spam * p_w_given_spam (1-p_spam) * p_w_given_ham p_spam_given_w (p_spam * p_w_given_spam) / p_w results[word] p_spam_given_w # 可视化 plt.figure(figsize(10,5)) plt.bar(results.keys(), results.values()) plt.axhline(p_spam, colorred, linestyle--, label先验概率) plt.title(不同词语对垃圾邮件判断的影响) plt.ylabel(P(垃圾邮件|词语)) plt.legend() plt.show()这个柱状图清晰地展示了不同词语如何更新我们对邮件是否为垃圾邮件的判断。红色虚线表示先验概率柱子表示看到相应词语后的后验概率。
别再死记硬背了!用Python+Matplotlib画张图,5分钟搞懂贝叶斯公式到底在算什么
发布时间:2026/6/12 9:38:23
用PythonMatplotlib动态拆解贝叶斯公式从概率迷雾到可视化直觉当第一次接触贝叶斯定理时很多人会被那些抽象的概率符号弄得晕头转向。P(H|E)、P(E|H)、先验、后验...这些术语就像一堵高墙把我们对概率的直觉挡在外面。但如果我们换一种方式——用代码和图形来呈现这个过程一切突然变得清晰可见。这就是为什么Python和Matplotlib成为理解贝叶斯定理的绝佳工具它们能把数学公式转化为可以交互、可以调整的动态可视化过程。1. 环境准备与基础概念可视化在开始之前确保你的Python环境已经安装了以下库pip install matplotlib numpy贝叶斯定理的核心在于理解三个关键概率先验概率P(H)在观察到新证据前假设成立的概率似然概率P(E|H)假设成立时观察到该证据的概率后验概率P(H|E)观察到证据后假设成立的概率让我们用图书馆管理员和农民的经典案例来构建可视化。假设农民与图书馆管理员的比例是20:140%的图书馆管理员符合温顺有条理的描述10%的农民符合这一描述import numpy as np import matplotlib.pyplot as plt # 设置参数 total_farmers 200 total_librarians 10 p_librarian 0.4 # 管理员中符合描述的概率 p_farmer 0.1 # 农民中符合描述的概率 # 计算符合描述的人数 described_librarians total_librarians * p_librarian described_farmers total_farmers * p_farmer2. 构建韦恩图展示概率关系韦恩图是展示集合关系的绝佳工具。我们可以用Matplotlib绘制一个动态的韦恩图来展示这些概率关系from matplotlib_venn import venn2 plt.figure(figsize(10,6)) venn venn2(subsets(total_farmers, total_librarians, described_farmers), set_labels(农民, 图书管理员)) venn.get_label_by_id(11).set_text(f{described_farmers}\n符合描述) venn.get_label_by_id(10).set_text(f{total_farmers-described_farmers}\n农民) venn.get_label_by_id(01).set_text(f{total_librarians}\n图书管理员) plt.title(职业分布与性格特征关系) plt.show()这个可视化清晰地展示了左侧大圆代表200位农民右侧小圆代表10位图书管理员重叠区域代表符合温顺有条理描述的人群关键观察尽管图书管理员中符合描述的比例更高但绝对人数上农民更多。这就是贝叶斯思维的核心——既要考虑比例也要考虑基数。3. 动态计算后验概率现在让我们编写一个函数动态计算后验概率并可视化计算过程def bayes_visualization(total_f, total_l, p_f, p_l): # 计算各部分人数 described_f total_f * p_f described_l total_l * p_l total_described described_f described_l # 计算后验概率 posterior described_l / total_described # 可视化 fig, ax plt.subplots(1, 2, figsize(14,6)) # 左侧职业分布 ax[0].bar([农民, 图书管理员], [total_f, total_l], color[green, purple]) ax[0].set_title(总体职业分布) # 右侧符合描述的人群分布 ax[1].bar([农民, 图书管理员], [described_f, described_l], color[green, purple]) ax[1].set_title(f符合描述的人群分布\nP(管理员|描述){posterior:.2f}) plt.tight_layout() return posterior # 使用示例 posterior_prob bayes_visualization(total_farmers, total_librarians, p_farmer, p_librarian)这段代码会生成两个并排的柱状图左侧显示农民和图书管理员的总体数量右侧显示符合描述的两类人群数量并在标题中直接显示计算得到的后验概率4. 交互式参数探索为了更深入理解各参数如何影响后验概率我们可以创建一个交互式可视化from ipywidgets import interact def interactive_bayes(total_farmers200, total_librarians10, p_farmer0.1, p_librarian0.4): posterior bayes_visualization(total_farmers, total_librarians, p_farmer, p_librarian) print(f后验概率P(管理员|描述){posterior:.4f}) interact(interactive_bayes, total_farmers(50,500,10), total_librarians(1,50,1), p_farmer(0.01,1.0,0.01), p_librarian(0.01,1.0,0.01))这个交互式工具允许你调整农民和图书管理员的总体数量两类人群中符合描述的概率 实时观察这些变化如何影响最终的后验概率。5. 面积图展示概率更新过程贝叶斯定理的本质是概率的更新过程。我们可以用面积图来形象展示这一更新def probability_flow(total_f, total_l, p_f, p_l): described_f total_f * p_f described_l total_l * p_l total_described described_f described_l # 创建图形 fig, ax plt.subplots(figsize(10,6)) # 绘制先验概率 ax.barh([先验], [total_l], colorpurple, alpha0.3) ax.barh([先验], [total_f], left[total_l], colorgreen, alpha0.3) # 绘制似然概率 ax.barh([似然], [described_l], colorpurple, alpha0.6) ax.barh([似然], [described_f], left[described_l], colorgreen, alpha0.6) # 绘制后验概率 ax.barh([后验], [described_l], colorpurple) ax.barh([后验], [described_f], left[described_l], colorgreen) # 添加标注 ax.text(total_l/2, 0, fP(H){total_l/(total_ftotal_l):.2f}, hacenter, vacenter) ax.text(described_l/2, 1, fP(E|H){p_l:.2f}, hacenter, vacenter) ax.text(described_l described_f/2, 1, fP(E|¬H){p_f:.2f}, hacenter, vacenter) ax.text(described_l/2, 2, fP(H|E){described_l/total_described:.2f}, hacenter, vacenter) ax.set_xlim(0, max(total_f, total_l)) ax.set_title(贝叶斯概率更新流程) plt.show() probability_flow(total_farmers, total_librarians, p_farmer, p_librarian)这个面积图清晰地展示了先验概率不考虑任何描述时的职业分布似然概率考虑描述后的分布变化后验概率最终的条件概率结果6. 从具体案例到通用公式通过前面的可视化我们已经对贝叶斯定理有了直观理解。现在让我们把这些具体数字抽象为通用公式def bayes_theorem(p_H, p_E_given_H, p_E_given_notH): p_notH 1 - p_H p_E p_H * p_E_given_H p_notH * p_E_given_notH p_H_given_E (p_H * p_E_given_H) / p_E return p_H_given_E # 计算通用案例 p_H 10/210 # 先验概率 p_E_given_H 0.4 # 似然概率 p_E_given_notH 0.1 # p_H_given_E bayes_theorem(p_H, p_E_given_H, p_E_given_notH) print(f通用贝叶斯公式计算结果: P(H|E) {p_H_given_E:.4f})这个通用函数可以计算任何符合贝叶斯定理的场景。为了更好理解各参数的关系我们可以绘制一个三维曲面图from mpl_toolkits.mplot3d import Axes3D # 创建网格 p_H_values np.linspace(0.01, 0.99, 50) ratio_values np.linspace(0.1, 10, 50) # P(E|H)/P(E|¬H) P_H, Ratio np.meshgrid(p_H_values, ratio_values) P_H_given_E (P_H * Ratio) / (P_H * Ratio (1 - P_H)) # 绘制3D曲面 fig plt.figure(figsize(12,8)) ax fig.add_subplot(111, projection3d) surf ax.plot_surface(P_H, Ratio, P_H_given_E, cmapviridis) ax.set_xlabel(先验概率 P(H)) ax.set_ylabel(似然比 P(E|H)/P(E|¬H)) ax.set_zlabel(后验概率 P(H|E)) ax.set_title(贝叶斯定理参数关系曲面) fig.colorbar(surf, shrink0.5, aspect5) plt.show()这个三维可视化展示了x轴先验概率P(H)y轴似然比(证据在假设成立和不成立时的概率比)z轴得到的后验概率P(H|E)7. 实际应用案例垃圾邮件过滤让我们看一个实际应用场景——垃圾邮件过滤。假设所有邮件中5%是垃圾邮件垃圾邮件中出现免费一词的概率是50%正常邮件中出现免费一词的概率是10%# 参数设置 p_spam 0.05 p_free_given_spam 0.5 p_free_given_notspam 0.1 # 计算 p_free p_spam * p_free_given_spam (1-p_spam) * p_free_given_notspam p_spam_given_free (p_spam * p_free_given_spam) / p_free print(f当邮件包含免费时是垃圾邮件的概率: {p_spam_given_free:.2%})我们可以扩展这个例子可视化不同词语对垃圾邮件判断的影响# 定义不同词语的似然概率 words { 免费: (0.5, 0.1), 赚钱: (0.4, 0.05), 会议: (0.1, 0.2), 报告: (0.15, 0.3) } # 计算每个词语的后验概率 results {} for word, (p_w_given_spam, p_w_given_ham) in words.items(): p_w p_spam * p_w_given_spam (1-p_spam) * p_w_given_ham p_spam_given_w (p_spam * p_w_given_spam) / p_w results[word] p_spam_given_w # 可视化 plt.figure(figsize(10,5)) plt.bar(results.keys(), results.values()) plt.axhline(p_spam, colorred, linestyle--, label先验概率) plt.title(不同词语对垃圾邮件判断的影响) plt.ylabel(P(垃圾邮件|词语)) plt.legend() plt.show()这个柱状图清晰地展示了不同词语如何更新我们对邮件是否为垃圾邮件的判断。红色虚线表示先验概率柱子表示看到相应词语后的后验概率。