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

Popular posts from this blog

Java 3D LWJGL collision -

spring - SubProtocolWebSocketHandler - No handlers -

methods - python can't use function in submodule -