二项式分布html实验

二项式分布html实验

本文将带你一步步搭建一个纯前端的二项分布 Monte-Carlo 模拟器。
只要一个 HTML 文件,打开就能运行:

  • 动态输入试验次数 n、成功概率 p 与重复次数 m
  • 点击按钮立刻得到「模拟频数 vs 理论频数」柱状图
  • 随着 m 增大,两组柱状图逐渐重合,从视觉上 印证二项分布公式

目录

  1. 为什么要做这个实验
  2. 技术选型
  3. 功能与界面预览
  4. 逐段解析核心代码
  5. 完整源码(复制即用)
  6. 如何使用 & 实验建议
  7. 可能的扩展方向

1. 为什么要做这个实验

学习概率论时,我们经常“纸上谈兵”——写下

[
P(X=k)=\binom{n}{k}p{k}(1-p){n-k}
]

就宣称“这就是答案”。
如果能亲手做实验,让抽样分布真实地落在眼前,
不仅能直观体会“大数定律”与“二项分布”的关系,也能加深对公式每一项含义的理解。


2. 技术选型

角色工具说明
样式Tailwind CSS(Play CDN)无需构建、开箱即用的原子化类
图表Chart.js v4体积小、易上手、对柱状图支持好
逻辑原生 JavaScript仅用 ES6 语法即可完成全部计算与交互

优势:

  • 单文件、零依赖后端,复制到本地或放到 GitHub Pages 就能跑
  • 代码总行数 < 200,便于教学与改造

3. 功能与界面预览

  • 三个输入框:
    • 试验次数 n:每个伯努利实验重复多少次
    • 成功概率 p:0 ~ 1
    • 重复实验次数 m:Monte-Carlo 总抽样次数
  • 「运行模拟」按钮
  • 双数据集柱状图
    • 蓝色 = 模拟得到的实际频数
    • 绿色 = 理论 PMF×m 得到的期望频数

随着 m 增大,两种柱子高度越贴近 —— 这就是经验分布逼近理论分布的过程。


4. 逐段解析核心代码

4.1 组合数 comb(n,k)

function comb(n, k) {k = Math.min(k, n - k);      // 对称性优化let c = 1;for (let i = 0; i < k; i++)  // 逐项相乘避免溢出c = (c * (n - i)) / (i + 1);return c;
}

思路:用递推而非阶乘,避免中间结果溢出并减少运算量。


4.2 理论 PMF binomPMF(n,p)

function binomPMF(n, p) {const q = 1 - p;return Array.from({ length: n + 1 }, (_, k) =>comb(n, k) * Math.pow(p, k) * Math.pow(q, n - k));
}

返回长度 n+1 的数组,第 k 项即公式值。


4.3 Monte-Carlo 模拟 simulate(n,p,m)

function simulate(n, p, m) {const freq = Array(n + 1).fill(0);for (let i = 0; i < m; i++) {let successes = 0;for (let j = 0; j < n; j++)if (Math.random() < p) successes++;freq[successes]++;}return freq;
}

双层循环:外层m 次实验,内层n 次伯努利试验。


4.4 Chart.js 初始化与刷新

const chart = new Chart(ctx, {type: "bar",data: { labels: [], datasets: [...] },options: { scales: { x: {...}, y: {...} } }
});runBtn.onclick = () => {const n = +nInput.value, p = +pInput.value, m = +mInput.value;const sim = simulate(n,p,m);const theory = binomPMF(n,p).map(x => x*m);chart.data.labels = [...Array(n+1).keys()];chart.data.datasets[0].data = sim;chart.data.datasets[1].data = theory;chart.update();
};

Chart.js 会自动在同一 X-轴按类别叠放两组柱子。


5. 完整源码(复制即用)

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8" /><title>二项分布模拟实验</title><script src="https://cdn.tailwindcss.com"></script><script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
</head>
<body class="min-h-screen bg-slate-50 flex flex-col items-center py-8"><h1 class="text-3xl font-bold mb-6">二项分布模拟实验</h1><div class="bg-white shadow-md rounded-lg p-6 w-full max-w-md mb-8"><div class="mb-4"><label class="block font-semibold mb-1" for="n">试验次数 n</label><input id="n" type="number" min="1" max="100" value="10" class="w-full border rounded px-3 py-2" /></div><div class="mb-4"><label class="block font-semibold mb-1" for="p">成功概率 p (0~1)</label><input id="p" type="number" step="0.01" min="0" max="1" value="0.5" class="w-full border rounded px-3 py-2" /></div><div class="mb-4"><label class="block font-semibold mb-1" for="m">重复实验次数 m</label><input id="m" type="number" min="1" max="20000" value="1000" class="w-full border rounded px-3 py-2" /></div><button id="runBtn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 rounded">运行模拟</button></div><div class="w-full max-w-3xl"><canvas id="chart"></canvas></div><script>const comb = (n, k) => {if (k < 0 || k > n) return 0;k = Math.min(k, n - k);let c = 1;for (let i = 0; i < k; i++) c = (c * (n - i)) / (i + 1);return c;};const binomPMF = (n, p) => {const q = 1 - p;return Array.from({ length: n + 1 }, (_, k) =>comb(n, k) * Math.pow(p, k) * Math.pow(q, n - k));};const simulate = (n, p, m) => {const freq = Array(n + 1).fill(0);for (let i = 0; i < m; i++) {let success = 0;for (let j = 0; j < n; j++) success += Math.random() < p ? 1 : 0;freq[success]++;}return freq;};const ctx = document.getElementById("chart");const chart = new Chart(ctx, {type: "bar",data: {labels: [],datasets: [{ label: "模拟频数", data: [], backgroundColor: "rgba(59,130,246,0.6)" },{ label: "理论期望频数", data: [], backgroundColor: "rgba(16,185,129,0.6)" }]},options: {responsive: true,scales: {x: { title: { display: true, text: "成功次数 k" } },y: { title: { display: true, text: "频数" } }}}});document.getElementById("runBtn").onclick = () => {const n = +document.getElementById("n").value;const p = +document.getElementById("p").value;const m = +document.getElementById("m").value;if (n <= 0 || p < 0 || p > 1 || m <= 0) {alert("请输入合法参数!");return;}const sim = simulate(n, p, m);const theory = binomPMF(n, p).map(v => v * m);chart.data.labels = [...Array(n + 1).keys()];chart.data.datasets[0].data = sim;chart.data.datasets[1].data = theory;chart.update();};</script>
</body>
</html>

6. 如何使用 & 实验建议

  1. 下载/复制源文件 → 直接双击或用 VS Code Live Server 打开。
  2. 先用默认参数 n=10,p=0.5,m=1000 运行一次。
  3. 增大 m(如 5000、10000):观察柱状图差距逐渐减小。
  4. 改变 p(偏心硬币):体验图形从对称到偏斜的变化。
  5. 改变 n:试验次数越大,横轴成功次数种类越多,曲线越接近正态分布形状。

小实验:设置 n=1,此时模拟结果就会精确落在伯努利分布 ( {0,1} ) 上,验证“二项分布在 n=1 时退化为伯努利”。


7. 可能的扩展方向

想法技术提示
加入 泊松近似/正态近似 曲线再添加一个折线数据集,公式计算期望值
计算并展示 卡方检验 χ²在 JS 中对两组频数做 Σ((obs-exp)²/exp)
支持 动画增量抽样setInterval 每隔 N 次刷新一次柱状图
WebWorker 提升大规模模拟性能simulate 放到 worker 线程

复制本文源码,亲眼见证经验分布二项分布收敛的全过程吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/77206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过 API 对接应用网络商城实现订单自动化

前言 API&#xff08;Application Programming Interface&#xff09;即应用程序编程接口&#xff0c;是一种允许不同软件应用程序之间进行交互和数据共享的工具。它通过定义一组明确的规则和协议&#xff0c;使得各个软件系统能够以标准化的方式相互通信。 在支付领域&#x…

openwrt作旁路由时的几个常见问题 openwrt作为旁路由配置zerotier 图文讲解

1 先看openwrt时间&#xff0c;一定要保证时间和浏览器和服务器是一致的&#xff0c;不然无法更新 2 openwrt设置旁路由前先测试下&#xff0c;路由器能否ping通主路由&#xff0c;是否能够连接外网&#xff0c;好多旁路由设置完了&#xff0c;发现还不能远程好多就是旁路由本…

FANUC机器人GI与GO位置数据传输设置

FANUC机器人GI与GO位置数据传输设置&#xff08;整数小数分开发&#xff09; 一、概述 在 Fanuc 机器人应用中&#xff0c;如果 IO 点位足够&#xff0c;可以利用机器人 IO 传输位置数据及偏移位置数据等。 二、操作步骤 1、确认通讯软件安装 首先确认机器人控制柜已经安装…

UE5 Assimp 自用

记录一下配assimp库到ue中的过程。因为想在ue里面实现一些几何处理(虽然ue好像有相关的geo的代码&#xff09;&#xff0c;遂配置了一下assimp。 1. 编译整理生成自己所需要的文件。cmake编译&#xff0c;下载github 的官方的assimp-master&#xff0c;然后cmake都是默认的就行…

第18章:MCP在创作领域中的应用

第18章:MCP在创作领域中的应用 创意过程,无论是写作、绘画、音乐创作还是设计,往往充满了不确定性、迭代和灵感的迸发。传统 AI 在创意领域的应用常常局限于风格迁移、简单内容生成等。MCP 框架通过其对记忆、上下文和规划的整合,为 AI Agent 参与和辅助更深层次的创意活动…

电子电子架构 --- 主机厂视角下ECU开发流程

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

【Agent】LangManus深度解析:AI自动化框架的对比与langgraph原理

LangManus深度解析&#xff1a;AI自动化框架的技术演进与实践 本文将带你深入探索LangManus这一AI自动化框架的核心技术与其基于langgraph的实现原理&#xff0c;并与OpenManus进行全面对比&#xff0c;助你掌握多智能体系统的前沿技术。 本文3万字&#xff0c;没有时间的话可以…

机器学习-08-推荐算法-案例

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中关联规则 参考 机器学习&#xff08;三&#xff09;&#xff1a;Apriori算法&#xff08;算法精讲&#xff09; Apriori 算法 理论 重点 MovieLens:一个常用的电影推荐系统领域的数据集 23张图&#x…

OpenCV 图形API(63)图像结构分析和形状描述符------计算图像中非零像素的边界框函数boundingRect()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算点集或灰度图像非零像素的 upright&#xff08;不旋转&#xff09;边界矩形。 该函数计算并返回指定点集或灰度图像非零像素的最小 upright …

Redis ⑥-string | hash | list

string类型基本介绍 Redis 中的字符串&#xff0c;是直接按照二进制的方式进行存储的。也就是说&#xff0c;在存取的过程中&#xff0c;是不会做任何编码转换的。存的是啥&#xff0c;取的时候就是啥。 Redis 的这个机制&#xff0c;就使得 Redis 非常适合用来存储各种各样的…

星火燎原:大数据时代的Spark技术革命在数字化浪潮席卷全球的今天,海量数据如同奔涌不息的洪流,传统的数据处理方式已难以满足实时、高效的需求。

星火燎原&#xff1a;大数据时代的Spark技术革命 在数字化浪潮席卷全球的今天&#xff0c;海量数据如同奔涌不息的洪流&#xff0c;传统的数据处理方式已难以满足实时、高效的需求。Apache Spark作为大数据领域的璀璨明星&#xff0c;凭借其卓越的性能和强大的功能&#xff0c…

通信算法之273 : 循环自相关函数和自相关函数

一、循环自相关函数定义与计算流程 ‌定义式‌: 循环自相关函数为时间平均自相关函数的傅里叶变换: Rxα(τ)=1T∫−T/2T/2Rx(t+τ2,t−τ2)e−j2παtdtRxα​(τ)=T1​∫−T/2T/2​Rx​(t+2τ​,t−2τ​)e−j2παtdt 其中,Rx(t,τ)Rx​(t,τ) 是信号的自相关函数,α为循…

使用 VMware 安装一台 Linux 系统之Centos

使用 VMware 安装一台 Linux 系统之Centos 想体验一下 Linux 的魅力&#xff0c;又不想在现有电脑上进行大刀阔斧的改动&#xff1f;使用 VMware 虚拟机是一个绝佳的选择。它能让你在 Windows 或 macOS 系统中轻松创建一个独立的 Linux 环境。本文将手把手带你完成从下载 VMwa…

uniapp-商城-36-shop 购物车 选好了 进行订单确认2 支付方式颜色变化和颜色滤镜filter

颜色滤镜&#xff0c;在好多网页都这样使用&#xff0c;滤掉彩色&#xff0c;显示黑白&#xff0c;这在一些关键的日子中都这样使用。 1、依然回到订单确认页面 看到支付的颜色了嘛&#xff1f; <view class"payType"><view class"box" :class&q…

gerbera文件转PCB文件-Altium Designer

gerbera文件转PCB文件-Altium Designer 1. 新建 CAM 文档2. 导入 Gerber 文件和钻孔文件导入 Gerber 文件导入钻孔文件&#xff08;NC Drill&#xff09; 3. 提取网络表4. 检查并设置层映射5. 导出为 PCB 文件 1. 新建 CAM 文档 打开 Altium Designer&#xff0c;执行以下操作…

Flask 请求数据获取方法详解

一、工作原理 在 Flask 中&#xff0c;所有客户端请求的数据都通过全局的 request 对象访问。该对象是 请求上下文 的一部分&#xff0c;仅在请求处理期间存在。Flask 在收到请求时自动创建 request 对象&#xff0c;并根据请求类型&#xff08;如 GET、POST&#xff09;和内容…

队列基础和例题

基础 #include <queue> #include <iostream>/*** 入队*/ void Test01() {std::queue<int> q;q.push(1);q.push(2);q.push(3);q.push(4);q.push(777);std::cout << "队列大小:" << q.size() << std::endl;std::cout << &q…

U-Mail邮件加速服务:全球链路加速,安全稳定收发

由于跨国网络拥堵、带宽不稳定等因素&#xff0c;导致海外用户在使用企业邮箱收发邮件时&#xff0c;经常出现邮件收发不畅的问题。针对这种情况&#xff0c;U-Mail正式推出了邮件加速服务&#xff0c;U-Mail邮件加速服务依托全球优质加速链路和转发集群服务器&#xff0c;为海…

从工作到娱乐:Codigger Desktop 让桌面环境更智能

在数字化时代&#xff0c;我们的桌面环境几乎成了第二个家。Codigger Desktop 就像是这个家的设计师&#xff0c;帮你打造一个既实用又舒适的数字空间。无论你是想放松娱乐&#xff0c;还是高效工作&#xff0c;Codigger Desktop 都能满足你的需求。 想象一下&#xff0c;你有一…

用python进行OCR识别

原文链接&#xff1a;https://www.bilibili.com/opus/1036675560501149699 我担心原作者删除&#xff0c;所以重新拷贝了一遍 1.下载tesseract 链接&#xff1a;https://github.com/UB-Mannheim/tesseract/wiki 这里示例安装最新版本 点击下载tesseract安装包 2.安装tess…