这是迄今为止我发现的最快的例程,它不使用 Cython 或像 Numba 这样的 JIT。我在我的机器上处理一个 4x4 数组大约需要 1.6 μs(100K 4x4 数组列表的平均时间):
inds_cache = {}
def upper_triangular_to_symmetric(ut):
n = ut.shape[0]
try:
inds = inds_cache[n]
except KeyError:
inds = np.tri(n, k=-1, dtype=np.bool)
inds_cache[n] = inds
ut[inds] = ut.T[inds]
以下是我尝试过的其他一些不太快的方法:
上面的代码,但是没有缓存。每个 4x4 阵列大约需要 8.3 μs:
def upper_triangular_to_symmetric(ut):
n = ut.shape[0]
inds = np.tri(n, k=-1, dtype=np.bool)
ut[inds] = ut.T[inds]
一个普通的 Python 嵌套循环。每个 4x4 阵列大约需要 2.5 μs:
def upper_triangular_to_symmetric(ut):
n = ut.shape[0]
for r in range(1, n):
for c in range(r):
ut[r, c] = ut[c, r]
使用np.triu 进行浮点加法。每个 4x4 阵列大约需要 11.9 μs:
def upper_triangular_to_symmetric(ut):
ut += np.triu(ut, k=1).T
Numba 版本的 Python 嵌套循环。这是我发现的最快的东西(每个 4x4 数组大约 0.4 μs),并且是我最终在生产中使用的东西,至少在我开始遇到 Numba 问题并不得不恢复到纯 Python 版本之前:
import numba
@numba.njit()
def upper_triangular_to_symmetric(ut):
n = ut.shape[0]
for r in range(1, n):
for c in range(r):
ut[r, c] = ut[c, r]
Python 嵌套循环的 Cython 版本。我是 Cython 的新手,所以这可能没有完全优化。由于 Cython 增加了运营开销,我有兴趣听到 Cython 和纯 Numpy 的答案。每个 4x4 阵列大约需要 0.6 μs:
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def upper_triangular_to_symmetric(np.ndarray[np.float64_t, ndim=2] ut):
cdef int n, r, c
n = ut.shape[0]
for r in range(1, n):
for c in range(r):
ut[r, c] = ut[c, r]