如何在python中模拟随机行走的首次通过时间概率?

如何在python中模拟随机行走的首次通过时间概率?,python,random,simulation,Python,Random,Simulation,我有一个二维随机游动,粒子有相同的概率向左、右、上、下移动或停留在相同的位置。我生成一个从到1到5的随机数来决定粒子移动的方向。粒子将执行n步骤,我将重复模拟几次 我想绘制第一次撞击位于x=-10处的线性屏障的概率F(t)(粒子撞击该点后将消失)。我开始为每个命中陷阱的模拟计算粒子数fp,每次在x=-10位置有一个粒子时,加上值1。在此之后,我绘制了第一次撞击陷阱的粒子数vst,时间步长 导入matplotlib.pyplot作为plt 导入matplotlib 将numpy作为np导入 进口派

我有一个二维随机游动,粒子有相同的概率向左、右、上、下移动或停留在相同的位置。我生成一个从到1到5的随机数来决定粒子移动的方向。粒子将执行
n
步骤,我将重复模拟几次

我想绘制第一次撞击位于
x=-10处的线性屏障的概率
F(t)
(粒子撞击该点后将消失)。我开始为每个命中陷阱的模拟计算粒子数
fp
,每次在
x=-10
位置有一个粒子时,加上值
1
。在此之后,我绘制了第一次撞击陷阱的粒子数vs
t
,时间步长

导入matplotlib.pyplot作为plt
导入matplotlib
将numpy作为np导入
进口派拉布
随机输入
n=1000
n_=1000
x=numpy.zero((n_,n))
y=numpy.zero((n_,n))
步长=np.arange(0,n,1)
对于范围内的i(n_模拟):
对于范围(1,n)内的j:
val=random.randint(1,5)
如果val==1:
x[i,j]=x[i,j-1]+1
y[i,j]=y[i,j-1]
elif val==2:
x[i,j]=x[i,j-1]-1
y[i,j]=y[i,j-1]
elif val==3:
x[i,j]=x[i,j-1]
y[i,j]=y[i,j-1]+1
elif val==4:
x[i,j]=x[i,j-1]
y[i,j]=y[i,j-1]-1
其他:
x[i,j]=x[i,j-1]
y[i,j]=y[i,j-1]
如果x[i,j]=-10:
打破
fp=np.零((n_模拟,n))#每次模拟中击中陷阱的粒子数。
对于范围内的i(n_模拟):
对于范围(1,n)内的j:
如果x[i,j]=-10:
fp[i,j]=fp[i,j-1]+1
其他:
fp[i,j]=fp[i,j-1]
s=[邮政编码(*fp)中x的总和(x)]
plt.xlim(0,1000)
plt.绘图(步骤,s)
plt.show()
我应该有以下情节:

但是我得到的曲线图是不同的,因为曲线总是在增加,而对于较大的
t
,曲线应该会减小(对于较大的
t
,大多数粒子已经击中目标,概率降低)。即使不使用
fp
的和,我也没有得到期望的结果。我想知道我的代码哪里错了。这是我用代码得到的情节


首先,您当前正在计算穿过陷阱的所有粒子的累积和。这个数字必然渐近于
n
。你要找的是累积和的导数,它是每单位时间内穿过陷阱的粒子数

在第二个循环中,需要进行非常简单的更改。更改以下条件

if x[i, j] == -10:
    fp[i, j] = fp[i, j - 1] + 1
else:
    fp[i, j] = fp[i, j - 1]

这是因为布尔值已经是
int
的子类,您希望在每个步骤中存储1或0。这相当于从
if
语句的两个分支的赋值的RHS中删除
fp[i,j-1]

你得到的情节是

这似乎很奇怪,但希望你能看到你已经想要的情节的一线曙光。奇怪的是,穿过陷阱的粒子密度很低。可以通过增加粒子密度或平滑曲线(例如,使用运行平均值)来修复外观

首先,让我们尝试使用以下平滑方法:

除非出现一些规范化问题,否则这将开始大致类似于您正在寻找的曲线。当然,平滑曲线有助于估计绘图的形状,但它可能不是实际可视化模拟的最佳方法。您可能会注意到的一个特殊问题是,曲线左端的值因平均值而严重失真。您可以通过改变窗口的解释方式或使用不同的卷积内核来稍微缓解这种情况,但总会有一些边缘效应

要真正提高结果的质量,您需要增加样本数量。在这样做之前,我建议先优化一下代码

优化#1,如评论中所述,是指您不需要为这个特定问题同时生成
x
y
坐标,因为陷阱的形状允许您将两个方向解耦。相反,你有1/5的概率步进-x和1/5的概率步进+x

优化#2纯粹是为了速度。您不必为
循环运行多个
,而可以以纯矢量化的方式完成所有操作。我还将展示一个示例,因为我通常发现它比

优化#3是为了提高易读性。像
n\u模拟
n
fp
这样的名称,如果没有完整的文档,信息量就不大。我将重命名以下示例中的一些内容,以使代码能够自我记录:

particle_count = 1000000
step_count = 1000

# -1 always floor divides to -1, +3 floor divides to +1, the rest zero
random_walk = np.random.default_rng().integers(-1, 3, endpoint=True, size=(step_count, particle_count), dtype=np.int16)
random_walk //= 3  # Do the division in-place for efficiency
random_walk.cumsum(axis=0, out=random_walk)
这段代码首先使用巧妙的楼层划分技巧,将
随机行走
计算为一系列步骤,以确保每个步骤的比率正好为1/5。然后使用将这些步骤集成到位

步行第一次穿过-10的地方很容易通过掩蔽找到:

steps = (random_walk == -10).argmax(axis=0)
返回第一次出现的最大值。数组
(random_walk==-10)
由布尔值组成,因此它将返回每列中第一次出现的
-10
的索引。在
simulation\u count
步骤中从未穿过
-10
的粒子将在其列中包含所有
False
值,因此
argmax
将返回
0
。由于
0
从来都不是有效的步骤数,因此很容易过滤掉
particle_count = 1000000
step_count = 1000

# -1 always floor divides to -1, +3 floor divides to +1, the rest zero
random_walk = np.random.default_rng().integers(-1, 3, endpoint=True, size=(step_count, particle_count), dtype=np.int16)
random_walk //= 3  # Do the division in-place for efficiency
random_walk.cumsum(axis=0, out=random_walk)
steps = (random_walk == -10).argmax(axis=0)
histogram = np.bincount(steps)
plt.plot(np.arange(2, histogram.size + 1), hist[1:] / particle_count)