Это самая быстрая процедура, которую я нашел до сих пор, которая не использует Cython или JIT, как Numba. На моей машине у меня уходит около 1,6 мкс для обработки массива 4x4 (среднее время по списку массивов 4K4 размером 100 КБ):
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]
Вот еще несколько вещей, которые я пробовал, но не так быстро:
Вышеприведенный код, но без кеша. Принимает около 8,3 мкс на массив 4x4:
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. Принимает около 2,5 мкс на массив 4x4:
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
. Принимает около 11,9 мкс на массив 4x4:
def upper_triangular_to_symmetric(ut):
ut += np.triu(ut, k=1).T
Cython-версия вложенного цикла Python. Я новичок в Cython, так что это не может быть полностью оптимизировано. Поскольку Cython добавляет эксплуатационные накладные расходы, мне интересно услышать ответы как от Cython, так и от чистого Numpy. Принимает около 0,6 мкс на массив 4x4:
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]