R语言硬币翻转序列抽样代码正确性验证问询
依赖概率硬币序列抽样统计问题排查
先明确这个硬币是一阶马尔可夫链:
- 出正面后,下一次再出正面的概率是0.6,出反面就是0.4
- 出反面后,下一次再出反面的概率是0.6,出正面就是0.4
按理论来说,稳态下正面和反面的概率都是0.5,而且HH和TT的期望次数应该差不多,TH和HT的期望次数也该近似相等。你结果里曲线没重合,多半是抽样、序列截取或者统计环节的逻辑出问题了。
容易踩的坑
1. 学生序列生成错了
如果生成序列时初始状态固定死是H或者T,不是各50%概率随机选,那初始段的转移统计会直接偏掉。还有转移概率写反的话,整个序列的分布都不对。
2. 有放回抽样的实现问题
重复抽同一个学生时,如果没重新给这个学生选新的x和y,而是用之前用过的截取段,数据重复统计,独立性就没了,结果肯定乱。
3. 序列截取和统计出错
- 截取x到y的序列后,统计的是相邻元素对,比如x到y有y-x+1个元素,相邻对是y-x个。要是统计时算错数量,或者选了x=y(根本没相邻对),结果肯定不对。
- 统计相邻对时,得把第1个和第2个、第2个和第3个……直到倒数第1个和最后一个配对,要是遍历的起始/结束位置错了,统计的就不是连续的相邻对。
正确代码示例
# 设置随机种子,结果能复现 set.seed(123) # 生成单个学生的硬币翻转序列 generate_markov_coin <- function(max_flips = 50) { # 随机给每个学生分配10-50次翻转次数 n_flips <- sample(10:50, 1) # 初始状态随机选H/T,各50%概率 current <- sample(c("H", "T"), 1) sequence <- current for (i in 2:n_flips) { if (current == "H") { current <- sample(c("H", "T"), 1, prob = c(0.6, 0.4)) } else { current <- sample(c("H", "T"), 1, prob = c(0.4, 0.6)) } sequence <- c(sequence, current) } return(sequence) } # 生成100名学生的序列 students_sequences <- replicate(100, generate_markov_coin()) # 单次迭代的抽样统计函数 single_iteration <- function(students) { # 有放回抽100名学生 sampled_students <- sample(students, 100, replace = TRUE) # 初始化四种配对的统计数 total_counts <- c(HH=0, HT=0, TH=0, TT=0) for(seq in sampled_students) { len <- length(seq) if(len < 2) next # 序列太短,没相邻对直接跳过 # 随机选x和y,保证x < y x <- sample(1:(len-1), 1) y <- sample((x+1):len, 1) # 截取子序列 sub_seq <- seq[x:y] # 生成相邻元素对 pairs <- paste(sub_seq[-length(sub_seq)], sub_seq[-1], sep = "") # 统计当前子序列的配对数,累加到总统计里 pair_counts <- table(pairs) for(p in names(pair_counts)) { total_counts[p] <- total_counts[p] + pair_counts[p] } } return(total_counts) } # 重复1000次迭代 results <- replicate(1000, single_iteration(students_sequences)) # 转成数据框方便查看 results_df <- as.data.frame(t(results)) # 看各配对的平均次数 colMeans(results_df) # 画图验证曲线 plot(results_df$HH, type = "l", col = "red", ylim = c(0, max(results_df)), main = "HH vs TT, TH vs HT") lines(results_df$TT, col = "blue") lines(results_df$TH, col = "green") lines(results_df$HT, col = "orange") legend("topright", legend = c("HH", "TT", "TH", "HT"), col = c("red", "blue", "green", "orange"), lty = 1)
代码关键细节
- 生成序列时初始状态随机选H/T,避免初始偏差;转移概率严格按题目要求设置。
- 每次抽学生后,都重新给这个学生选x和y,保证每次截取的子序列都是独立的。
- 截取后用
sub_seq[-length(sub_seq)]和sub_seq[-1]配对,准确生成相邻元素对,用table计数不会出错。 - 跳过长度不足2的序列,避免无效统计。
验证效果
跑这段代码的话,colMeans(results_df)里HH和TT的均值会很接近,TH和HT的均值也差不多,画出来的曲线基本重合,符合理论预期。你可以对比自己的代码,看看是不是踩了上面说的坑。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

