使用numpy与pandas从DF随机选择,10万次后分布不符合预期
D&D施法概率脚本问题分析与优化方案
问题原因
当前方案出现概率偏差的核心原因无非两种:
- 行数计算不精准:如果原法术DataFrame的行数是奇数,你没办法精准追加“原DF一半”的行数(比如原DF有95行,只能加47或48行),导致三类结果的总行数比例偏离预期的50/25/25,采样概率自然跟着偏差。
- 统计逻辑出错:要是你统计结果时,把“随机采样到当前指定法术”的情况从“随机法术”类别里拆分出来,会直接拉低“随机法术”的占比,同时让“原法术生效”的统计值混入随机命中的情况,出现数据偏差。
另外,10万次采样出现3%左右的偏差,绝对不是随机误差,肯定是代码里的行数计算或者统计逻辑出了问题,比如你可能误把追加行数设成了原DF的其他比例,而非准确的一半。
优化方案
没必要修改原DataFrame去追加大量重复行,直接用下面两种方法就能实现精准概率,逻辑更清晰,效率也更高:
方案一:分阶段随机选择(推荐)
先按概率确定事件类型,再执行对应逻辑,完全贴合你的需求:
import random import pandas as pd # 示例原法术列表 spell_df = pd.DataFrame({"spell_name": ["火球术", "治愈术", "闪电术", "隐身术"]}) # 当前施法者要放的目标法术 target_spell = "火球术" def cast_spell(): # 第一步:按设定概率选事件类型 event = random.choices( ["随机法术", "原法术生效", "无效果"], weights=[0.5, 0.25, 0.25], k=1 )[0] if event == "随机法术": # 从原法术里随机挑一个 return spell_df.sample(n=1).iloc[0]["spell_name"] elif event == "原法术生效": return target_spell else: return "无效果" # 10万次测试示例 results = [cast_spell() for _ in range(100000)] random_rate = sum(1 for res in results if res in spell_df["spell_name"].values and res != target_spell) / 100000 original_rate = sum(1 for res in results if res == target_spell) / 100000 nothing_rate = sum(1 for res in results if res == "无效果") / 100000 print(f"随机法术占比:{random_rate:.2%}") print(f"原法术生效占比:{original_rate:.2%}") print(f"无效果占比:{nothing_rate:.2%}")
方案二:带权重直接采样
把所有可能结果整合到一个列表,通过权重分配实现精准概率:
import random import pandas as pd spell_df = pd.DataFrame({"spell_name": ["火球术", "治愈术", "闪电术", "隐身术"]}) target_spell = "火球术" # 构建所有可选结果 all_options = spell_df["spell_name"].tolist() + [target_spell, "无效果"] # 分配权重:随机法术总权重0.5,分摊到每个法术;原法术和无效果各占0.25 weights = [0.5 / len(spell_df)] * len(spell_df) + [0.25, 0.25] def cast_spell(): return random.choices(all_options, weights=weights, k=1)[0] # 测试逻辑同上,此处省略
内容的提问来源于stack exchange,提问作者DrakeMurdoch
相关产品推荐
相关产品推荐

