As we have seen Python offers a lot of help in programming, allowing users to implement complex code in few, but easily readable, lines of code. This ease of use does come at a cost though, in particular speed. Since python is interpreted at runtime and has to interpret what users wants it tends to be slower, therefore not always right for long and cpu-intensive calculations (a shame since the ease of implementation makes it a great choice for data-analysis). This is where scientific libraries such as Numpy and Scipy come in. These librares are written in C, and python is used as a wrapper to facilitate their use. These two librarie are usually imported as
import numpy as np
import scipy as sp (though often scipy sub-modules have to be imported manually)
Numpy main contrbution is the implementation of multidimensional arrays, as well as all the necessary operations between vectors, matricies and scalars.
Scipy on the other hand offers a series of implementations for computing integrals, derivatives, interpolations etc.
Numpy arrays can be created starting from a python list, or from one of the methods provided by numpy. Keep in mind that numpy works with numbers, and will therefore be stricter when it comes to the values passed to the constructors. It will however follow Python's approach towards types. Therefore if you create an array with integers they will stay integers, they also replicate python's useful list slicing
import numpy as np
a = np.array([1,2,3,4])
print(a)
[1 2 3 4]
a = np.array([1.0,2,3])
print(a)
[1. 2. 3.]
a = np.array([1,2,3,'a'])#this will work, but you will now have only a vector of chars
print(a)
['1' '2' '3' 'a']
a = np.arange(7) #create a array starting from 0 and 7 elements long
print(a)
[0 1 2 3 4 5 6]
a = np.linspace(0,2,9) # creates an array starting at 0 and ending at 2 (included) of 9 elements
print(a)
[0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. ]
a = np.logspace(0,2,9) #create an array starting at 10^0 to 10^2 of 9 elements
print(a)
print(np.array([10**x for x in np.linspace(0,2,9)]))
[ 1. 1.77827941 3.16227766 5.62341325 10. 17.7827941 31.6227766 56.23413252 100. ] [ 1. 1.77827941 3.16227766 5.62341325 10. 17.7827941 31.6227766 56.23413252 100. ]
a = np.zeros(5) #create an array of zeros
print(a)
[0. 0. 0. 0. 0.]
Numpy arrays can be used with numpy functions to calculate the function on all the values of the array
x = np.linspace( 0, 2*np.pi, 10 )
print(np.sin(x))
[ 0.00000000e+00 6.42787610e-01 9.84807753e-01 8.66025404e-01 3.42020143e-01 -3.42020143e-01 -8.66025404e-01 -9.84807753e-01 -6.42787610e-01 -2.44929360e-16]
a = np.array([2,4,6])
b = np.array([1,3,5])
print(a.dot(b)) #dot product
print(a*b)#element wise product
44 [ 2 12 30]
Numpy supports multidimensionl arrays (matricies), these can be created using nested lists or by reshaping one dimensional arrays
np.array([[1,2,3],[4,5,6],[7,8,9]])
array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
np.array(range(1,10)).reshape(3,3)
array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(np.array(range(1,10)).reshape(3,3)[1,:])
[4 5 6]
print(np.array(range(1,10)).reshape(3,3)[:,1])
[2 5 8]
Covering all of numpy here would be an impossible task. Fortunatly numpy offers a great documentation:
https://docs.scipy.org/doc/numpy/index.html
the page for a comand wil give you all the information you need, the parameters, what they do, whether a default value is provided (optional) and what it returns (make sure you realize that in some cases numpy will modify the array rather than return a new one). Some basic, and not so basic, examples are also provided
Scipy offers a wider range of operations, it is therefore divided in multiple submodules:
Scipy works in conjunction with numpy, and therefore often makes use of numpy arrays in it's calculations
Contains methods to calculate values of special, commonly used, functions, such as spherical bessel functions.
from scipy import special
special.spherical_jn(1,np.arange(10))
array([ 0. , 0.30116868, 0.43539777, 0.3456775 , 0.11611075, -0.09508941, -0.16778992, -0.09429243, 0.03364623, 0.10632458])
Contains methods to calculate integrals following differente algorithms.
For example one can calculate the volume of a sphere
from scipy.integrate import tplquad
def sphereVolume(radius = 1):
return tplquad(lambda theta,phi,r: r**2*np.sin(phi), 0, radius,
lambda r: 0, lambda r: np.pi, lambda r,phi:0 , lambda r,phi:2*np.pi)
print(sphereVolume(1)) #Returns a Tuple with the value and the error
(4.18879020478639, 1.389095079694993e-13)
Interpolating points allows you to find a polynomial function which passes though all given points (this is not a fitting of data points, for that i suggest looking into lmfit-py, a very reliable library with a very active group). The result of interpolated functions can be used ot calculate new points, as well as integrals and derivatives
from scipy import interpolate
x = np.arange(0, 2*np.pi+np.pi/4, 2*np.pi/8)
y = np.sin(x)
tck = interpolate.splrep(x, y, s=0)
ynew = interpolate.splev(x, tck, der=0)
print("Old y's")
print(y)
print("Calculated y's")
print(ynew)
Old y's [ 0.00000000e+00 7.07106781e-01 1.00000000e+00 7.07106781e-01 1.22464680e-16 -7.07106781e-01 -1.00000000e+00 -7.07106781e-01 -2.44929360e-16] Calculated y's [ 3.44265545e-18 7.07106781e-01 1.00000000e+00 7.07106781e-01 1.94289029e-16 -7.07106781e-01 -1.00000000e+00 -7.07106781e-01 -2.44929360e-16]
In most cases we want to display the data in a nicly formatted graph rather than just writing a list of numbers. Matplotlib offers to possibility of producing graphs, similar to those created by Matlab, in python. It is usually imported as
import matplotlib.pyplot as plt
When working in Jupyter one can use the magic function
%matplotlib inline
to display the plots in the notebook.
Matplotlib can be used in two different modes, either using plt methods to edit the current plot, or using handles to diretly reference objects. This second method is the one we will be seeing, as it allows for a clearer code.
import matplotlib.pyplot as plt
%matplotlib inline
x = np.arange(0, 2*np.pi+np.pi/4, 2*np.pi/8)
y = np.sin(x)
fig = plt.figure(figsize=(10,5))
ax = fig.add_subplot(111)
ax.plot(x,y,'rx')
[<matplotlib.lines.Line2D at 0x11eef2390>]
Let's create a more interesting plot, using the some of the notions from all three libraries
x = np.arange(0, 3*np.pi+np.pi/4, 2*np.pi/8)
hiResX = np.arange(0, 3*np.pi+np.pi/4, 2*np.pi/24)
y = np.sin(x) #Create a series of points to plot
yLinFit = interpolate.splrep(x, y, k=1) #interpolate the points using a linear spline
yCubeFit = interpolate.splrep(x, y, k=3) #interpolate the points using a cubic spline
fig = plt.figure(figsize=(15,5))#Create a figure 15 inches wide and 5 inches high
ax1 = fig.add_subplot(131)#Add a first plot in a grid of 1 row and 3 columns
ax1.plot(x,y,'rx', label='Exp. Points')
ax1.plot(hiResX,interpolate.splev(hiResX, yLinFit),'b', label='Linear Spline')
ax1.plot(hiResX,interpolate.splev(hiResX, yCubeFit),'g', label='Cubic Spline')
ax1.axhline(0,linewidth=1,color='k')
ax1.legend()
ax1.set_title("Point, Lin. Spline and Cubic Spline")
ax2 = fig.add_subplot(132)#Add a second plot in a grid of 1 row and 3 columns
ax2.plot(hiResX,interpolate.splev(hiResX, yCubeFit),'g', label='Cubic Spline')
ax2.plot(hiResX,interpolate.splev(hiResX, yCubeFit, der=1),'b', label='First Derivative')
ax2.axhline(0,linewidth=1,color='k')
ax2.legend()
ax2.set_title("Cubic Spline and First Der.")
ax3 = fig.add_subplot(133)#Add a third plot in a grid of 1 row and 3 columns
ax3.plot(hiResX,interpolate.splev(hiResX, yCubeFit),'g', label='Cubic Spline')
ax3.fill_between(hiResX, 0, interpolate.splev(hiResX, yCubeFit), color='g', alpha=0.5)
ax3.axhline(0,linewidth=1,color='k')
ax3.legend()
ax3.set_title("Filled Area Below Spline")
Text(0.5, 1.0, 'Filled Area Below Spline')
Great documentation of matplotlib can be found at https://matplotlib.org/gallery.html