Preliminaries and Data types

Initialization of scalar data

  • In python we don't declare variables. The variables are created when a value is assigned to them
In [1]:
a = 2;
b = -1;
c = 4;
d = 10.0;
  • Some elementary arithmetic operations using the above defined scalars:
In [2]:
e = a+b;
f = a-b;
g = a*b*c;
h = a/d;

print("The value of e is",e,"where a = ", a, " and b = ", b ,sep = ' ');
The value of e is 1 where a =  2  and b =  -1
  • The print command is used to display the output.
  • Separators can be used to make the output more legible. Defualt separator is space " ".
  • Besides printing to screen, the output can also be written to a file using file parameter
In [3]:
fid = open('arithematic.txt', 'w') 
print("The value of e is",e,"where a = ", a, " and b = ", b ,sep = ' ', file = fid) 
fid.close() 

Importing libraries

  • We'll import some libraries to provide additional functionality
In [4]:
import numpy as np
  • $\textbf{numpy}$ is a python library used for working with arays and matrices.
  • The $\textbf{import}$ command also allows us to specify an alias $\textbf{np}$ for the $\textbf{numpy}$ library.
  • Now we can make an array of size 5 using $\textbf{ndarray}$ provided in $\textbf{numpy}$
In [5]:
a = np.ndarray(5, dtype=float)
  • Here we have generated a 1D array of size 5 with float datatype
  • We can manually intialize the array as:
In [6]:
a[0] = 5; # Indexing of an array starts from zero
a[1] = 10;
a[2] = 11;
a[3] = -2;
a[4] = 6;
In [7]:
print(a)
[ 5. 10. 11. -2.  6.]
  • We can query the size of the array using $\textbf{np.shape}$.
  • This can be useful when the arrays are arbitrarily long and you want to know how long that particular array is. For example, the data could be a time series of velocity in a flow field as measured with the help of an anemometer.
In [8]:
np.shape(a)
Out[8]:
(5,)
  • An array can be initialized with zero values using $\textbf{np.zeros}$. It creates a zero array of float type with 1 row and 5 columns
In [9]:
b = np.zeros(5, dtype=float);
In [10]:
print(b)
[0. 0. 0. 0. 0.]
  • We can create a linear space (arithmetic progression) from point a to b with the help of the function $\textbf{np.linspace}$.
In [11]:
c = np.linspace(1.0, 2.0, num=5, retstep=True, endpoint=True) #Extremely important
print(c)
(array([1.  , 1.25, 1.5 , 1.75, 2.  ]), 0.25)
  • Here we see that the endpoint is included in the list and the step size is 0.25.
  • We can also provide the step size and infer the number of elements using np.arange
In [12]:
c = np.arange(1.0, 2.0, 0.25)
print(c)
[1.   1.25 1.5  1.75]
  • Note that unlike linspace $\textbf{np.arange}$ doesn't include the last element
  • We can similarly create a logspace. The fundamental difference between the logspace and linspace is that the former is a geometric progression while the other is an arithmetic progression.
  • The function call to logspace looks quite similar to linspace but whatever linspace would have produced, is the exponent of 10. Thus creating essentially, $10^{\textrm{equivalent linspace}}$
In [13]:
d = np.logspace(1.0, 4.0, num=4, endpoint=True)
In [14]:
print(d)
[   10.   100.  1000. 10000.]
  • In the above expression; we basically have; 10^1, 10^2, 10^3, 10^4

Some elementary array operations:

  • Let us create an array $\textrm{e}$ with 5 random values drawn from a normal distribution with mean equal to $\textrm{0}$ and variance equal to $\textrm{1}$ and print the two arrays $\textrm{a}$ and $\textrm{e}$
In [15]:
e = np.random.normal(0, 1, 5)

print("array a is =", a, "array e is =",e);
array a is = [ 5. 10. 11. -2.  6.] array e is = [ 0.0814339   0.58887912 -1.04712179 -0.60416989  1.04913826]
  • Let us perform element wise addition; save the output in the variable b, and then printout the elements of b.
In [16]:
b = a+e;
print(b);
[ 5.0814339  10.58887912  9.95287821 -2.60416989  7.04913826]
  • Similarly we can perform other elementwise operations such as subtraction, multiplication, and division. Note that there are 3 types of multiplication possible.
    • $\textbf{A * B}$ performs elementwise product for numpy arrays and numpy vectors while it performs matrix multiplication when A and B are matrices
    • $\textbf{np.dot(A,B)}$ performs matrix multiplication for numpy arrays and numpy matrices and a dot product for numpy vectors
    • $\textbf{np.multiply(A,B)}$ performs elementwise product for all
In [17]:
c = a-e;
d = np.multiply(a,e);      #element wise multiplication
f = np.divide(a, e);       #element wise division
print(c);
print(d);
print(f);
[ 4.9185661   9.41112088 12.04712179 -1.39583011  4.95086174]
[  0.40716952   5.88879115 -11.51833968   1.20833978   6.29482955]
[ 61.39948841  16.98141391 -10.50498626   3.31032717   5.71897932]
  • We can multiply a scalar with an array
In [18]:
c = 2*a;
print(a);
print(c);
[ 5. 10. 11. -2.  6.]
[10. 20. 22. -4. 12.]
  • We can perform element-wise exponenetiation using $\textbf{**}$ operator. Let's create a linearly spaced array from $1$ to $4$ and a log spaced array from $10$ to $10^4$
In [19]:
c = np.linspace(1., 4., 4);
print("c = :",c)
d = np.logspace(1., 4., 4)
print("d = :", d)
e = 10**c;
print("e = :", e)
c = : [1. 2. 3. 4.]
d = : [   10.   100.  1000. 10000.]
e = : [   10.   100.  1000. 10000.]

Array splicing

  • Let us create an array $\textrm{f}$ and select the 3rd through 5th element of the array
In [20]:
print(f)
[ 61.39948841  16.98141391 -10.50498626   3.31032717   5.71897932]
In [21]:
f[2:-1]
Out[21]:
array([-10.50498626,   3.31032717])
  • The last index is not included in the splice
  • In Python like most languages, the array indexing starts from $0$ and ends at $n-1$; where $n$ is the number of elements in that array.
  • We can access the elements from the back of the array using negative indexing. Here we print elements from the index $3$ from the end till the index $1$ from end
In [22]:
f[-3:-1]
Out[22]:
array([-10.50498626,   3.31032717])
  • While splicing we can also provide a step size. Here we print elements from the start till the end with step size of $2$
In [23]:
f[0::2]
Out[23]:
array([ 61.39948841, -10.50498626,   5.71897932])

Creation of a random array can be done as following:

In [24]:
h = np.random.uniform(0,1,10);  # Random array of size 1x10 with a uniform distribution between 0 and 1
print(h);
[0.27418738 0.69634651 0.82929717 0.57825513 0.72691078 0.15234377
 0.02331987 0.20518642 0.94486804 0.04572729]
  • The array can be spliced as follows and assigned to a new variable $\textrm{'k'}$
In [25]:
k = h[2:8];
print(k);
[0.82929717 0.57825513 0.72691078 0.15234377 0.02331987 0.20518642]
  • We can make use of the negative index(-1) to reference the last element of an array.
In [26]:
print("First element:",k[0] ,"Last element:", k[-1])
First element: 0.829297166993202 Last element: 0.20518642005934074

Some conditionals on arrays

In [27]:
print(k);
m = k>0.5; # This line checks whether the entries of array k are larger than 0.5. If yes, then that particular index of m gets a value of 1 (boolean for True) else m gets a value of zero
print(m);
[0.82929717 0.57825513 0.72691078 0.15234377 0.02331987 0.20518642]
[ True  True  True False False False]
In [28]:
m = k<0 # For logical false python gives Boolean False as output
print(m);
[False False False False False False]
In [29]:
n = k[k>0.5]; 
print(n); # Find the values of k>0 and assign them to another array n
[0.82929717 0.57825513 0.72691078]

Declaration of a matrix

  • Matrices can declared using $\textbf{np.ndarray}$ by providing additional dimensions
In [30]:
a = np.ndarray(shape=(2,2), dtype=float); 
print(a);
[[   10.   100.]
 [ 1000. 10000.]]
  • A matrix can be initialized with zeros as shown:
In [31]:
a = np.zeros(shape=(4,4)); 
print(a);
[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]]
  • A random matrix can be declared as follows (uniform random values between $0$ and $1$)
In [32]:
b = np.random.uniform(0,1,(4,4)); 
print(b);
[[0.30391692 0.03978351 0.71717393 0.61542301]
 [0.82551889 0.02853404 0.28859014 0.73980943]
 [0.88728081 0.01325815 0.99873943 0.09212724]
 [0.21852489 0.36754009 0.74079869 0.33186311]]
  • A matrix can be initialized with all elements as $1$ as shwon:
In [33]:
e = np.ones(shape=(4,4)); 
print(e);
[[1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]
 [1. 1. 1. 1.]]
  • np.multiply() perfroms element-wise multiplication
In [34]:
f = np.multiply(b, e); 
print(f);
[[0.30391692 0.03978351 0.71717393 0.61542301]
 [0.82551889 0.02853404 0.28859014 0.73980943]
 [0.88728081 0.01325815 0.99873943 0.09212724]
 [0.21852489 0.36754009 0.74079869 0.33186311]]
  • $\textrm{b}\textbf{*}\textrm{e}$ elso performs element-wise multiplication
In [35]:
f = b*e;
print (f);
[[0.30391692 0.03978351 0.71717393 0.61542301]
 [0.82551889 0.02853404 0.28859014 0.73980943]
 [0.88728081 0.01325815 0.99873943 0.09212724]
 [0.21852489 0.36754009 0.74079869 0.33186311]]
  • $\textbf{np.dot}$ performs proper matrix multiplication
In [36]:
f = np.dot(b, e); 
print(f);
[[1.67629737 1.67629737 1.67629737 1.67629737]
 [1.8824525  1.8824525  1.8824525  1.8824525 ]
 [1.99140562 1.99140562 1.99140562 1.99140562]
 [1.65872678 1.65872678 1.65872678 1.65872678]]
  • Scalar multiplication of matrix
In [37]:
g = 2*f; print(g);
[[3.35259474 3.35259474 3.35259474 3.35259474]
 [3.76490499 3.76490499 3.76490499 3.76490499]
 [3.98281124 3.98281124 3.98281124 3.98281124]
 [3.31745355 3.31745355 3.31745355 3.31745355]]
  • $\textbf{np.where}$ conditional statements returns the indices of elements in array $\textrm{g}$ which statisfy the provided condition.
In [41]:
p = np.where(g>3); 
print(p);
(array([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], dtype=int64), array([0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3], dtype=int64))
  • We can now print those elements
In [42]:
print(g[p]) # g[row values, column values]
[3.35259474 3.35259474 3.35259474 3.35259474 3.76490499 3.76490499
 3.76490499 3.76490499 3.98281124 3.98281124 3.98281124 3.98281124
 3.31745355 3.31745355 3.31745355 3.31745355]
In [43]:
print(g[g>3])
[3.35259474 3.35259474 3.35259474 3.35259474 3.76490499 3.76490499
 3.76490499 3.76490499 3.98281124 3.98281124 3.98281124 3.98281124
 3.31745355 3.31745355 3.31745355 3.31745355]
In [ ]: