|  | 
|  | 1 | +# Basic Mathematics | 
|  | 2 | +## What is a Matrix? | 
|  | 3 | +A matrix is a collection of numbers ordered in rows and columns. Here is one. | 
|  | 4 | + | 
|  | 5 | +<body> | 
|  | 6 | + <table> | 
|  | 7 | +  <tr> | 
|  | 8 | +  <td>1</td> | 
|  | 9 | +  <td>2</td> | 
|  | 10 | +  <td>3</td> | 
|  | 11 | +  </tr> | 
|  | 12 | +  <tr> | 
|  | 13 | +  <td>4</td> | 
|  | 14 | +  <td>5</td> | 
|  | 15 | +  <td>6</td> | 
|  | 16 | +  </tr> | 
|  | 17 | +  <tr> | 
|  | 18 | +  <td>7</td> | 
|  | 19 | +  <td>8</td> | 
|  | 20 | +  <td>9</td> | 
|  | 21 | +  </tr> | 
|  | 22 | + </table> | 
|  | 23 | +</body> | 
|  | 24 | + | 
|  | 25 | + | 
|  | 26 | +A matrix is generally written within square brackets[]. The dimensions of a matrix is represented by (Number of rows x Number of columns).The dimensions of the above matrix is 3x3. | 
|  | 27 | + | 
|  | 28 | +Matrices are the main characters in mathematical operations like addition, subtraction etc, especially those used in Pandas and NumPy. They can contain only numbers, symbols or expressions. | 
|  | 29 | + | 
|  | 30 | +In order to refer to a particular element in the matrix we denote it by :  | 
|  | 31 | +A<sub>ij</sub> | 
|  | 32 | + | 
|  | 33 | +where i represents the ith row and j represents the jth column of the matrix. | 
|  | 34 | + | 
|  | 35 | +## Scalars and Vectors | 
|  | 36 | +### Scalars | 
|  | 37 | +There exists specific cases of matrices which are also widely used. | 
|  | 38 | + | 
|  | 39 | +A matrix with only one row and column i.e. containing only one element is commonly referred to as a scalar. | 
|  | 40 | + | 
|  | 41 | +The numbers ```[12] ; [-5] ; [0] ; [3.14]``` all represent scalars. Scalars have 0 dimensions. | 
|  | 42 | + | 
|  | 43 | +### Vectors | 
|  | 44 | +Vectors are objects with 1 dimension. They sit somewhere between scalars and matrices. They can also be referred to as one dimensional matrices. | 
|  | 45 | + | 
|  | 46 | +```[1 3 5]``` represents a vector with dimension 1x3. | 
|  | 47 | + | 
|  | 48 | +A vector is the simplest linear algebraic object.A matrix can be refered to as a collection of vectors | 
|  | 49 | + | 
|  | 50 | +Vectors are broadly classified into 2 types: | 
|  | 51 | +- Row Vectors: Is of the form 1 x n where n refers to the number of columns the vector has.  | 
|  | 52 | +- Column Vectors: Is of the form m x 1 where m refers to the number of rows the vector has. | 
|  | 53 | + | 
|  | 54 | +m or n are also called as the length of the column and row vector respectively. | 
|  | 55 | + | 
|  | 56 | +## Arrays in Python | 
|  | 57 | + | 
|  | 58 | +To understand arrays, first let us start by declaring scalars, vectors and matrices in Python. | 
|  | 59 | + | 
|  | 60 | +First we need to import numpy. We do so by importing it as 'np' as it provides better readability, namespace clarity and also aligns with the community guidelines. | 
|  | 61 | + | 
|  | 62 | +```python | 
|  | 63 | +import numpy as np | 
|  | 64 | +``` | 
|  | 65 | +Next up, we declare a scalar s as, | 
|  | 66 | +``` | 
|  | 67 | +s = 5 | 
|  | 68 | +``` | 
|  | 69 | + | 
|  | 70 | + | 
|  | 71 | + | 
|  | 72 | +Now we declare a vector, | 
|  | 73 | +```python | 
|  | 74 | +v = np.array([5,-2,4]) | 
|  | 75 | +``` | 
|  | 76 | +On printing v we get the following output, | 
|  | 77 | +```python | 
|  | 78 | +array([5,-2,4]) | 
|  | 79 | +``` | 
|  | 80 | +By default, a vector is declared as a **'row vector'**. | 
|  | 81 | + | 
|  | 82 | +Finally, we declare matrices, | 
|  | 83 | +```python | 
|  | 84 | +m=np.array([[5,12,6],[-3,0,14]]) | 
|  | 85 | +``` | 
|  | 86 | +On printing m we get, | 
|  | 87 | +```python | 
|  | 88 | +array([[5,12,6], | 
|  | 89 | + [-3,0,14]]) | 
|  | 90 | +``` | 
|  | 91 | +> The type() function is used to return the data type of a given variable. | 
|  | 92 | +
 | 
|  | 93 | +* The type(s) will return **'int'**. | 
|  | 94 | + | 
|  | 95 | +* The type(v) will return **'numpy.ndarray'** which represents a **n-dimensional array**, since it is a 1 dimensional array. | 
|  | 96 | +  | 
|  | 97 | + * The type(m) will also return **'numpy.ndarray'** since it is a 2-dimensional array. | 
|  | 98 | + | 
|  | 99 | +These are some ways in which arrays are useful in python. | 
|  | 100 | + | 
|  | 101 | +> The shape() function is used to return the shape of a given variable. | 
|  | 102 | +
 | 
|  | 103 | +* m.shape() returns (2,3) since we are dealing with a (2,3) matrix. | 
|  | 104 | + | 
|  | 105 | +* v.shape() returns(3,) indicates it has only one dimensional or that it stores 3 elements in order. | 
|  | 106 | + | 
|  | 107 | +* However, 'int' objects do not have shape and therefore s.shape() gives an error. | 
|  | 108 | + | 
|  | 109 | +## What is a Tensor? | 
|  | 110 | +A Tensor can be thought of as a collection of matrices. It has dimensions k x m x n. | 
|  | 111 | + | 
|  | 112 | +**NOTE:** Scalars, vectors and matrices are also tensors of rank 0,1,2 respectively. | 
|  | 113 | + | 
|  | 114 | +Tensors can be stored in ndarrays. | 
|  | 115 | + | 
|  | 116 | +Let's create a tensor with 2 matrices, | 
|  | 117 | +```python | 
|  | 118 | +m1=np.array([[5,12,6],[-3,0,14]]) | 
|  | 119 | +m2=np.array([[2,1,8],[-6,2,0]]) | 
|  | 120 | +t=np.array([m1,m2]) | 
|  | 121 | +``` | 
|  | 122 | +Upon printing t we get, | 
|  | 123 | +```python | 
|  | 124 | +array([[[5,12,6], | 
|  | 125 | + [-3,0,14]], | 
|  | 126 | +  | 
|  | 127 | + [[2,1,8], | 
|  | 128 | + [-6,2,0]]]) | 
|  | 129 | +``` | 
|  | 130 | +If we check it's shape, we see that is is a **(2,2,3)** object. | 
|  | 131 | + | 
|  | 132 | +If we want to manually create a tensor we write, | 
|  | 133 | +```python | 
|  | 134 | +t=np.array([[[5,12,6], [-3,0,14]],[[2,1,8], [-6,2,0]]]) | 
|  | 135 | +``` | 
|  | 136 | + ## Addition and Subtraction in Matrices | 
|  | 137 | + | 
|  | 138 | + ### Addition | 
|  | 139 | + For 2 matrices to be added to one another they must have **same dimensions**. | 
|  | 140 | + | 
|  | 141 | + If we have 2 matrices say, | 
|  | 142 | + | 
|  | 143 | +```python | 
|  | 144 | +A=np.array([[5,12,6],[-3,0,14]]) | 
|  | 145 | +B=np.array([[2,1,8],[-6,2,0]]) | 
|  | 146 | +C= A+B | 
|  | 147 | + ``` | 
|  | 148 | +The element at position A<sub>ij</sub> gets added to the element at position B<sub>ij</sub>. It's that simple! | 
|  | 149 | +The above input will give the resultant C as: | 
|  | 150 | +```python | 
|  | 151 | +array([[7,13,14], | 
|  | 152 | + [-9,2,14]]) | 
|  | 153 | +``` | 
|  | 154 | +### Subtraction | 
|  | 155 | + | 
|  | 156 | +As we know, subtraction is a type of addition, the same rules apply here. | 
|  | 157 | + | 
|  | 158 | + If we have 2 matrices say, | 
|  | 159 | + | 
|  | 160 | +```python | 
|  | 161 | +A=np.array([[5,12,6],[-3,0,14]]) | 
|  | 162 | +B=np.array([[2,1,8],[-6,2,0]]) | 
|  | 163 | +C= A-B | 
|  | 164 | + ``` | 
|  | 165 | + | 
|  | 166 | +The element at position B<sub>ij</sub> gets subtracted from the element at position A<sub>ij</sub>. | 
|  | 167 | +The above input will give the resultant C as: | 
|  | 168 | +```python | 
|  | 169 | +array([[3,11,-2], | 
|  | 170 | + [3,-2,14]]) | 
|  | 171 | +``` | 
|  | 172 | +Similarly the same operations can be done with **floating point numbers** as well. | 
|  | 173 | + | 
|  | 174 | +In a similar fashion, we can add or subtract vectors as well with the condition that they must be of the **same length**. | 
|  | 175 | +```python | 
|  | 176 | +A=np.array([1,2,3,4,5]) | 
|  | 177 | +B=np.array([6,7,8,9,10]) | 
|  | 178 | +C= A+B | 
|  | 179 | + ``` | 
|  | 180 | +The result is a vector of length 5 with C as, | 
|  | 181 | +```python | 
|  | 182 | +array([7,9,11,13,15]) | 
|  | 183 | +``` | 
|  | 184 | + ### Addition of scalars with vectors & matrices | 
|  | 185 | + | 
|  | 186 | + Scalars show unique behaviour when added to matrices or vectors. | 
|  | 187 | + | 
|  | 188 | + To demonstrate their behaviour, let's use an example, | 
|  | 189 | + Let's declare a matrix, | 
|  | 190 | + | 
|  | 191 | +```python | 
|  | 192 | +A=np.array([[5,12,6],[-3,0,14]]) | 
|  | 193 | +A+1 | 
|  | 194 | +``` | 
|  | 195 | +We see that if we perform the above function, i.e. add scalar [1] to the matrix A we get the output, | 
|  | 196 | +```python | 
|  | 197 | +array([[6,13,7],[-2,1,15]]) | 
|  | 198 | +``` | 
|  | 199 | +We see that the scalar is added to the matrix elementwise, i.e. each element gets incremented by 1. | 
|  | 200 | + | 
|  | 201 | +**The same applies to vectors as well.** | 
|  | 202 | + | 
|  | 203 | +Mathematically, it is not allowed as the shape of scalars are different from vectors or matrices but while programming in Python it works. | 
|  | 204 | + | 
|  | 205 | +## Transpose of Matrices & Vectors | 
|  | 206 | +### Transposing Vectors | 
|  | 207 | + | 
|  | 208 | +If X is the vector, then the transpose of the vector is represented as X<sup>T</sup>. It changes a vector of dimension n x 1 into a vector of dimension 1 x n, i.e. a row vector to a column vector and vice versa. | 
|  | 209 | + | 
|  | 210 | +> * The values are not changing or transforming ; only their position is. | 
|  | 211 | +> * Transposing the same vector (object) twice yields the initial vector (object). | 
|  | 212 | +
 | 
|  | 213 | +```python | 
|  | 214 | +x=np.array([1,2,3)) | 
|  | 215 | +``` | 
|  | 216 | +Transposing this in python using ```x.T``` will give | 
|  | 217 | +```python | 
|  | 218 | +array([1,2,3)) | 
|  | 219 | +``` | 
|  | 220 | +which is the same vector as the one taken as input. | 
|  | 221 | + | 
|  | 222 | +> 1-Dimensional arrays don't really get transposed (in the memory of the computer) | 
|  | 223 | + | 
|  | 224 | +To transpose a vector, we need to reshape it first. | 
|  | 225 | +```python | 
|  | 226 | +x_new= x.reshape(1,3) | 
|  | 227 | +x_new.T | 
|  | 228 | +``` | 
|  | 229 | +will now result in the vector getting transposed, | 
|  | 230 | +```python | 
|  | 231 | +array([[1], | 
|  | 232 | + [2], | 
|  | 233 | + [3]]) | 
|  | 234 | +``` | 
|  | 235 | + | 
|  | 236 | +### Transposing Matrices | 
|  | 237 | + | 
|  | 238 | +If M is a matrix, then the transpose of the matrix M is represented as M<sup>T</sup>. When transposed, a m x n matrix becomes a n x m matrix.  | 
|  | 239 | + | 
|  | 240 | +The element M<sub>ij</sub> of the initial matrix becomes the N<sub>ji</sub> where N is the transposed matrix of M. | 
|  | 241 | + | 
|  | 242 | +Let's understand this further with the help of of an example, | 
|  | 243 | +```python | 
|  | 244 | +A = np.array([[1,5,-6],[8,-2,0]]) | 
|  | 245 | +``` | 
|  | 246 | +The output for the above code snippet will be, | 
|  | 247 | +```python | 
|  | 248 | +array([[1,5,-6], | 
|  | 249 | + [8,-2,0]]) | 
|  | 250 | +``` | 
|  | 251 | +> **array.T** returns the transpose of an array (matrix). | 
|  | 252 | + | 
|  | 253 | +```python | 
|  | 254 | +A.T | 
|  | 255 | +``` | 
|  | 256 | +will give the output as, | 
|  | 257 | +```python | 
|  | 258 | +array([[1,8], | 
|  | 259 | + [5,-2], | 
|  | 260 | + [-6,0]]) | 
|  | 261 | +``` | 
|  | 262 | + | 
|  | 263 | +Hope the following examples have cleared your concept on transposing. | 
|  | 264 | + | 
|  | 265 | +## Dot Product | 
|  | 266 | + | 
|  | 267 | +> **np.dot()** returns the dot product of two objects | 
|  | 268 | +> Dot product is represented by ( * ), for example, x(dot)y = x * y | 
|  | 269 | +>  | 
|  | 270 | +### Scalar * Scalar | 
|  | 271 | +Let's start with scalar multiplication first. | 
|  | 272 | + | 
|  | 273 | +``` [6] * [5] = [30] | 
|  | 274 | + [10] * [-2] = [-20] | 
|  | 275 | +``` | 
|  | 276 | +It is the same multiplication that we are familiar with since learnt as kids. | 
|  | 277 | + Therefore, ```np.dot([6]*[5])``` returns ```30```. | 
|  | 278 | + | 
|  | 279 | +### Vector * Vector | 
|  | 280 | +To multiply vectors with one another, they must be of **same length**. | 
|  | 281 | + | 
|  | 282 | +Now let's understand this with an example, | 
|  | 283 | +```python | 
|  | 284 | +x = np.array([2,8,-4]) | 
|  | 285 | +y = np.array([1,-7,3]) | 
|  | 286 | +``` | 
|  | 287 | + | 
|  | 288 | +The dot product returns the elementwise product of the vector i.e.  | 
|  | 289 | +x * y = ( x<sub>1</sub> * y<sub>1</sub> ) + ( x<sub>2</sub> * y<sub>2</sub> ) + ( x<sub>3</sub> * y<sub>3</sub> ) in the above example. | 
|  | 290 | + | 
|  | 291 | +Therefore, ```np.dot(x,y)``` gives ```[-66]``` as the input. | 
|  | 292 | + | 
|  | 293 | +We observe that **dot product of 2 vectors returns a scalar**. | 
|  | 294 | + | 
|  | 295 | +### Scalar * Vector | 
|  | 296 | + | 
|  | 297 | +When we multiply a scalar with a vector, we observe that each element of the vector gets multiplied to the scalar individually. | 
|  | 298 | +  | 
|  | 299 | +A scalar k when multiplied to a vector v([x1,x2,x3]) gives the product = [(k * x1) + (k * x2) + (k * x3)] | 
|  | 300 | + | 
|  | 301 | +An example would bring further clarity, | 
|  | 302 | +```python | 
|  | 303 | +y = np.array([1,-7,3]) | 
|  | 304 | +y*5 | 
|  | 305 | +``` | 
|  | 306 | +will give the following output | 
|  | 307 | +```python | 
|  | 308 | +array[(5,-35,15)] | 
|  | 309 | +``` | 
|  | 310 | + | 
|  | 311 | +We observe that **dot product of 2 vectors returns a scalar**. | 
|  | 312 | + | 
|  | 313 | +We observe that **dot product of a vector and a scalar returns a vector**. | 
|  | 314 | + | 
|  | 315 | +## Dot Product of Matrices  | 
|  | 316 | + | 
|  | 317 | +### Scalar * Matrix | 
|  | 318 | + Dot product of a scalar with a matrix works similar to dot product of a vector with a scalar. | 
|  | 319 | +Now, we come to a very important concept which will be very useful to us while working in Python. | 
|  | 320 | + | 
|  | 321 | +Each element of the vector gets multiplied to the scalar individually. | 
|  | 322 | + | 
|  | 323 | +```python | 
|  | 324 | +A = np.array([[1,5,-6],[8,-2,0]]) | 
|  | 325 | +B = 3 * A | 
|  | 326 | +``` | 
|  | 327 | +will give the resultant B as  | 
|  | 328 | +```python | 
|  | 329 | +array([[3,15,-18], | 
|  | 330 | + [24,-6,0]]) | 
|  | 331 | +``` | 
|  | 332 | +Thus each element gets multiplied by 3. | 
|  | 333 | +> NOTE: The dot product of a scalar and a matrix gives a matrix of the same shape as the input matrix. | 
|  | 334 | + | 
|  | 335 | +### Matrix * Matrix | 
|  | 336 | + A matrix can be multipied to a matrix. However it has certain compatibility measures, | 
|  | 337 | + * We can only multiply an m x n matrix with an n x k matrix | 
|  | 338 | + * Basically the 2nd dimension of the first matrix has to match the 1st dimension of the 2nd matrix. | 
|  | 339 | +> The output of a m x n matrix with a n x k matrix gives a **m x k** matrix. | 
|  | 340 | + | 
|  | 341 | +**Whenever we have a dot product of 2 matrices, we multiply row vectors within one matrix to the column vector of 2nd matrix.** | 
|  | 342 | + | 
|  | 343 | +For example, let's use multiply a row vector to a column vector to understand it further.  | 
|  | 344 | + | 
|  | 345 | +``` | 
|  | 346 | + ([[1] | 
|  | 347 | + ([2 8 4]) * [2] = [(2*1) + (8*2) + (4*3)] = [30] | 
|  | 348 | + [3]]) | 
|  | 349 | +``` | 
|  | 350 | +Now, let's multiply a 2 x 3 matrix with a 3 x 2 matrix. | 
|  | 351 | +``` | 
|  | 352 | + ([[A1,A2,A3], * ([[B1,B2] ([[(A1 * B1 + A2 * B3 + A3 * B5) , (A1 * B2 + A2 * B4 + A3 * B6)] | 
|  | 353 | + [A4,A5,A6]]) [B3,B4], = [ (A4 * B1 + A5 * B3 + A6 * B5) , (A4 * B2 + A5 * B4 + A6 * B6)]]) | 
|  | 354 | + [B5,B6]]) | 
|  | 355 | +``` | 
|  | 356 | +Thus we obtain a 2 x 2 matrix. | 
|  | 357 | + | 
|  | 358 | +We use the np.dot() method to directly obtain the dot product of the 2 matrices. | 
|  | 359 | + | 
|  | 360 | +Now let's do an example using python just to solidify our knowledge. | 
|  | 361 | + | 
|  | 362 | +```python | 
|  | 363 | +A=np.array([[5,12,6],[-3,0,14]]) | 
|  | 364 | +B=np.array([[2,-1],[8,0],[3,0]]) | 
|  | 365 | +np.dot(A,B) | 
|  | 366 | +``` | 
|  | 367 | +The output we obtain is, | 
|  | 368 | +```python | 
|  | 369 | +array[[124,-5], | 
|  | 370 | + [36, 3]]) | 
|  | 371 | +``` | 
0 commit comments