R语言蒙特霍尔问题模拟报错:sample.int无效参数及向量迭代问题
蒙特霍尔问题R语言模拟报错解决
问题场景
在统计课程中用R模拟蒙特霍尔问题,计划通过10000次实验验证换门胜率2/3、不换门胜率1/3的结论。已完成不换门的模拟,但编写主持人开门函数时遇报错:
- 调用
revealed_door函数时出现:Error in sample.int(length(x), size, replace, prob) : invalid first argument - 尝试用
all_doors[-initial_choice]替代setdiff时,出现only 0’s may be mixed with negative subscripts错误,还出现过结果全为NA的情况
当前revealed_door函数及换门逻辑代码如下:
## 原主持人开门函数 revealed_door = function(initial_choice, car_door, all_doors){ ## if-else to determine which doors can be revealed and reveal one ifelse(car_door == initial_choice, sample(setdiff(all_doors, initial_choice), 1), setdiff(all_doors, c(initial_choice, car_door))) } ## 原换门逻辑 switch_wins = 0 ## Switch doors reveal = revealed_door(initial_choice, car_door, all_doors) new_choice = all_doors[-c(reveal, initial_choice)] ## Count wins ifelse(car_door == new_choice, switch_wins + 1, switch_wins) total_switch_wins = sum(switch_wins) ## Divide wins by n to calculate probability switch_win_prob = total_switch_wins / 10000 print(switch_win_prob)
注:car_door和initial_choice均为长度10000的向量,元素取自1:3;all_doors为c(1,2,3)
错误原因
ifelse与sample的不兼容:ifelse是向量化操作,但sample是标量函数。当initial_choice是长度10000的向量时,setdiff(all_doors, initial_choice)会返回all_doors中不在整个initial_choice向量里的元素(而非逐元素移除对应值),导致sample的输入不符合预期,触发sample.int报错。- 向量索引错误:
all_doors[-initial_choice]中,若initial_choice是向量,负索引会被当成整体位置移除,而非逐元素处理,导致索引越界或逻辑错误。 - 换门计数逻辑错误:
switch_wins = 0是单个数值,ifelse不会修改它的值,最终sum(switch_wins)始终为0。
修正代码
1. 修正主持人开门函数
使用sapply逐元素处理每一次实验的初始选择和奖品门,确保每次都正确计算主持人要打开的门:
revealed_door = function(initial_choice, car_door, all_doors) { sapply(seq_along(initial_choice), function(i) { ic = initial_choice[i] cd = car_door[i] if (cd == ic) { # 玩家选对了,主持人随机开剩下两扇门中的一个 sample(setdiff(all_doors, ic), 1) } else { # 玩家选错了,主持人只能开剩下那扇没车的门 setdiff(all_doors, c(ic, cd)) } }) }
2. 修正换门计数逻辑
直接用向量运算统计获胜次数,避免单个数值的错误赋值:
# 生成10000次实验的随机数据 n = 10000 all_doors = c(1,2,3) car_door = sample(all_doors, n, replace = TRUE) initial_choice = sample(all_doors, n, replace = TRUE) # 不换门的胜率(验证用) stay_win_prob = mean(car_door == initial_choice) cat("不换门胜率:", stay_win_prob, "\n") # 换门逻辑 reveal = revealed_door(initial_choice, car_door, all_doors) # 计算换门后的选择:排除初始选择和主持人打开的门 new_choice = sapply(seq_along(initial_choice), function(i) { setdiff(all_doors, c(initial_choice[i], reveal[i])) }) # 统计换门获胜次数 total_switch_wins = sum(car_door == new_choice) switch_win_prob = total_switch_wins / n cat("换门胜率:", switch_win_prob, "\n")
运行说明
- 运行后会输出不换门和换门的胜率,多次运行后换门胜率会趋近于2/3,不换门胜率趋近于1/3,符合蒙特霍尔问题的结论。
- 核心修正点是逐元素处理每一次实验,而非对整个向量做批量操作,确保逻辑符合单次实验的规则。
内容的提问来源于stack exchange,提问作者bay
相关产品推荐
相关产品推荐

