Scientific Python 2: Elegant Arrays
 Make use of numpy APIs
 Assigning values for multidimensional arrays
 The test case for following scenarios
 Looking for elements that satisfy the predicate
 Replacing elements that satisfy the predicate
 Replacing elements according to a “dictionary”
Unlike programming in C++, where loops are extremely efficient, the loops in Python are notoriously slow. Usually we need a lot of workarounds to eliminate loops in Python to achieve high performance. In my opinion, numpy can make loop unnecessary in at least 80 percent of scenarios. In this post, I demonstrate some common scenarios where proper numpy techniques can reduce the amount of code and improve performance. I would recommend that every time someone finds it necessary to write loops in Python for scientific computation, he/she should refer to the documentation of numpy/scipy or stackoverflow to see if there is builtin functions to help eliminate loops. Surprisingly, such functions usually exist (because we usually underestimate the number of APIs in numpy/scipy).
Make use of numpy APIs
numpy provides a number of useful APIs for general scientific computation. Here I list some of the functions that I use most often. This is just a glimpse of the enormous amount of all APIs.

np.mean
,np.var

np.searchsorted
: binary search 
np.clip
,np.pad

np.intersect1d
,np.union1d
,np.setdiff1d
Assigning values for multidimensional arrays
Suppose we have a 3dimensional array arr3
(essentially an image), which is defined by:
arr3 = np.zeros((100, 100, 3), np.uint8)
If we want to assign all elements with a particular value, we can do the following:
arr3.fill(255)
If we want to assign each pixel with a particular RGB tuple, we can do the following:
arr3[:, :, :] = [125, 200, 50]
The test case for following scenarios
Assume the test case is given as below:
import numpy as np
# makes it possible to reproduce results
np.random.seed(0x1a2b3c4d)
# random array of size 100
arr = np.random.randint(2, 10, 100)
Suppose there is a predicate Pred
for each element, which is given by:
def Pred(x):
return x < 0
Looking for elements that satisfy the predicate
We would like to apply this predicate to all elements and output those elements that satisfy the predicate. The most naive way of doing it is:
indices = []
# note that the len(arr) and arr.size can be different
# for multidimensional arrays
for index in range(arr.size):
if(Pred(arr[index])):
indices.append(index)
We can eliminate this loop by writing:
indices = np.where(Pred(arr))[0]
It is a simple oneliner that achieves the same result at much higher speed. The np.where
function returns the indices of True
elements in an array. When it is given a dimensional array, its output would be arrays, each containing the index of a True
element of that dimension. Therefore, the columns of the output would be the coordinate of a True
element. That is why the subscript [0]
is needed here. In fact, if the predicate takes such a simple form, we can rewrite the code into:
indices = np.where(arr < 0)[0]
Replacing elements that satisfy the predicate
Now we would like to replace all elements that satisfy the predicate with a certain value (for example, 100). I will not provide the naive code here. The elegant way of doing it is:
arr[Pred(arr)] = 100
Replacing elements according to a “dictionary”
Assume that there is an array of nonnegative integers, where each element has a corresponding item in a “dictionary”. An example is shown as below:
arr = np.random.randint(0, 10, 20)
dictionary = ['zero', 'one', 'two', 'three',
'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']
We need to replace the elements of arr
by their corresponding elements in dictionary
. It can be done in the following way:
dictionary = np.asarray(dictionary, dtype = object)
result = dictionary[arr]
A possible content of arr
and its corresponding result
is shown as below.
>>> arr
[4 7 2 7 3 6 6 8 7 6 4 6 3 3 9 6 4 0 2 2]
>> result
['four' 'seven' 'two' 'seven' 'three' 'six' 'six' 'eight' 'seven' 'six'
'four' 'six' 'three' 'three' 'nine' 'six' 'four' 'zero' 'two' 'two']