Просто мыслите нестандартно, как насчет реализации функции piecewise_exp()
, которая в основном умножает np.exp()
на arr < 0
?
import numpy as np
def piecewise_exp(arr):
return np.exp(arr) * (arr < 0)
Написание кода, предложенного для функций:
@np.vectorize
def myfun(x):
if x > 0:
return 0.0
else:
return np.exp(x)
def bnaeker_exp(arr):
return np.where(arr > 0, 0, np.exp(arr))
И проверка того, что все согласовано:
np.random.seed(0)
# : test that the functions have the same behavior
num = 10
x = np.random.rand(num) - 0.5
print(x)
print(myfun(x))
print(piecewise_exp(x))
print(bnaeker_exp(x))
Выполнение некоторых микропроцессоров для небольших входов:
# : micro-benchmarks for small inputs
num = 100
x = np.random.rand(num) - 0.5
%timeit np.exp(x)
# 1.63 µs ± 45.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit myfun(x)
# 54 µs ± 967 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit bnaeker_exp(x)
# 4 µs ± 87.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit piecewise_exp(x)
# 3.38 µs ± 59.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
... и для больших входов:
# : micro-benchmarks for larger inputs
num = 100000
x = np.random.rand(num) - 0.5
%timeit np.exp(x)
# 32.7 µs ± 1.78 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit myfun(x)
# 44.9 ms ± 1.17 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit bnaeker_exp(x)
# 481 µs ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit piecewise_exp(x)
# 149 µs ± 2.65 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Это показывает, что piecewise_exp()
быстрее, чем все, что было предложено до сих пор, особенно для больших входов, для которых np.where()
становится более неэффективным, поскольку использует целочисленную индексацию вместо логических масок и разумно приближается к np.exp()
speed.
EDIT
Кроме того, производительность версии np.where()
(bnaeker_exp()
) зависит от количества элементов массива, фактически удовлетворяющих условию.Если ни один из них не подходит (например, при тестировании на x = np.random.rand(100)
), это немного быстрее, чем версия умножения логического массива (piecewise_exp()
) (128 µs ± 3.26 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
на моем компьютере для n = 100000
).