You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 05:37:39