Распределение памяти является ограничивающей частью
Если вы используете такие функции, как sqrt, exp, sin, потому что убедитесь, что вы установили Intel SVML . Также добавьте все, что вы пробовали до сих пор и как вы получили время.
Ваше решение Numpy использует временные массивы, поэтому должно быть достаточно места для улучшения.
Пример
import numpy as np
import numba as nb
def calc_M(x,y):
M = x[:,:,None] - y[None,None,:]
i_pos = M>0
M[i_pos] = np.sqrt(M[i_pos])
M[~i_pos] = -np.inf
return M
@nb.njit(parallel=True)
def calc_M_nb_1(x,y):
res=np.empty((x.shape[0],x.shape[1],y.shape[0]))
for i in nb.prange(x.shape[0]):
for j in range(x.shape[1]):
for k in range(y.shape[0]):
val= x[i,j]-y[k]
if val>0:
res[i,j,k]=np.sqrt(val)
else:
res[i,j,k]=-np.inf
return res
@nb.njit(parallel=True)
def calc_M_nb_2(x,y,res):
for i in nb.prange(x.shape[0]):
for j in range(x.shape[1]):
for k in range(y.shape[0]):
val= x[i,j]-y[k]
if val>0:
res[i,j,k]=np.sqrt(val)
else:
res[i,j,k]=-np.inf
return res
Время
x = np.arange(10000,dtype=np.float64).reshape(100,100)
y = np.arange(4000,dtype=np.float64)
res=np.empty((x.shape[0],x.shape[1],y.shape[0]))
%timeit res_1=calc_M(x,y)
469 ms ± 3.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_2=calc_M_nb_1(x,y)
79.5 ms ± 671 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
res=np.empty((x.shape[0],x.shape[1],y.shape[0]))
%timeit res_3=calc_M_nb_2(x,y,out)
25.5 ms ± 204 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Если сравнить время calc_M_nb_2
и calc_M_nb_1
видно, что выделение памяти занимает больше времени, чем все вычисления, что не является редким случаем в простых функциях. Конечно, не всегда возможно избежать выделения памяти, но если вы хотите применить эту функцию ко многим аналогичным входам (размер массива), вы можете получить некоторое ускорение.