title: Masking a Numpy array and applying a calculation per mask without using a for loop
body: <p>Let's say we have the following data array:</p>
  
  <pre><code>data_array = np.array([[1, 1, 1], [1, 1, 2], [2, 2, 2], [3, 3, 3], [4, 4, 4]], np.int16)
  
  data_array
  array([[1, 1, 1],
         [1, 1, 2],
         [2, 2, 2],
         [3, 3, 3],
         [4, 4, 4]])
  </code></pre>
  
  <p>And we want to mask the array according to the following ranges to be able to apply a calculation on the masked parts:</p>
  
  <pre><code>intervals = [[1, 2], [2, 3], [3, 4]]
  </code></pre>
  
  <p>We first create an empty array and mask based on the data array so we can combine the results for each masked array:</p>
  
  <pre><code>init = np.zeros((data_array.shape[0], data_array.shape[1]))
  result_array = np.ma.masked_where((init == 0), init)
  
  result_array
  masked_array(
  data=[[--, --, --],
        [--, --, --],
        [--, --, --],
        [--, --, --],
        [--, --, --]],
  mask=[[ True,  True,  True],
        [ True,  True,  True],
        [ True,  True,  True],
        [ True,  True,  True],
        [ True,  True,  True]]
  </code></pre>
  
  <p>With this we can start a for loop that masks the array according the the interval ranges, performs a calculation on the masked array and combines to results to a single result array:</p>
  
  <pre><code>for inter in intervals:
  
      # Extact the start and en values for interval range
      start_inter = inter[0]
      end_inter = inter[1]
  
      # Mask the array based on interval range
      mask_init = np.ma.masked_where((data_array &gt; end_inter), data_array)
      masked_array = np.ma.masked_where((mask_init &lt; start_inter), mask_init)
  
      # Perform a dummy calculation on masked array
      outcome = (masked_array + end_inter) * 100
  
      # Combine the outcome arrays
      result_array[result_array.mask] = outcome[result_array.mask]
  </code></pre>
  
  <p>With the following result:</p>
  
  <pre><code>array([[300.0, 300.0, 300.0],
        [300.0, 300.0, 400.0],
        [400.0, 400.0, 400.0],
        [600.0, 600.0, 600.0],
        [800.0, 800.0, 800.0]])
  </code></pre>
  
  <p>The question I have is, how can the same result be achieved without using this for loop? So applying the masking and calculation for the whole data_array in a single operation. Note that the calculation's variables change with each mask. Is it possible to apply a vectorized approach to this problem? I would imagine <a href="https://pypi.org/project/numpy-indexed/" rel="nofollow noreferrer">numpy_indexed</a> could be of some help. Thank you. </p>