ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

freeCodeCamp 概率计算器项目全解:用蒙特卡洛模拟实现 Hat 类与 experiment 实验函数

freeCodeCamp 概率计算器项目全解:用蒙特卡洛模拟实现 Hat 类与 experiment 实验函数 freeCodeCamp 概率计算器项目全解用蒙特卡洛模拟实现 Hat 类与 experiment 实验函数【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp本指南以 freeCodeCamp「Scientific Computing with Python」认证中的 Build a Probability Calculator Project 为对象完整讲解其任务设定、Hat类与experiment函数的设计要求、浏览器内自动化评测机制以及官方参考实现的行级剖析。读完你将掌握用大量随机实验近似求解组合概率的蒙特卡洛编程套路并理解这类多文件 Python 项目challengeType 23multifilePythonCertProject是如何被 pyodide 与unittest联合验收的。一、项目定位与问题背景本项目的完整任务文档位于仓库中的 curriculum/challenges/english/blocks/build-a-probability-calculator-project/5e44414f903586ffb414c950.md它是 scientific-computing-with-python.json 中列出的最后一个第 21 个block属于科学计算方向的结业型项目。其 challengeType 为 23即 challenge-types.ts 中的multifilePythonCertProject并带有saveSubmissionToDB: true意味着通过测试后会把代码作为项目提交保存。任务从一个经典的概率问题切入假设帽子里有 5 个蓝球、4 个红球、2 个绿球。随机抽取 4 个球时抽到至少 1 个红球且至少 2 个绿球的概率是多少虽然可以用高等数学精确计算但更简单也更容易编程的做法是编写程序执行大量随机实验用统计结果估算近似概率。这正是蒙特卡洛方法的朴素形态——本项目不要求你手算组合数而是要求你用代码模拟随机抽取过程。二、核心思路为什么用 M/N 估算概率任务说明给出了蒙特卡洛的基本范式执行N次独立实验统计其中满足条件M次把M/N作为概率的近似值。每一步实验包含三个阶段用一个包含指定颜色球数量的新帽子开始从中随机抽取若干球不放回检查抽到的球是否满足expected_balls指定的目标组合。文档中给出的示例帽子含 6 个黑球、4 个红球、3 个绿球每次抽 5 个希望估算至少抽到 2 个红球和 1 个绿球的概率调用代码如下hat Hat(black6, red4, green3) probability experiment(hathat, expected_balls{red:2,green:1}, num_balls_drawn5, num_experiments2000)典型输出0.356因为每次运行都涉及随机抽取输出会略有不同例如 0.352、0.358……。num_experiments越大M/N越接近真实概率但运行时间也越长——这是精确度与开销之间的经典取舍。三、实现 Hat 类3.1contents把关键字参数展开成逐球列表Hat类接收可变数量的关键字参数来指定各颜色球数例如hat1 Hat(yellow3, blue2, green6) hat2 Hat(red5, orange4) hat3 Hat(red5, orange4, black1, blue0, pink2, striped9)规格约束帽子创建时至少含 1 个球传入参数应被转换为实例变量contentscontents是字符串列表每种颜色的每个球对应一个颜色名元素。例如{red: 2, blue: 1}应转换为[red, red, blue]。注意hat3中blue0意味着展开时不应产生任何blue元素。同时这也说明颜色名完全由用户关键字决定可以是striped、test等任意名称。3.2draw不放回随机抽取draw方法接收一个参数表示要抽取的球数从contents中随机移除并返回这些球组成的列表。行为约定不放回无放回抽取抽出的球在本次抽取过程中不会放回类似瓮实验urn experiment超额抽取如果请求抽取的球数超过帽子中现有数量则直接返回所有球并把帽子清空。在 Python 中移除并返回某个随机位置的元素可以借助list.pop(random.randrange(len(self.contents)))实现pop本身既取出元素又将其从列表中删除天然满足不放回语义。四、实现 experiment 函数experiment是模块级函数不能放进Hat类接收四个参数参数含义示例hat包含目标球的帽子对象函数内部应拷贝它再使用Hat(black6, red4, green3)expected_balls目标组合表示试图抽到的球组如抽到 2 蓝 1 红则传{blue:2, red:1}{red:2,green:1}num_balls_drawn每次实验抽取的球数5num_experiments实验次数越多结果越接近真实概率2000返回值是估算概率M/N这样的float。实现要点官方文档与参考解共同强调每次实验都要从初始帽子重新开始。由于draw会就地修改contents必须先对传入的hat做深拷贝copy.deepcopy再抽取否则第一次实验就会把帽子抽空后续实验全部失真。成功判定是把目标球组逐一从抽出的结果中消费掉把expected_balls展开成目标球列表遍历实际抽出的每个球若它在目标列表中存在则移除一个对应项注意用list.pop(index)只移除一个而不是remove的语义问题最终目标列表被清空即说明抽到的球覆盖了目标组合。概率 成功次数 / 实验总次数。4.1 完整参考实现任务文档# --solutions--段给出了官方参考解5e44414f903586ffb414c950.mdimport copy import random class Hat: def __init__(self, **hat): self.hat hat contents [] for i in hat: for j in range(hat[i]): contents.append(i) self.contents contents def draw(self, number): drawn [] if number len(self.contents): drawn.extend(self.contents) self.contents [] else: for i in range(number): drawn.append( self.contents.pop(random.randrange(len(self.contents))) ) return drawn def experiment(hat, expected_balls, num_balls_drawn, num_experiments): expected_balls_list [] drawn_list [] success 0 for i in expected_balls: for j in range(expected_balls[i]): expected_balls_list.append(i) for j in range(num_experiments): hat_copy copy.deepcopy(hat) drawn_list.append(hat_copy.draw(num_balls_drawn)) exp_ball_list_copy expected_balls_list[:] for k in range(len(drawn_list[j])): try: ind exp_ball_list_copy.index(drawn_list[j][k]) exp_ball_list_copy.pop(ind) except: continue if len(exp_ball_list_copy) 0: success 1 probability success/num_experiments return probability4.2 关键行解读__init__中的双重循环把{red: 2, blue: 1}展平成[red, red, blue]blue0时内层range(0)不产生元素天然处理零球颜色。draw采用两条分支当number len(self.contents)时把整个contents交给返回列表并清空帽子满足超额抽取返回全部的规格否则循环number次用random.randrange(len(self.contents))取随机下标并pop同时实现随机性与不放回。experiment预先在函数体外把expected_balls展开为expected_balls_list只展开一次避免在循环内重复劳动exp_ball_list_copy expected_balls_list[:]用切片复制目标列表的副本从而每轮实验都有独立的待匹配清单。匹配采用目标列表里逐个移除已抽到的球的贪心策略每抽到一个球就尝试在剩余目标清单中找到同色项并pop掉一个找不到ValueError就continue。若最终exp_ball_list_copy为空说明所有目标球都被抽中本轮success 1。drawn_list收集每轮结果不是必需的这里主要是为了后续逐轮比对而缓存功能上完全可以边抽边比不必照抄这一结构。五、浏览器内自动化评测机制本项目不是在终端跑pytest而是由 freeCodeCamp 的浏览器端测试栈在挑战页内完成评测。测试代码位于文档# --hints--段通过 pyodide 把学生代码与一段unittest测试模块写入虚拟文件系统再执行main(moduletest_module, exitFalse)收集结果。pyodide.FS.writeFile(/home/pyodide/probability_calculator.py, code); pyodide.FS.writeFile(/home/pyodide/test_module.py, ...unittest 用例...);几点值得注意的工程细节固定随机种子每个测试用例开头都会执行probability_calculator.random.seed(95)。因此评测结果在给定代码下是确定性的——这也是为什么描述中特别提示不要在文件内初始化随机种子否则会覆盖测试方设置的种子、破坏用例断言。模块名约定评测脚本把用户代码写入probability_calculator.py再import。文档正文写的是在main.py中编写两个名字指向同一份浏览器内执行的学生代码挑战页的 Python 运行环境由 python-worker-handler.ts 管理的 Web Worker 承载Python 代码在其中通过 pyodide 解释执行。容差断言概率用例使用assertAlmostEqual(actual, expected, delta0.01)允许估算结果与期望值有 ±0.01 的浮动毕竟蒙特卡洛结果是随机的。F12 可看细节文档特别注明按 F12 打开浏览器控制台可以看到测试更详细的输出便于定位具体失败的用例信息。5.1 四组测试用例逐条解读# --hints--段共定义了四组断言正好对应需要满足的四条行为规格用例 1创建 Hat 对象应生成正确的 contentshat probability_calculator.Hat(red3, blue2) actual hat.contents # 期望 [red,red,red,blue,blue]验证__init__的关键字展开逻辑注意顺序文档示例要求red在前、blue在后即按关键字传入顺序展开。用例 2draw 应返回随机球并减少 contents 数量hat probability_calculator.Hat(red5, blue2) actual hat.draw(2) # seed95 时期望 [blue, red] len(hat.contents) 5 # 2 个球被移走剩 5 个同时验证了随机性返回项因种子固定而确定与不放回contents长度确实减少。用例 3抽取数超过存量时应返回全部球hat probability_calculator.Hat(yellow5,red1,green3,blue9,test1) hat.draw(20) # 只 19 个球要求抽 20 len(hat.contents) 0 # 帽子被清空该用例同时覆盖了任意颜色名test与零余量draw后 contents 为空两个边界。用例 4experiment 应返回合理的概率hat probability_calculator.Hat(blue3, red2, green6) probability experiment(hathat, expected_balls{blue:2,green:1}, num_balls_drawn4, num_experiments1000) # seed95 下期望约 0.272容差 ±0.01 hat probability_calculator.Hat(yellow5, red1, green3, blue9, test1) probability experiment(hathat, expected_balls{yellow:2,blue:3,test:1}, num_balls_drawn20, num_experiments100) # 抽 20 个 抽光全部 19 个球超额抽取返回全部必然满足目标 → 期望 1.0第二个子用例非常巧妙只要每次实验把帽子抽空那么只要目标组合的各色球数不超过帽子初始存量成功就是必然事件概率收敛到1.0。它同时考验了draw的超额返回全部分支在experiment中的串联正确性。六、易错点自查清单综合文档规格与上述用例写完代码后可逐条核对contents是列表而非字典且元素个数之和必须等于各颜色球数之和blue0不应产生元素。draw必须就地修改contents不放回返回值是本次抽出的子列表当number len(self.contents)时返回全部并清空。experiment中每次实验前都要深拷贝帽子copy.deepcopy(hat)不能直接复用同一个对象否则第一轮就把contents抽空了同时把hat作为参数传入也不会影响调用方原对象。expected_balls应解释为至少命中这些球的组合匹配时目标清单允许被抽到的多余球浪费掉continue只要目标项全部被命中即成功。同色多球计数要准确用pop(index)且index取第一个命中位置保证目标 2 个蓝球需要真正抽到 2 个蓝球才算覆盖。不要在文件顶层设置random.seed(...)评测方用seed(95)锁定结果初始化种子会破坏断言。函数返回float概率即success / num_experimentsPython 3 中整数相除自动得到浮点数。描述中帽子总是至少含一个球期望至少 1 红 2 绿这类条件只要被Hat/experiment的通用逻辑覆盖任何颜色名与组合都能工作——评测用例中的test、striped等古怪颜色名正是为了验证这一点。七、延伸阅读完整挑战文档含全部描述、种子代码与官方解5e44414f903586ffb414c950.md本项目的课程排布作为 Scientific Computing with Python 最后一个项目 blockscientific-computing-with-python.jsonPython 挑战运行机制浏览器端通过 Web Worker 加载 pyodide见 python-worker-handler.tschallengeType 23multifilePythonCertProject的类型定义challenge-types.ts理解并跑通本例之后你可以尝试把它推广到更一般的场景调整expected_balls验证至少/恰好两种语义、改用random.sample实现同类不放回抽取、或把成功计数换成collections.Counter做多集合包含判定——这些改进都不改变大量实验统计频率这一蒙特卡洛核心思想。【免费下载链接】freeCodeCampfreeCodeCamp.orgs open-source codebase and curriculum. Learn math, programming, and computer science for free.项目地址: https://gitcode.com/GitHub_Trending/fr/freeCodeCamp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表