Это можно легко векторизовать, передавая новые оси массивам.В результате узкое место norm.logpdf
будет выполнено только один раз:
log_lh = norm.logpdf(y, loc=B0[..., None] + B1[..., None] * x[None, None, :]).sum(axis=2)
# comparison with LogLik:
np.allclose(LogLik, log_lh)
# Out: True
Преобразование этого в функцию позволит рассчитать время выполнения:
def loglik(x, y, B0, B1):
return norm.logpdf(y, loc=B0[..., None] + B1[..., None] * x[None, None, :]).sum(axis=2)
def loglik_loop(x, y, B0, B1):
LogLik = 0
for xs, ys in zip(x, y):
LogLik+= norm.logpdf(ys, loc=B0+B1*xs)
%timeit loglik(x, y, B0, B1)
# Out: 94.1 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit loglik_loop(x, y, B0, B1)
# Out: 54 ms ± 4.25 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Как видите,похоже, это один из редких случаев, когда векторизация кода не улучшает производительность .Кажется, в модуле norm
модуля scipy есть еще одно узкое место, которое снижает производительность при работе с многомерными массивами.
В результате ваша единственная возможность улучшить производительность вашего кода будет заключаться в следующем:реализовать параллельное выполнение цикла (замена оператора +=
назначением фиксированного массива и последующим суммированием).