如何在循环中每隔 x 步创建一个新列表?

How can I create a new list every x amount of steps in a loop?

我正在 python 上绘制一些随机游走函数并尝试创建它,以便它每 1000 步获取一次随机游走的位置,然后将它们绘制在直方图中。我意识到我可以每次都为 n=1000,2000 等创建一个新列表,然后将 walk 的值附加到该列表,但是有没有办法让 python 创建一个新列表每 1000 步?

import numpy as np 
import matplotlib.pyplot as plt

def random_walk(N,d):       
    walk = d*np.cumsum(2*np.random.binomial(1,.6,N)-1)
    return walk
n1=[]
n2=[]
n3=[]
n4=[]
n5=[]

for k in range(5000):
    particular_walk = random_walk(5000,2)
    n1.append(particular_walk[1000])
    n2.append(particular_walk[2000])
    n3.append(particular_walk[3000])
    n4.append(particular_walk[4000])
    n5.append(particular_walk[-1])


plt.hist(n1,bins=20,histtype='step',density=True)
plt.hist(n2,bins=20,histtype='step',density=True)
plt.hist(n3,bins=20,histtype='step',density=True)
plt.hist(n4,bins=20,histtype='step',density=True)
plt.hist(n5,bins=20,histtype='step',density=True)
plt.show()

这是我目前的代码,但我意识到它不起作用。我知道我可以有一个名为 say "midpoint" 的列表,并将其设置为 2500 处特定步行的位置,但是有没有办法自动执行此操作?

也许您可以使用 python 字典并在字典中创建列表。

可能是这样的:

if k%1000 == 0:
    rw_dict[str(k/1000)]=[]

其中 str(k/1000) 只是字典中键的名称:1.0、2.0 等。每当您需要对该特定列表进行操作时,您可以使用 [= 访问该列表20=][list_name]。

希望对您有所帮助!

通常,您希望在使用 numpy 时排除使用列表的可能性。就时间和 space 而言,数组的效率要高得多。您还应该尽量避免使用显式 Python 循环,因为 numpy 提供的矢量化会更快。

假设您想对 Z 种不同的步行方式执行此操作,其中样本中 Z = 5000 ,但您希望它在一般情况下更大。您可以利用大多数 numpy 函数都可以应用于特定轴这一事实来完成此操作:

import numpy as np 
from matplotlib import pyplot as plt

Z = 5000
N = 5000
d = 2

all_walks = d * np.cumsum(2 * np.random.binomial(1, 0.6, size=(Z, N)) - 1, axis=1)

将步长设置为 (Z, N) 将得到一个包含 Z 行的矩阵,每行有 N 步。用 axis=1 求和意味着对列求和。现在每一行都是一个独立的步行。您可以使用非常基本的切片来获取您想要的任何列。第 n 列将包含每个 Z 步行的第 n 步。您想要制作切片列的原因是这样绘图变得容易得多。

我们来看看n=1000:

n1k = all_walks[:, 1000]
plt.hist(n1k, bins=20, histtype='step', density=True)

到目前为止一切顺利。要每 1000 个样本取一次,请使用索引中的步长:

n = 1000
samples = all_walks[:, n::n]

samples 现在是 Zx(N//n)-1 ((5000, 4)) 数组,包含每个数组中索引 1000, 3000, 4000 处的步骤。在此示例中,您似乎希望总共有五个样本。在我看来,有三种合理的方法可以做到这一点:

  1. 从索引 0 开始:samples = all_walks[:, ::n]
  2. 从索引 n-1 开始:samples = all_walks[:, n-1::n]
  3. 为您的步行添加额外的步数(列):

    all_walks = ... size=(Z, N+1) ...
    samples = all_walks[:, n::n]
    

我不认为通过不一致地添加索引 -1 来弄乱间距是一个特别好的主意。我将改用选项 #2(请记住索引 999 包含第 1000 步)。

好消息是 matplotlib 允许您一次绘制向量的所有列:

plt.hist(samples, bins=20, histtype='step', density=True)

所以整个脚本实际上很短:

import numpy as np 
from matplotlib import pyplot as plt

Z = 5000
N = 5000
d = 2
n = 1000

all_walks = d * np.cumsum(2 * np.random.binomial(1, 0.6, size=(Z, N)) - 1, axis=1)
samples = all_walks[:, n-1::n]
plt.hist(samples, bins=20, histtype='step', density=True)
plt.show()

如果由于某种原因你不能同时在内存中保存一个大小为 Z * N 的数组,你可以使用一次生成一次行走的循环来实现行 all_walks,有点像你最初尝试做的。请记住,这仅在您 Z 一些非常大的数字或由于某种原因没有 RAM 的情况下才会出现:

samples = np.empty((Z, N//n))
for row in range(Z):
    walk = d * np.cumsum(2 * np.random.binomial(1, 0.6, size=N) - 1)
    samples[row] = walk[n-1::n]

如果您从相同的随机种子开始,这两种方法应该会得到相同的结果。主要区别在于第一个占用更多内存,而第二个占用更多时间。