从 numpy 数组中有效地采样以相同数字终止的连续整数序列?

efficiently sample sequences of consecutive integers that terminate in the same number from a numpy array?

假设我有以下 numpy 数组:

Space = np.arange(7) 

问题: 我怎样才能从 Space 生成一组 N 个样本,使得:

  1. 每个样本仅由递增或递减的连续数字组成
  2. 采样是通过替换完成的,因此样本不需要单调增加或减少。
  3. 每个样本以 6 或 0 结尾,并且
  4. 样本的长度没有限制(但是,一旦选择了 6 或 0,每个样本就会终止)。

本质上我是通过 numpy 采样创建一个马尔可夫奖励过程(可能有一个更有效的数据包,但我不确定它会是什么。)例如,如果 N = 3,一个可能的采样集看起来像这样。

Sample = [[1,0],[4, 3, 4, 5, 6],[4, 3, 2, 1, 2, 1, 0]]

我可以用一些不太优雅的东西来完成这个:

N = len(Space)
Set = []
for i in range(3):
    X = np.random.randint(N)
    if (X == 0) | (X==6):
        Set.append(X)
    else:
        Sample = []
        while (X !=0) & (X != 6):
            Next = np.array([X-1, X+1])
            X = np.random.choice(Next)
            Sample.append(X)
        Set.append(Sample)
return(Set)

但我想知道还有什么 efficient/pythonic 方法可以进行这种类型的采样,也许没有那么多循环?或者如果有更好的 python 库来处理这类事情?谢谢

Numpy 在这里似乎没什么用,我只是使用标准的 random 模块。主要原因是 random 像该算法一样处理单个值时速度更快,除非需要,否则似乎不需要引入额外的依赖项。

from random import randint, choice

def bounded_path(lo, hi):
    # r covers the interior space
    r = range(lo+1, hi)
    n = randint(lo, hi)
    result = [n]
    while n in r:
        n += choice((-1, 1))
        result.append(n)
    return result

似乎对我来说是对的,例如评估以上 10 次,我得到:

[0]
[4, 3, 4, 3, 2, 1, 0]
[5, 6]
[2, 3, 4, 3, 4, 5, 4, 3, 4, 3, 2, 1, 0]
[1, 0]
[1, 0]
[4, 3, 4, 3, 4, 3, 2, 3, 2, 1, 0]
[3, 2, 3, 2, 1, 0]
[6]
[4, 5, 4, 3, 4, 3, 2, 1, 0]

刚刚做了随机数生成的快速基准比较:

def rng_np(X):
    for _ in range(10):
        X = np.random.choice(np.array([X-1,X+1]))
    return X

def rng_py(X):
    for _ in range(10):
        X += choice((-1, +1))
    return X

Numpy 版本慢了大约 30 倍。 Numpy 必须做很多额外的工作,每次迭代构建一个 Python 数组,转换为 Numpy 数组,切换到 choice 以允许花哨的矢量化。 Python 知道 vanilla 版本中的 (-1, +1) 是常量,所以它只构建一次(例如 dis 有助于查看内部情况)。

您可能可以通过使用更大的数字块来到达某个地方,但我怀疑它会更快。保持起点的一致性似乎很尴尬,但如果你真的很小心,你可能会做一些事情! Numpy 在每次调用都经过大约 10 个值的矢量化时开始收支平衡,并且当您拥有超过 100 个值时真正闪耀。