import numpy as np
import scipy.sparse
from numpy.random import default_rng
rand = default_rng(seed=0)
N = 100
x = rand.integers(0, 10, (N, 2))
A = np.clip(rand.integers(0, 100, (N, N)) - 80, a_min=0, a_max=None)
diff = (x[:, None, :] - x[None, :, :])**2
product = np.einsum("ij,ijk->k", A, diff)
s_loop = [0, 0]
for i in range(N):
for j in range(N):
for k in range(2):
s_loop[k] += A[i, j]*(x[i, k] - x[j, k])**2
assert np.allclose(product, s_loop)
A_i_nz, A_j_nz = A.nonzero()
diff = (x[A_i_nz, :] - x[A_j_nz, :])**2
s_semidense = A[A_i_nz, A_j_nz].dot(diff)
assert np.allclose(product, s_semidense)
A_sparse = scipy.sparse.coo_array(A)
diff = (x[A_sparse.row, :] - x[A_sparse.col, :])**2
s_sparse = A_sparse.data.dot(diff)
assert np.allclose(product, s_sparse)
看起来相当快;这大约需要一秒钟完成:
N = 100_000_000
print(f'Big test: initialising a {N}x{N} array')
n_values = 10_000_000
A = scipy.sparse.coo_array(
(
rand.integers(0, 100, n_values),
rand.integers(0, N, (2, n_values)),
),
shape=(N, N),
)
x = rand.integers(0, 100, (N, 2))
print('Big test: calculating')
s = A.data.dot((x[A.row, :] - x[A.col, :])**2)
print(s)
diff
比a
(形状)大20倍,且密集。 - hpauljeinsum
能够正常工作,也不会改善内存使用情况。您仍然需要计算三维diff
。我认为np.einsum('ij,ijk->k, a.A, diff)
和np.sum(a.A[:,:,None]*diff), axis=(0,1))
将具有类似的内存使用情况,相当于在临时缓冲区中复制三维diff
一到两次。(注意,我通常不进行精细的内存使用跟踪,并且不想用潜在的内存错误来挂起我的机器。) - hpaulj\sigma_k = \sum_i^N \sum_j^N A_{i,j} (x_{i,k} - x_{j,k})^2
。 - Reinderien