随机翻转多个二维矩阵中的 n 个元素

问题描述 投票:0回答:1

我需要完全随机翻转

n
(
n>2
) 个选定的元素(均匀分布)在
m
具有不同大小的 2d numpy 矩阵中(参见我的代码的初始化),我将其存储在字典中,每个我的模拟时间(总共大约
10^(7-8)
次)。

以下代码本身有效,此处的循环

N
用于测试速度。如果有人能告诉我一种更快地做到这一点的方法,我会很高兴。 <3

进一步说明:我还尝试首先将临时一维矩阵的索引转换为二维矩阵(

numpy.unravel_index
),然后仅更改我的条目,但在高维度中速度更慢。

# Initialization
import numpy as np
import time
rng = np.random.default_rng(seed=1)
sizes = [700, 27, 48, 20]# code must work for any numbers, usually in the range of~1-1000
num_layers = len(sizes)
params = np.sum([sizes[i]*sizes[i+1] for i in range(num_layers-1)])
w = dict((key, rng.choice([-1, 1], size=(y, x))) for key, (x, y) in enumerate(zip(sizes[:-1], sizes[1:])))# e.g. 27x700, 48x27, 20x48


# The problematic part...
N = 1001
start = time.time()
for i in range(N):# just for testing the speed a little
    # 1) Generate n random numbers idx (1d) (replace is a must, since we need exactly n), then store the old matrices away for later usage.
    n = rng.integers(2, high=params+1)
    idx = rng.choice(np.arange(params), size=(n,), replace=False)
    w_old = dict((key, np.copy(w)) for key, w in sorted(w.items()))
    # 2) Initialize matrices with ones.
    w_flip = dict((key, np.ones((sizes[i]*sizes[i+1]), dtype=np.int32)) for key, i in enumerate(range(num_layers-1)))
    # 3) Flip the spins of this temporary matrix and reshape it afterwards into a 2d one
    left = 0
    for i in range(num_layers-1):
        right = left + sizes[i]*sizes[i+1] 
        w_flip[i][idx[np.where(np.logical_and(idx>=left, idx<right))]-left] *= -1
        w_flip[i] = np.reshape(w_flip[i], (sizes[i+1], sizes[i]))
        left = right
    # 4) Flip the n entries of the m matrices
    for (_,w_i), (__,w_flip_i) in zip(w.items(), w_flip.items()):
        w_i *= w_flip_i
    # ... here I do other stuff with the changed matrices, but that's irrelevant to the topic at hand.
end = time.time()
print(end-start)


# Test if algorithm works (just for me)
for (_,w_i), (__,w_flip_i) in zip(w.items(), w_flip.items()):
    w_i *= w_flip_i
diff = 0
for i in range(len(w)):
    diff = np.sum(w[i] != w_old[i])
if diff != 0:
    print("Something wrong with the algorithm, diff = {0} != 0.".format(diff))
python numpy random
1个回答
0
投票

您正在进行大量迭代,特别是在两个最内部的 for 循环中。 要翻转数组元素的符号,您可以使用逻辑非运算符

~
并加 1。示例:

>>> import numpy as np
>>> a = np.array([-1, 0, 1, 2])
>>> ~a + 1
array([ 1,  0, -1, -2])

对于您的示例,使用种子生成器来翻转数组中的

n
项的简单函数如下所示:

def flip_n(arr: np.ndarray, n: int, rng: np.random.Generator) -> np.ndarray:
    idx = rng.choice(np.arange(arr.size), size=(n,), replace=False)
    arr_flat = arr.ravel()
    arr_flat[idx] = ~arr.ravel()[idx] + 1
    return arr_flat.reshape(*arr.shape)

请注意,此操作确实会影响存储在

w
中的原始数组。

您可以通过循环进行测试:

N = 1001
start = time.time()
for _ in range(N):
    for arr in w.values():
        n = rng.integers(2, high=arr.size)
        flip_n(arr, n, rng)
end = time.time()
print(end-start)
© www.soinside.com 2019 - 2024. All rights reserved.