python - Efficient way to do math in elements of a numpy array according to condition -
i trying optimize python code. 1 of bottlenecks comes when tried apply function numpy array according each element value. instance, have array thousand elements , apply function values greater tolerance , function (taylor series) rest. masking still slow, @ least i'm calling following functions 64 millions times.
epsilonzeta = 1.0e-6 zeta1_12 = 1.0/12.0 zeta1_720 = 1.0/720.0 def masked_condition_zero(array, tolerance): """ return indices values lesser (and greater) tolerance """ # search indices array values < tolerance indzeros_ = np.where(np.abs(array) < tolerance)[0] # create mask mask_ = np.ones(np.shape(array), dtype=bool) mask_[[indzeros_]] = false return (~mask_, mask_) def bernoulli_function1(zeta): """ returns bernoulli function of zeta, vector version """ # indices according condition zeros_, others_ = masked_condition_zero(zeta, epsilonzeta) # create array filled zeros fb_ = np.zeros(np.shape(zeta)) # apply original function values greater epsilonzeta fb_[others_] = zeta[others_]/(np.exp(zeta[others_])-1.0) # computes series zeta < eps zeta0_ = zeta[zeros_] zeta2_ = zeta0_ * zeta0_ zeta4_ = zeta2_ * zeta2_ fb_[zeros_] = 1.0 - 0.5*zeta0_ + zeta1_12 * zeta2_ - zeta1_720 * zeta4_ return fb_
now suppose have array zeta negative , positive floats changes in each loop extends 2^26 iterations , want compute fbernoulli_function1(zeta) each time.
there better solution ?
the basic structure of problem is:
def foo(zeta): result = np.empty_like(zeta) = condition(zeta) ni = ~i result[i] = func1(zeta[i]) result[ni] = func2(zeta[ni])
it looks polynomial expression can evaluated @ zeta
, 'exception', fall calculation when zeta
close 0.
if both functions can evaluated zeta
, use where:
np.where(condition(zeta), func1(zeta), func2(zeta))
this streamlined version of:
def foo(zeta): result = np.empty_like(zeta) = condition(zeta) ni = ~i v1 = func1(zeta) v2 = func2(zeta) result[i] = v1[i] result[ni] = v2[ni]
another option apply 1 function values, , other 'exceptions'.
def foo(zeta): result = func2(zeta) = condition(zeta) result[i] = func1[zeta[i]]
and of course reverse - result = func1(zeta); result[ni]=func2[zeta]
.
in brief time tests, func1
, func2
take same time.
masked_condition_zero
takes time, simpler np.abs(array) < tolerance
(and it's ~j
) cuts in half.
lets compare allocation strategies
def foo(zeta, j, nj): result = np.empty_like(zeta) result[j] = fun1(zeta[j]) result[nj] = fun2(zeta[nj]) return result
for sample zeta[j]
10% of full zeta
, sample times are:
in [127]: timeit foo(zeta, j, nj) 10000 loops, best of 3: 55.7 µs per loop in [128]: timeit result=fun2(zeta); result[j]=fun1(zeta[j]) 10000 loops, best of 3: 49.2 µs per loop in [129]: timeit np.where(j, fun1(zeta),fun2(zeta)) 10000 loops, best of 3: 73.4 µs per loop in [130]: timeit result=fun1(zeta); result[nj]=fun2(zeta[nj]) 10000 loops, best of 3: 60.7 µs per loop
the second case fastest because running fun1
on fewer values compensates added cost of indexing zeta[j]
. there's trade off between cost of indexing , cost of function evaluation. boolean indexing more expensive slicing. other mixes of values, timings go other direction.
it looks problem can whittle away @ times, don't see break though stategy cut times order of magnitude.
Comments
Post a Comment