Numpy is an abbreviation of NUMerical Python. It adds support for multi-dimensional arrays and matrices, as well as many of the algebraic formulae often used in working with these structures.
For a great tutorial see: https://docs.scipy.org/doc/numpy/user/quickstart.html
Recall that the main Python datastructs are as follows:
xs = [1,'1',2,'2'] # list := mutable & unordered collection of items
xd = {'cat': 'cute', 'dog': 'furry'} # dictionary:= (key,value) pairs
xa = {'cat', 'dog'} # set := unordered collection of distinct elements
xt = (5, 6) # tuple := immutable & ordered list of values
A numpy array is a grid of values, all of the same type, and is indexed by a tuple of nonnegative integers.
rank = number of dimensions of the array
shape= a tuple of integers giving the size of the array along each dimension
b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array from 2 python lists
print(b.shape) # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"
np.arange( 10, 30, 5 ) # creates a sequence of numbers similar to range
#>>> array([10, 15, 20, 25])
# arange() can also work with floating numbers but this is inadvisable as it the number of elements is unpredictable
# Use linspace instead when dealing with floats
np.linspace( 0, 2, 9 ) # 9 numbers from 0 to 2
#>>> array([ 0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
# there are some built in functions to create and populate often used arrays
np.zeroes((2,2)) # 2x2 array of zeroes
np.empty((2,2)) # 2x2 uninitialized, output may vary
np.ones((2,2)) # 2x2 array of ones
np.full((2,2), 7) # 2x2 array of sevens
np.eye(2) # 2x2 identity matrix
np.random.random((2,2)) # 2x2 array of random numbers between(0,1)
Arithmetic operators on arrays apply elementwise. A new array is created and filled with the result.
a = np.array( [20, 30, 40, 50] )
b = np.arange( 4 )
c = a-b # c(0,0) = [a(0,0)-b(0,0), ...etc ]
b**2 # each element of b raised to the 2nd power
10*np.sin(a) # [10*sine(a(0,0)), ... ,10*sine(a(3,3))
a < 35 # array([ True, True, False, False])
A = np.array( [[1,1],[0,1]] )
B = np.array( [[2,0],[3,4]] )
A * B # elementwise product
A @ B # matrix product
A.dot(B) # another matrix product
# Some operations, such as += and *=, act in place to modify an existing array rather than create a new one.
a = np.ones((2,3), dtype=int)
b = np.random.random((2,3))
a *= 3 # multiply each element of a by 3
b += a # upcasting is permitted
# adds each element of a to the corresponding element of b
# a += b # Downcasting is not permitted
# ERROR: b is not automatically converted to integer type
b = np.arange(10)**3 # create an array
#>>> [ 0 1 8 27 64 125 216 343 512 729]
a = b.reshape(2,5)
#>>> [[ 0 1 8 27 64]
#>>> [125 216 343 512 729]]
a.sum() # sum all elements
a.sum(axis=0) # sum each row
a.sum(axis=1) # sum each column
# Similarly there is min(), max(), cumsum() cumulative summation
#
a = np.arange(10)**3 # Create a 1dim array
#>>> array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729])
a[2] # get element at i = 2
a[2:5] # get elements [2,3,4]
a[:6:2] = -1000 # from start to position 6, exclusive, set every 2nd element to -1000
# equivalent to a[0:6:2] = -1000
a[ : :-1] # a in reverse order
for i in a: # iterate over a
print(i**(1/3.))
a = np.arange(10)**3 # Create a 1dim array
#>>> array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729])
a[2:5]