我需要完全随机翻转
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))
您正在进行大量迭代,特别是在两个最内部的 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)