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

加速一维随机游走模拟:提升马尔可夫链仿真效率的方法咨询

一维随机游走模拟效率优化问题

问题背景

一个变量以0.5的概率+1,0.5的概率-1移动(一维随机游走马尔可夫链),起始位置为5。

场景1

求该变量首次到达位置0的期望时间?

场景2

求该变量在至少到达过位置10后,首次到达位置0的期望时间?

尝试的模拟代码(运行耗时过长已中断)

# the simulations can take a long time to run, I interrupted them

library(ggplot2)
library(gridExtra)

n_sims <- 100
times_to_end_0 <- numeric(n_sims)
times_to_end_0_after_10 <- numeric(n_sims)
paths_0 <- vector("list", n_sims)
paths_0_after_10 <- vector("list", n_sims)

for (i in 1:n_sims) {
    print(paste("Running simulation", i, "for situation 1..."))
    y <- 5
    time <- 0
    path_0 <- c(y)

    while(y > 0) {
        step <- sample(c(-1, 1), 1, prob = c(0.5, 0.5))
        y <- y + step
        path_0 <- c(path_0, y)
        time <- time + 1

        if (y == 0) {
            times_to_end_0[i] <- time
            paths_0[[i]] <- data.frame(time = 1:length(path_0), y = path_0, sim = i)
            break
        }
    }

    print(paste("Running simulation", i, "for situation 2..."))
    y <- 5
    time <- 0
    reached_10 <- FALSE
    path_0_after_10 <- c(y)

    while(y > 0 || !reached_10) {
        step <- sample(c(-1, 1), 1, prob = c(0.5, 0.5))
        y <- y + step
        path_0_after_10 <- c(path_0_after_10, y)
        time <- time + 1

        if (y == 10) {
            reached_10 <- TRUE
        }

        if (y == 0 && reached_10) {
            times_to_end_0_after_10[i] <- time
            paths_0_after_10[[i]] <- data.frame(time = 1:length(path_0_after_10), y = path_0_after_10, sim = i)
            break
        }
    }
}

df1 <- data.frame(time = times_to_end_0)
df2 <- data.frame(time = times_to_end_0_after_10[times_to_end_0_after_10 > 0])

mean1 <- mean(log(df1$time))
mean2 <- mean(log(df2$time))

p1 <- ggplot(df1, aes(x = log(time))) +
    geom_density() +
    geom_vline(aes(xintercept = exp(mean1)), color = "red", linetype = "dotted") +
    labs(title = paste("Density of Times to Reach 0 - Mean Time:", round(exp(mean1), 2)), x = "Time", y = "Density") + theme_bw()

p2 <- ggplot(df2, aes(x = log(time))) +
    geom_density() +
    geom_vline(aes(xintercept = exp(mean2)), color = "red", linetype = "dotted") +
    labs(title = paste("Density of Times to Reach 0 After Reaching 10 - Mean Time:", round(exp(mean2), 2)), x = "Time", y = "Density") + theme_bw() 

plot_df_0 <- do.call(rbind, paths_0)

p3 <- ggplot(plot_df_0, aes(x = log(time), y = y, group = sim)) +
    geom_line() +
    labs(title = "Paths of First Simulation", x = "Time", y = "Y") +
    theme_bw()

plot_df_0_after_10 <- do.call(rbind, paths_0_after_10)

p4 <- ggplot(plot_df_0_after_10, aes(x = log(time), y = y, group = sim)) +
    geom_line() +
    labs(title = "Paths of Second Simulation", x = "Time", y = "Y") +
    theme_bw()

grid.arrange(p1, p2, p3, p4, ncol = 2)

效率优化方法

1. 批量生成随机步长,减少采样开销

每次调用sample都会产生额外性能损耗,预先生成大量随机步长数组,模拟时直接取用,用完再补充:

# 预先生成1e6个步长
large_steps <- sample(c(-1, 1), 1e6, replace = TRUE, prob = c(0.5, 0.5))
step_ptr <- 1

# 模拟循环内直接调用预先生成的步长
while(y > 0) {
    y <- y + large_steps[step_ptr]
    step_ptr <- step_ptr + 1
    time <- time + 1
    # 步长耗尽时重新生成
    if(step_ptr > length(large_steps)) {
        large_steps <- sample(c(-1, 1), 1e6, replace = TRUE)
        step_ptr <- 1
    }
    if(y == 0) break
}

2. 避免动态扩展向量

c(path_0, y)会频繁重新分配内存,预先给路径向量分配足够大的初始空间,模拟结束后截断到实际长度:

max_steps <- 1e5  # 预设足够大的步数上限
path_0 <- numeric(max_steps)
path_0[1] <- 5
y <- 5
time <- 0
idx <- 2

while(y > 0 && idx <= max_steps) {
    y <- y + large_steps[step_ptr]
    step_ptr <- step_ptr + 1
    time <- time + 1
    path_0[idx] <- y
    idx <- idx + 1
    if(y == 0) break
}
# 截断到实际路径长度
path_0 <- path_0[1:(idx-1)]

3. 移除冗余操作,简化循环逻辑

删除循环内的print进度语句(仅在必要时批量输出),减少循环内的条件判断嵌套,提升单循环执行效率。

4. 采用解析解替代模拟

对于对称一维随机游走,这两个场景存在精确解析结论,无需模拟:

  • 场景1:从位置5出发首次到达0的期望时间为无穷大,因为随机游走会无限徘徊,样本中会出现极长时间的路径,导致模拟无法收敛。
  • 场景2:从位置5出发,先到达10再到达0的期望时间同样为无穷大,原因同上。

5. 并行化模拟

若坚持模拟,可使用R的并行包将模拟任务分配到多个核心运行:

library(parallel)
n_cores <- detectCores() - 1
cl <- makeCluster(n_cores)

# 定义场景1的单模拟函数
sim_scenario1 <- function() {
    y <- 5
    time <- 0
    while(y > 0) {
        y <- y + sample(c(-1,1), 1)
        time <- time + 1
        if(y == 0) break
    }
    time
}

# 并行运行100次模拟
times_to_end_0 <- parSapply(cl, 1:100, function(x) sim_scenario1())

stopCluster(cl)

内容的提问来源于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.02 04:32:33