1

What is the proper way to adaptively affect elements of a numpy array? I came up with 2 methods: Using masks, and using numpy's where function:

import numpy as np
from numpy.core.umath_tests import inner1d
import time


# Make a large array of 3d points & iterate
vec = np.random.rand(1000000,3) * 100

# Method 1: Iterate with MASK
def MASK():
    vec0 = np.array(vec)
    while True:

        # Calculate magnitudes and generate mask
        mag = inner1d(vec0,vec0)
        mask = mag >= 1

        # If all masks = False, break
        if not np.ma.max(mask):
            break

        # Apply fancy expensive math on desired elements
        vec0[mask] = vec0[mask] * 0.5

    return vec0


# Method 2: Iterate with WHERE
def WHERE():
    vec1 = np.array(vec)
    while True:

        #Calculate magnitudes
        mag = inner1d(vec1,vec1)

        # If all magnitudes meet criteria, break
        if (mag < 1).all():
            break

        # Apply fancy expensive math on desired elements
        vec1[np.where(mag >= 1)] *= 0.5

    return vec1



t = time.time()
m = MASK()
t = time.time() - t
print 'MASK:  %s'%t

t = time.time()
w = WHERE()
t = time.time() - t
print 'WHERE: %s'%t
print np.allclose(m,w) 

Results:

>>> 
MASK:  0.586141109467
WHERE: 0.477689981461
True
>>> 

Method #2 was slightly faster, which is good! Are there any other methods to do this more efficiently?

Fnord
  • 5,365
  • 4
  • 31
  • 48
  • 3
    Looks mostly fine to me, maybe look at http://stackoverflow.com/q/6299770/553404 for a faster way to compute the magnitudes, and you can skip the square root, just threshold with the square of the value...which in this case is also `1`. Also, compute the mask as `[mask = mag >= 1]` and avoid the inversion. – YXD Jul 31 '15 at 09:33

0 Answers0