In [177]:
# importing required packages 
import numpy as np

In [178]:
# forming numpy array
array1 = np.array([1,2,3,4])
array1


Out[178]:
array([1, 2, 3, 4])

In [179]:
# checking type of above formed array
print type(array1)
# checking type of element in the array
print array1.dtype


<type 'numpy.ndarray'>
int32

In [180]:
# Specifying the type of elements in np.array 
array2 = np.array([4,3,2,7],float)
array2


Out[180]:
array([ 4.,  3.,  2.,  7.])

In [181]:
# Indexing numpy array 
print array1[1]
print array2[1:]
print array1[:2]


2
[ 3.  2.  7.]
[1 2]

In [182]:
# While indexing if x:y is used then we must note that x is inclusive and y is exclusive
array1[1:3]


Out[182]:
array([2, 3])

In [183]:
# Negative values in indexing are also allowed 
print array1
array1[-2,]
# This returns second element from the end


[1 2 3 4]
Out[183]:
3

In [184]:
# Multidimensional array 
array3 = np.array([[1,5,6],[7,8,9]])
array3


Out[184]:
array([[1, 5, 6],
       [7, 8, 9]])

In [185]:
# Indexing multidimensional array
print array3[1,]
print array3[-1,]
print array3[:,-1]


[7 8 9]
[7 8 9]
[6 9]

In [186]:
# Indexing multidimensional array
print array3[0:2,1:2]
print array3[:,1]


[[5]
 [8]]
[5 8]

In [187]:
# Determing the dimensions of the array using shape which returns number of rows and columns in the array
array3.shape


Out[187]:
(2, 3)

In [188]:
# len function returns the length of first axis
len(array3)


Out[188]:
2

In [189]:
array4 = np.array(range(12))
array4


Out[189]:
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [190]:
# Changing dimensions of the array
print array4.shape
print 'After changing the dimensions : '
array4 = array4.reshape(4,3)
print array4


(12,)
After changing the dimensions : 
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]

In [191]:
# Checking Membership in array using 'in'. Returns a boolean value according to presence or absence of element
print 4 in array4
print 12 in array4


True
False

In [192]:
# Copying array elements from one array to another 
x = np.array([2,3,4,7,8,9,10,23])
print x
y = x
print y
# Changing one of the element in original array affects the new array also.
print '\nAfter modifying original array'
x[5] = 89
print x
print y


[ 2  3  4  7  8  9 10 23]
[ 2  3  4  7  8  9 10 23]

After modifying original array
[ 2  3  4  7  8 89 10 23]
[ 2  3  4  7  8 89 10 23]

In [193]:
# copy() function to create a seperate array array in memory
z = x.copy()
print z
# changing element in original array will not affect the new array
print '\nAfter modifying original array'
x[1] = 5
print x
print z


[ 2  3  4  7  8 89 10 23]

After modifying original array
[ 2  5  4  7  8 89 10 23]
[ 2  3  4  7  8 89 10 23]

In [194]:
# Forming string from array elements using tostring() function
string = np.array([1,2,3],float).tostring()
string


Out[194]:
'\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x08@'

In [195]:
# Getting array elements back from string format using fromstring()
np.fromstring(string)


Out[195]:
array([ 1.,  2.,  3.])

In [196]:
# Filling an array with a scalar value using fill() function
print z
print '\nElements in the array after using fill() function'
z.fill(2)
print z


[ 2  3  4  7  8 89 10 23]

Elements in the array after using fill() function
[2 2 2 2 2 2 2 2]

In [197]:
# Transposing multi-dimensional array using transpose() function 
print array3
print '\After transposing the array'
print array3.transpose()


[[1 5 6]
 [7 8 9]]
\After transposing the array
[[1 7]
 [5 8]
 [6 9]]

In [198]:
# Transforming multi-dimensional array into one dimensional using flatten() function
print array3
print '\nAfter using flatten() function'
print array3.flatten()


[[1 5 6]
 [7 8 9]]

After using flatten() function
[1 5 6 7 8 9]

In [199]:
# One dimensional arrays can be merged using the function conctenate() 
a = np.array([5,6,7])
b = np.array([78,99,100,12])
np.concatenate((a,b))


Out[199]:
array([  5,   6,   7,  78,  99, 100,  12])

In [200]:
# Multi-dimensional arrays can also be merged using concatenate() and mentioning axis. By default it considers first dimension.
a = np.array([[10,11],[34,22]])
b = np.array([[12,13],[15,16]])
print 'Without mentioning axis value\n'
print np.concatenate((a,b))
print '\nMentioning axis value 0 for the first dimension'
np.concatenate((a,b),axis=0)


Without mentioning axis value

[[10 11]
 [34 22]
 [12 13]
 [15 16]]

Mentioning axis value 0 for the first dimension
Out[200]:
array([[10, 11],
       [34, 22],
       [12, 13],
       [15, 16]])

In [201]:
# Changing axis to point to second dimension by making axis = 1
np.concatenate((a,b),axis = 1)


Out[201]:
array([[10, 11, 12, 13],
       [34, 22, 15, 16]])

In [202]:
# Alternative way of creating array using arange() function
# If we mention only one single scalar value 'n' then it makes an array of 'n' starting from index 0  
a = np.arange(7)
a


Out[202]:
array([0, 1, 2, 3, 4, 5, 6])

In [203]:
# If we mention np.arange(x,y,increment) then it starts the array elements from x and y is exclusive. 
# Increment value acts as a step value.
np.arange(1,10,2)


Out[203]:
array([1, 3, 5, 7, 9])

In [204]:
# There are some functions like np.ones() and np.zeros() to create arrays having all values 1 and 0 respectively.
# We need to mention the number of elements and their type in the array
np.ones(8,dtype=float)


Out[204]:
array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.])

In [205]:
# Multi-dimensional arrays can also be formed by mentioning number of rows and columns
np.zeros((3,2), dtype = int)


Out[205]:
array([[0, 0],
       [0, 0],
       [0, 0]])

In [206]:
# There are functions like np.zeros_like(arrayname) and np.ones_like(arrayname) to create new arrays like the exisitng ones
a = np.array([[2,3],[4,5]], dtype = int)
a
print a.shape
np.zeros_like(a)


(2, 2)
Out[206]:
array([[0, 0],
       [0, 0]])

In [207]:
# Identity matrices can also be formed using np.identity() function by mentioning 'n' value as a parameter
np.identity(3,dtype = int)


Out[207]:
array([[1, 0, 0],
       [0, 1, 0],
       [0, 0, 1]])

In [208]:
# Arithmetic operations on arrays are performed element-by-element. So in operations like addition or subtraction, the number 
# of elements in the arrays should be same. 
a = np.array([1,2,3])
b = np.array([4,5,6])
print a
print b
print 'After Addition :'
print a + b


[1 2 3]
[4 5 6]
After Addition :
[5 7 9]

In [209]:
print 'After Subtraction'
print b - a


After Subtraction
[3 3 3]

In [210]:
print 'After Multiplication'
print a * b


After Multiplication
[ 4 10 18]

In [211]:
print 'After Division'
print b/a


After Division
[4 2 2]

In [212]:
print 'After Modulo Operation'
print b%a


After Modulo Operation
[0 1 0]

In [213]:
print 'Power operation'
print b**a


Power operation
[  4  25 216]

In [214]:
# For 2D arrays, multiplication operation remains element wise.
x = np.array([[1,2],[4,5]])
y = np.array([[10,4],[5,2]])
x * y


Out[214]:
array([[10,  8],
       [20, 10]])

In [215]:
# If arrays are not of same size, then error occurs.
a = np.array([51,42,78])
b = np.array([21,4])

In [216]:
# Arrays that do not have same dimsensions will be broadcasted by python to perform mathematical operations. 
# smaller array will be repeated as necessary to perform the operation.  
a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[2,3]])
a + b


Out[216]:
array([[3, 5],
       [5, 7],
       [7, 9]])

In [217]:
# We can also add, subtract, multiply and divide scalar values element-wise   
a = np.array([1,2,45,67,44,23,56,34])
print a
print 'After Addition'
print a + 2
print 'After Subtraction'
print a - 2
print 'After Multiplication'
print a * 2
print 'After Division'
print a/2


[ 1  2 45 67 44 23 56 34]
After Addition
[ 3  4 47 69 46 25 58 36]
After Subtraction
[-1  0 43 65 42 21 54 32]
After Multiplication
[  2   4  90 134  88  46 112  68]
After Division
[ 0  1 22 33 22 11 28 17]

In [218]:
# There are several other operations that can be performed elementwise on numpy array
# Functions like ceil, floor, square, and sqrt are also available
# Considering an example for each 
a = np.array([25,64,100])
print a


[ 25  64 100]

In [219]:
print 'Performing Square root'
print np.sqrt(a)
print 'Performing Square'
print np.square(a)
print np.sqrt(a).dtype


Performing Square root
[  5.   8.  10.]
Performing Square
[  625  4096 10000]
float64

In [220]:
# Performing ceil and floor 
a = np.array([1.5,4.8,6.7,8.9,2.1,3.7,9.9])
print a
print 'Ceil Operation'
print np.ceil(a)
print 'Floor Operation'
print np.floor(a)


[ 1.5  4.8  6.7  8.9  2.1  3.7  9.9]
Ceil Operation
[  2.   5.   7.   9.   3.   4.  10.]
Floor Operation
[ 1.  4.  6.  8.  2.  3.  9.]

In [221]:
# Rounding off the array elements
np.rint(a)


Out[221]:
array([  2.,   5.,   7.,   9.,   2.,   4.,  10.])

In [222]:
# Array operations using built-in functions 
# For obtaining sum of all the elements in the array, we use function arrayname.sum()
a = np.array([21,23,54,10,45,67,99])
a.sum()


Out[222]:
319

In [223]:
# For obtaining product of all the elements in the array, there is a function which can be called by arrayname.prod()
a.prod()


Out[223]:
541446372

In [224]:
# There are some standalone functions in NumPy for array operations 
# For sum, np.sum() can be used
np.sum(a)


Out[224]:
319

In [225]:
# For product, np.prod() can be used
np.prod(a)


Out[225]:
541446372

In [226]:
# We also have functions to obtain mean and median 
print 'Mean'
print np.mean(a)
print 'Median'
print np.median(a)


Mean
45.5714285714
Median
45.0

In [227]:
# We also have functions for obtaining variance and standard deviation
print 'Variance of Array'
print a.var()
print 'Standard Deviation of Array'
print a.std()


Variance of Array
823.387755102
Standard Deviation of Array
28.6947339263

In [228]:
# To find maximum and minimum, we have functions called max() and min() respectively.
a.max()


Out[228]:
99

In [229]:
a.min()


Out[229]:
10

In [230]:
# We can also get array indices for maximum and minimum element using argmax() and argmin() respectively.
a.argmax()


Out[230]:
6

In [231]:
a.argmin()


Out[231]:
3

In [232]:
# We can also sort array elements using sorted() and sort() function
# sorted() returns list 
print sorted(a)
print type(sorted(a))


[10, 21, 23, 45, 54, 67, 99]
<type 'list'>

In [233]:
# sort() - simply sorts the elements in the array
a.sort()
print a


[10 21 23 45 54 67 99]

In [234]:
# If we want values in the array to lie within a specified range, function called clip() can be used
a.clip(50,80)


Out[234]:
array([50, 50, 50, 50, 54, 67, 80])

In [235]:
# To obtain correlation coefficient, we can use function np.corrcoef() 
x = np.array([[20,23,45,46,50],[11,23,56,34,78]])
np.corrcoef(x)


Out[235]:
array([[ 1.        ,  0.85890744],
       [ 0.85890744,  1.        ]])

In [236]:
# We can obtain covariance value using function np.cov()
a = np.array([23,45,67,78])
np.cov(a)


Out[236]:
array(594.9166666666666)

In [237]:
# To determine number of sistinct elements in the array, we can use unique() function of NumPy
a = np.array([11,2,2,3,5,11,6,5,7,8])
np.unique(a)


Out[237]:
array([ 2,  3,  5,  6,  7,  8, 11])

In [238]:
# Array comparisons can also be done element wise
a = np.array([45,33,23,4,11,5])
b = np.array([2,33,22,4,10,5])
a == b


Out[238]:
array([False,  True, False,  True, False,  True], dtype=bool)

In [239]:
a > 20


Out[239]:
array([ True,  True,  True, False, False, False], dtype=bool)

In [240]:
a < 25


Out[240]:
array([False, False,  True,  True,  True,  True], dtype=bool)

In [241]:
(a > 10) & (a < 30)


Out[241]:
array([False, False,  True, False,  True, False], dtype=bool)

In [242]:
c = (a<=b)
c


Out[242]:
array([False,  True, False,  True, False,  True], dtype=bool)

In [243]:
# We can use any() and all() function to check whether true value is present or not
print any(c)
print all(c)


True
False

In [244]:
all(np.array([1,2,3]) == np.array([1,2,3]))


Out[244]:
True

In [245]:
# We can also perform compound boolean expressions element-wise using np.logical_and(), np.logical_or() and np.logical_not().
a = np.array([23,45,6,7,8,12,34,2,1,5])
b = np.array([20,40,3,4,6,7,30,12,36,20])
np.logical_and(a > 20, a < 40)


Out[245]:
array([ True, False, False, False, False, False,  True, False, False, False], dtype=bool)

In [246]:
np.logical_or(a > 20, a < 40)


Out[246]:
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)

In [247]:
np.logical_not(a > 10)


Out[247]:
array([False, False,  True,  True,  True, False, False,  True,  True,  True], dtype=bool)

In [248]:
# To determine the indices of array where the value is nonzero. 
a = np.array([1,2,0,4,5,0,7,9,0,5])
print a.nonzero()
print type(a.nonzero())


(array([0, 1, 3, 4, 6, 7, 9]),)
<type 'tuple'>

In [249]:
a = np.array([11,15,56,23,20,10,8,4])
print np.where(a>10,1,0)
print sum(np.where(a>10,1,0))


[1 1 1 1 1 0 0 0]
5

In [250]:
# We can also use functions np.isnan() and np.isfinite() to check NA and Infinite values
a = np.array([1,2,np.NaN,3,6,np.Inf])
print a
np.isnan(a)


[  1.   2.  nan   3.   6.  inf]
Out[250]:
array([False, False,  True, False, False, False], dtype=bool)

In [251]:
np.isfinite(a)


Out[251]:
array([ True,  True, False,  True,  True, False], dtype=bool)

In [252]:
np.isinf(a)


Out[252]:
array([False, False, False, False, False,  True], dtype=bool)

In [253]:
# Checking for elements within specific range for 2D arrays
a = np.array([[4,5,6,7],[34,30,67,89],[23,20,45,33]])
print a
a[(a>10)&(a<30)]


[[ 4  5  6  7]
 [34 30 67 89]
 [23 20 45 33]]
Out[253]:
array([23, 20])

In [254]:
(a>10)&(a<35)


Out[254]:
array([[False, False, False, False],
       [ True,  True, False, False],
       [ True,  True, False,  True]], dtype=bool)

In [255]:
# We can also perform selection of some specific values with arrays as indices
a = np.array([56,45,40,99,100,105,44,34])
b = np.array([1,2,5,6,3,4])
print a
print 'Indices Array :'
print b
a[b]


[ 56  45  40  99 100 105  44  34]
Indices Array :
[1 2 5 6 3 4]
Out[255]:
array([ 45,  40, 105,  44,  99, 100])

In [256]:
# There is a function called take() which is used in similar manner for selection like the above approach
# We can also mention axis value for 2D arrays. - take(indices_array, axis)
a.take(b)


Out[256]:
array([ 45,  40, 105,  44,  99, 100])

In [257]:
# We also have put() function to place some values at specific positions.
a.put([1,2,4],0)
print a


[ 56   0   0  99   0 105  44  34]

In [258]:
# Here the source will be repeated if necessary
a.put([0,3,4],[5,6,7])
print a


[  5   0   0   6   7 105  44  34]

In [259]:
# NumPy has some built-in functions for vector and array mathematics.
# Considering two numpy one dimensional arrays and obtaining dot product using np.dot() function
a = np.array([11,2,33,5])
b = np.array([1,12,2,10])
print a
print b
print 'Dot Product of a and b'
np.dot(a,b)


[11  2 33  5]
[ 1 12  2 10]
Dot Product of a and b
Out[259]:
151

In [260]:
# For 2D NumPy array, using dot() function is similar to matrix multiplication
a = np.array([[10,11],[4,5]])
b = np.array([2,3])
np.dot(b,a)


Out[260]:
array([32, 37])

In [261]:
np.dot(a,b)


Out[261]:
array([53, 23])

In [262]:
# Numpy also has functions for inner, outer and cross product of vectors and matrices.
# For vectors, inner product is same as dot product.
print np.inner(a,b)
print np.dot(a,b)


[53 23]
[53 23]

In [263]:
# For outer product, we use numpy.outer() function
np.outer(a,b)


Out[263]:
array([[20, 30],
       [22, 33],
       [ 8, 12],
       [10, 15]])

In [265]:
# Cross Product for matrices and vectors can be obtained using function numpy.cross().
a = np.array([1,4,5])
b = np.array([2,3,6])
np.cross(a,b)


Out[265]:
array([ 9,  4, -5])

In [266]:
# NumPy also has built-in functions for linear algebra calculations 
# There is a subpackage called 'numpy.linalg' which provides functions for vector and matrix arithmetics
# Considering a matrix and obtaining determinant, rank and sign and natural logarithm of determinant of matrix.
a = np.array([[10,20],[35,45]])

# To obtain determinant of matrix, we use function numpy.linalg.det().  
np.linalg.det(a)


Out[266]:
-249.99999999999989

In [269]:
# Obtaining rank of matrix (number of independent vectors) can be obtained using numpy.linalg.matrix_rank()
# Here first two rows are dependent as second row can be obtained by multiplying each element of first row by 2. 
a = np.array([[12,13,14],[24,26,28],[1,2,3]])
print a
np.linalg.matrix_rank(a)


[[12 13 14]
 [24 26 28]
 [ 1  2  3]]
Out[269]:
2

In [273]:
# We can also obtain trace of matrix (Sum of elements across diagonal) using function numpy.trace()
# There are parameters like offset, axis, dtype and out. 
np.trace(a)


Out[273]:
41

In [274]:
# Condition number of matrix can be obtained using function numpy.linalg.cond(). 
# In numerical analysis, this number plays very important role in getting initial insights about matrix. 
# This number indicates the change in output values for small change in input values
np.linalg.cond(a)


Out[274]:
34656746943233008.0

In [276]:
# Determining sign and natural logarithm of determinant of matrix
np.linalg.slogdet(a)


Out[276]:
(0.0, -inf)

In [277]:
# This function returns one of norms out of eight different matrix norms or one out of an infinite number of vector norms 
# depending on the arguments. 
np.linalg.norm(a)


Out[277]:
50.586559479766954

In [288]:
# Eigen values and right eigen vectors of square array using functions numpy.linalg.eig().
# To obtain only eigen values of a general matrix, we use function numpy.linalg.eigvals() 
a = np.array([[2,3],[10,11]])
print a
print 'Eigen Values and Eigen Vectors'
print np.linalg.eig(a)
print 'Eigen Values'
print np.linalg.eigvals(a)


[[ 2  3]
 [10 11]]
Eigen Values and Eigen Vectors
(array([ -0.58872344,  13.58872344]), array([[-0.7570958 , -0.25061117],
       [ 0.65330388, -0.96808783]]))
Eigen Values
[ -0.58872344  13.58872344]

In [289]:
# To obtain eigen values and eigen vectors of symmetric or hermitian matrix, we use function numpy.linalg.eigh()
# To obtain eigen values of a symmetric or hermitian matrix, we use function numpy.linalg.eigvalsh() 
a = np.array([[1,4,5],[4,2,6],[5,6,3]])
print a
print 'Eigen Values and Eigen Vectors'
np.linalg.eigh(a)
print 'Eigen Values'
np.linalg.eigvalsh(a)


[[1 4 5]
 [4 2 6]
 [5 6 3]]
Eigen Values and Eigen Vectors
Eigen Values
Out[289]:
array([ -3.6686831 ,  -2.50728797,  12.17597107])

In [292]:
# Solving system of linear scalar equations using function numpy.linalg.solve()
a = np.array([[2,3],[1,2]])
b = np.array([[3,4],[5,6]])
np.linalg.solve(a,b)


Out[292]:
array([[ -9., -10.],
       [  7.,   8.]])

In [293]:
# Obtaining inverse of matrix using function numpy.linalg.inv() 
np.linalg.inv(a)


Out[293]:
array([[ 2., -3.],
       [-1.,  2.]])

In [294]:
# NumPy also have some functions to deal with polynomials 
# If we give set of roots to function np.poly(), it returns possible coefficients
np.poly([1,2])


Out[294]:
array([ 1., -3.,  2.])

In [295]:
# We can perform opposite operation to obtain roots of polynomial by passing coefficients to function np.roots()
np.roots([1,-3,2])


Out[295]:
array([ 2.,  1.])

In [308]:
# For polynomials, we can perform integration and differentiation using functions numpy.polyint() and numpy.polyder()
# respectively.
# Polynomial becomes x^3 + 2*x^2 + 4*x + 3 
inte = np.polyint([1,2,4,3])
inte


Out[308]:
array([ 0.25      ,  0.66666667,  2.        ,  3.        ,  0.        ])

In [309]:
# Using function numpy.polyder() for obtaining derivation of the same polynomial from its integration  
der = np.polyder(inte)
der


Out[309]:
array([ 1.,  2.,  4.,  3.])

In [307]:
# We can solve some polynomial for particular value by using function numpy.polyval()
# Here it takes coefficients of the polynomial and the value for which to solve as an input. 
# Polynomial becomes x^2 + x + 1 and value of x = 2 results value 7 
np.polyval([1,1,1],2)


Out[307]:
7

In [310]:
# There are functions like numpy.polyadd(), numpy.polysub(), numpy.polymul() and numpy.polydiv() for addition, subtraction, 
# multiplication and division respectively. 
# Showing an example for addition here. Other functions can be explored in similar manner. 
a = np.array([1,2,3])
b = np.array([4,5,6])
np.polyadd(a,b)


Out[310]:
array([5, 7, 9])

In [311]:
# Dealing with generation of random numbers using numpy subpackage numpy.random
# Using np.random.seed() to obtain same sequence of random numbers at different points in program
# Using same seed value ensures to generating same sequence of random numbers which is useful in debugging purpose 
np.random.seed(5)

In [312]:
# We can generate array of random numbers in half-open interval [0.0, 1) using function np.random.rand()
np.random.rand(5)


Out[312]:
array([ 0.22199317,  0.87073231,  0.20671916,  0.91861091,  0.48841119])

In [313]:
# To genrate a single random number, we use fumction np.random.random() in interval [0,1).
np.random.random()


Out[313]:
0.6117438629026457

In [314]:
# 2D arrays can be generated by mentioning dimensions as input.
# Can also use reshape() function to set the dimensions appropriately. 
np.random.rand(4,5)


Out[314]:
array([[ 0.76590786,  0.51841799,  0.2968005 ,  0.18772123,  0.08074127],
       [ 0.7384403 ,  0.44130922,  0.15830987,  0.87993703,  0.27408646],
       [ 0.41423502,  0.29607993,  0.62878791,  0.57983781,  0.5999292 ],
       [ 0.26581912,  0.28468588,  0.25358821,  0.32756395,  0.1441643 ]])

In [ ]: