├── .DS_Store
├── .gitignore
├── Linear Algebra with Python.ipynb
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oldclesleycode/linear-algebra-with-python/3db15e421cfad40a5953874f8573f78a0ff7429e/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | __pycache__/
3 | .ipynb_checkpoints/
4 |
--------------------------------------------------------------------------------
/Linear Algebra with Python.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "# Setup\n",
8 | "\n",
9 | "This guide was written in Python 3.6.\n",
10 | "\n",
11 | "\n",
12 | "## Python and Pip\n",
13 | "\n",
14 | "Download [Python](https://www.python.org/downloads/) and [Pip](https://pip.pypa.io/en/stable/installing/).\n",
15 | "\n",
16 | "\n",
17 | "## Libraries\n",
18 | "\n",
19 | "We'll be working with `numpy` and `scipy`, so make sure to install them. Pull up your terminal and insert the following: \n",
20 | "\n",
21 | "```\n",
22 | "pip3 install scipy\n",
23 | "pip3 install numpy\n",
24 | "```"
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "# Introduction\n",
32 | "\n",
33 | "Linear Algebra is a branch of mathematics that allows you to concisely describe coordinates and interactions of planes in higher dimensions, as well as perform operations on them. \n",
34 | "\n",
35 | "Think of it as an extension of algebra into an arbitrary number of dimensions. Linear Algebra is about working on linear systems of equations. Rather than working with scalars, we work with matrices and vectors. This is particularly important to the study of computer science because vectors and matrices can be used to represent data of all forms - images, text, and of course, numerical values.\n",
36 | "\n",
37 | "## Why Learn Linear Algebra?\n",
38 | "\n",
39 | "Machine Learning: A lot of Machine Learning concepts are tied to linear algebra concepts. Some basic examples, PCA - eigenvalue, regression - matrix multiplication. As most ML techniques deal with high dimensional data, they are often times represented as matrices.\n",
40 | "\n",
41 | "Mathematical Modeling: for example, if you want to capture behaviors (sales, engagement, etc.) in a mathematical model, you can use matrices to breakdown the samples into their own subgroups. This requires some basic matrix manipulation, such as matrix inversion, derivation, solving partial differential, or first order differential equations with matrices, for example. \n"
42 | ]
43 | },
44 | {
45 | "cell_type": "markdown",
46 | "metadata": {},
47 | "source": [
48 | "## Scalars & Vectors\n",
49 | "\n",
50 | "You'll see the terms scalar and vector throughout this course, so it's very important that we learn how to distinguish between the two. A scalar refers to the magnitude of an object. In contrast, a vector has both a magnitude and a direction. \n",
51 | "\n",
52 | "An intuitive example is with respect to distance. If you drive 50 miles north, then the scalar value is `50`. Now, the vector that would represent this could be something like `(50, N)` which indicates to us both the direction and the magnitude. \n",
53 | "\n"
54 | ]
55 | },
56 | {
57 | "cell_type": "markdown",
58 | "metadata": {},
59 | "source": [
60 | "# Challenge\n",
61 | "\n",
62 | "Using the [distance formula](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.norm.html) and [trigonometry functions](https://docs.python.org/3/library/math.html) in Python, calculate the magnitude and direction of a line with the two coordinates, `(5,3)` and `(1,1)`.\n",
63 | "\n",
64 | "For more information on [distance formula](http://www.purplemath.com/modules/distform.htm) and [trigonometry functions](http://www2.clarku.edu/~djoyce/trig/formulas.html)\n"
65 | ]
66 | },
67 | {
68 | "cell_type": "code",
69 | "execution_count": null,
70 | "metadata": {
71 | "collapsed": true
72 | },
73 | "outputs": [],
74 | "source": []
75 | },
76 | {
77 | "cell_type": "markdown",
78 | "metadata": {},
79 | "source": [
80 | "## Vectors\n",
81 | "\n",
82 | "A vector is typically an ordered tuple of numbers which have both a magnitude and direction. It's important to note that vectors are an element of a vector space. \n",
83 | "\n",
84 | "In the next section, we'll learn about matrices, which are a rectangular array of values. A vector is simply a one dimensional matrix. \n",
85 | "\n",
86 | "Sometimes what we're given, however, isn't a neat two value tuple consisting of a magnitude and direction value. Sometimes we're given something that resembles a list, and from there, we can create a tuple that describes the vector. \n",
87 | "\n",
88 | "With that said, we can represent a vector with a list, for example: "
89 | ]
90 | },
91 | {
92 | "cell_type": "code",
93 | "execution_count": 65,
94 | "metadata": {
95 | "collapsed": true
96 | },
97 | "outputs": [],
98 | "source": [
99 | "A = [2.0, 3.0, 5.0]"
100 | ]
101 | },
102 | {
103 | "cell_type": "markdown",
104 | "metadata": {},
105 | "source": [
106 | "Now, let's write this same vector with `numpy` instead:"
107 | ]
108 | },
109 | {
110 | "cell_type": "code",
111 | "execution_count": 66,
112 | "metadata": {
113 | "collapsed": true
114 | },
115 | "outputs": [],
116 | "source": [
117 | "v = np.array([2.0, 3.0, 5.0])"
118 | ]
119 | },
120 | {
121 | "cell_type": "markdown",
122 | "metadata": {},
123 | "source": [
124 | "# Challenge\n",
125 | "\n",
126 | "Write code for two vectors with five values of your choice. The first should be written as a regular one-dimensional list. The other should be be written with numpy. "
127 | ]
128 | },
129 | {
130 | "cell_type": "code",
131 | "execution_count": null,
132 | "metadata": {
133 | "collapsed": true
134 | },
135 | "outputs": [],
136 | "source": []
137 | },
138 | {
139 | "cell_type": "markdown",
140 | "metadata": {},
141 | "source": [
142 | "### What is a Norm? \n",
143 | "\n",
144 | "Remember the distance formula from the intro section? That's what a norm is, which is why that function we used from scipy was called `linalg.norm`. With that said, just to review, a norm just refers to the magnitude of a vector, and is denoted with ||u||. With numpy and scipy, we can do calculate the norm as follows: "
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "execution_count": 67,
150 | "metadata": {
151 | "scrolled": true
152 | },
153 | "outputs": [
154 | {
155 | "data": {
156 | "text/plain": [
157 | "5.4772255750516612"
158 | ]
159 | },
160 | "execution_count": 67,
161 | "metadata": {},
162 | "output_type": "execute_result"
163 | }
164 | ],
165 | "source": [
166 | "import numpy as np\n",
167 | "v = np.array([1,2,3,4])\n",
168 | "nln.norm(v)"
169 | ]
170 | },
171 | {
172 | "cell_type": "markdown",
173 | "metadata": {},
174 | "source": [
175 | "The actual formula looks like: \n",
176 | "\n",
177 | "$$ ||v|| = \\sqrt{v_1^2 + ... + v_n^2} $$"
178 | ]
179 | },
180 | {
181 | "cell_type": "markdown",
182 | "metadata": {},
183 | "source": [
184 | "# Challenge\n",
185 | "\n",
186 | "Find the norm of the vector `[3, 9, 5, 4]` using the actual formula above. You should write a function `find_norm(v1)` that returns this value as a float and then call it on the provided variable `n1`. You should not use `scipy`, but you may use the `math` module. "
187 | ]
188 | },
189 | {
190 | "cell_type": "code",
191 | "execution_count": null,
192 | "metadata": {
193 | "collapsed": true
194 | },
195 | "outputs": [],
196 | "source": []
197 | },
198 | {
199 | "cell_type": "markdown",
200 | "metadata": {},
201 | "source": [
202 | "## Matrices\n",
203 | "\n",
204 | "A Matrix is a 2D array that stores real or complex numbers. You can think of them as multiple vectors in an array! You can use numpy to create matrices:"
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": 68,
210 | "metadata": {
211 | "collapsed": true
212 | },
213 | "outputs": [],
214 | "source": [
215 | "matrix1 = np.matrix(\n",
216 | " [[0, 4],\n",
217 | " [2, 0]]\n",
218 | ")\n",
219 | "matrix2 = np.matrix(\n",
220 | " [[-1, 2],\n",
221 | " [1, -2]]\n",
222 | ")"
223 | ]
224 | },
225 | {
226 | "cell_type": "markdown",
227 | "metadata": {},
228 | "source": [
229 | "# Challenge\n",
230 | "\n",
231 | "Using `numpy`, create a 3 x 5 matrix with values of your choice. "
232 | ]
233 | },
234 | {
235 | "cell_type": "code",
236 | "execution_count": null,
237 | "metadata": {
238 | "collapsed": true
239 | },
240 | "outputs": [],
241 | "source": []
242 | },
243 | {
244 | "cell_type": "markdown",
245 | "metadata": {},
246 | "source": [
247 | "# 1.0 Linear Equations"
248 | ]
249 | },
250 | {
251 | "cell_type": "markdown",
252 | "metadata": {},
253 | "source": [
254 | "## Gauss-Jordan Elimination\n",
255 | "\n",
256 | "Gaussian Elimination helps to put a matrix in row echelon form, while Gauss-Jordan Elimination puts a matrix in reduced row echelon form?"
257 | ]
258 | },
259 | {
260 | "cell_type": "markdown",
261 | "metadata": {},
262 | "source": [
263 | "## Solving Systems of Equations\n",
264 | "\n",
265 | "Consider a set of m linear equations in n unknowns:\n",
266 | "\n",
267 | "...\n",
268 | "\n",
269 | "We can let:\n",
270 | "\n",
271 | "...\n",
272 | "\n",
273 | "And re-write the system: \n",
274 | "\n",
275 | "```\n",
276 | "Ax = b\n",
277 | "```\n",
278 | "This reduces the problem to a matrix equation and now we can solve the system to find $A^{-1}$.\n"
279 | ]
280 | },
281 | {
282 | "cell_type": "markdown",
283 | "metadata": {},
284 | "source": [
285 | "### Systems of Equations with Python\n",
286 | "\n",
287 | "Using numpy, we can solve systems of equations in Python. Each equation in a system can be represented with matrices. For example, if we have the equation `3x - 9y = -42`, it can be represented as `[3, -9]` and `[-42]`. If we add another equation to the mix, for example, `2x + 4y = 2`, we can merge it with the previous equation to get `[[3, -9], [2, 4]]` and `[-42, 2]`. Now let's solve for the x and y values.\n",
288 | "\n",
289 | "Now, let's put these equations into numpy arrays:"
290 | ]
291 | },
292 | {
293 | "cell_type": "code",
294 | "execution_count": 69,
295 | "metadata": {
296 | "collapsed": true
297 | },
298 | "outputs": [],
299 | "source": [
300 | "A = np.array([ [3,-9], [2,4] ])\n",
301 | "b = np.array([-42,2])"
302 | ]
303 | },
304 | {
305 | "cell_type": "markdown",
306 | "metadata": {},
307 | "source": [
308 | "Now, we can use the `linalg.solve()` function to solve the x and y values. Note that these values will be\n"
309 | ]
310 | },
311 | {
312 | "cell_type": "code",
313 | "execution_count": 70,
314 | "metadata": {},
315 | "outputs": [
316 | {
317 | "data": {
318 | "text/plain": [
319 | "array([-5., 3.])"
320 | ]
321 | },
322 | "execution_count": 70,
323 | "metadata": {},
324 | "output_type": "execute_result"
325 | }
326 | ],
327 | "source": [
328 | "np.linalg.solve(A,b)"
329 | ]
330 | },
331 | {
332 | "cell_type": "markdown",
333 | "metadata": {},
334 | "source": [
335 | "which means `x = -5` and `y = 3`. \n"
336 | ]
337 | },
338 | {
339 | "cell_type": "markdown",
340 | "metadata": {},
341 | "source": [
342 | "### What is a vector space?\n",
343 | "\n",
344 | "A vector space V is a set that contains all linear combinations of its elements. In other words, if you have a set A, the space vector V includes all combinations of the elements in A. \n",
345 | "\n",
346 | "With that said, there are three properties that every vector space must follow:\n",
347 | "\n",
348 | "1. Additive Closure: If vectors u and v ∈ V, then u + v ∈ V
\n",
349 | "When we earlier stated that the vector space has all combinations of the elements in set A, one of the operations we meant by 'combinations' was vector addition. For example if we have two vectors in set A, let's say (4, 5) and (3, 1), then the vector space of A must have those two vectors, as well as the vector (4+3, 5+1), or `(7, 6)`. This has to be true for any two vectors in set A. \n",
350 | "\n",
351 | "2. Scalar Closure: If u ∈ V, then α · u must ∈ Ν for any scalar α
\n",
352 | "Recall that a scalar is a magnitude value with no direction, such as 5. For a vector space to be a vector space, that means for every vector in the original set A, that vector multiplied by any number (or constant or scalar) must be in the vector space V. \n",
353 | "\n",
354 | "3. Additive Identity: There exists a · 0 ∈ V such that u + 0 = u for any u ∈ V
\n",
355 | "In other words, the vector space of set A must contain the zero vector.\n",
356 | "\n",
357 | "4. Additive Associativity: If u, v, w ∈ V, then u + (v + w) = (u + v) + w
\n",
358 | "Regardless of the order in which you add multiple vectors, their results should be the same\n",
359 | "\n",
360 | "5. Additive Inverse: If u ∈ V, then there exists a vector −u ∈ V so that u + (−u) = 0.
\n",
361 | "For example, if the vector (2, 3) ∈ V, then its additive inverse is (-2, -3) and must also be an element of the vector space V. \n",
362 | "\n",
363 | "\n",
364 | "The dimension of a vector space V is the cardinality. It's usually denoted as superscript, for example, ℜn. Let's break down what this looks like:\n",
365 | "\n",
366 | "- ℜ2 refers to your typical x, y systems of equations.
\n",
367 | "\n",
368 | "- ℜ3 adds an extra dimension, which means adding another variable, perhaps z."
369 | ]
370 | },
371 | {
372 | "cell_type": "markdown",
373 | "metadata": {},
374 | "source": [
375 | "# 2.0 Linear Transformations"
376 | ]
377 | },
378 | {
379 | "cell_type": "markdown",
380 | "metadata": {},
381 | "source": [
382 | "## Matrix Operations\n",
383 | "\n",
384 | "What makes matrices particularly useful is the fact that we can perform operations on them. While it won't be necessarily intuitive why these operations are important right now, it will become obvious in later content.\n",
385 | "\n",
386 | "### Addition\n",
387 | "\n",
388 | "Matrix addition works very similarlty to normal addition. You simply add the corresponding spots together. \n"
389 | ]
390 | },
391 | {
392 | "cell_type": "code",
393 | "execution_count": 82,
394 | "metadata": {
395 | "scrolled": true
396 | },
397 | "outputs": [
398 | {
399 | "data": {
400 | "text/plain": [
401 | "matrix([[-1, 6],\n",
402 | " [ 3, -2]])"
403 | ]
404 | },
405 | "execution_count": 82,
406 | "metadata": {},
407 | "output_type": "execute_result"
408 | }
409 | ],
410 | "source": [
411 | "matrix1 + matrix2"
412 | ]
413 | },
414 | {
415 | "cell_type": "markdown",
416 | "metadata": {},
417 | "source": [
418 | "### Multiplication\n",
419 | "\n",
420 | "To multiply two matrices with numpy, you can use the `np.dot` method: \n"
421 | ]
422 | },
423 | {
424 | "cell_type": "code",
425 | "execution_count": 71,
426 | "metadata": {
427 | "scrolled": true
428 | },
429 | "outputs": [
430 | {
431 | "data": {
432 | "text/plain": [
433 | "matrix([[ 4, -8],\n",
434 | " [-2, 4]])"
435 | ]
436 | },
437 | "execution_count": 71,
438 | "metadata": {},
439 | "output_type": "execute_result"
440 | }
441 | ],
442 | "source": [
443 | "np.dot(matrix1, matrix2)"
444 | ]
445 | },
446 | {
447 | "cell_type": "markdown",
448 | "metadata": {},
449 | "source": [
450 | "Or, simply, you can do:"
451 | ]
452 | },
453 | {
454 | "cell_type": "code",
455 | "execution_count": 72,
456 | "metadata": {
457 | "scrolled": true
458 | },
459 | "outputs": [
460 | {
461 | "data": {
462 | "text/plain": [
463 | "matrix([[ 4, -8],\n",
464 | " [-2, 4]])"
465 | ]
466 | },
467 | "execution_count": 72,
468 | "metadata": {},
469 | "output_type": "execute_result"
470 | }
471 | ],
472 | "source": [
473 | "matrix1 * matrix2"
474 | ]
475 | },
476 | {
477 | "cell_type": "markdown",
478 | "metadata": {},
479 | "source": [
480 | "The dot product is an operation that takes two coordinate vectors of equal size and returns a single number. The result is calculated by multiplying corresponding entries and adding up those products. "
481 | ]
482 | },
483 | {
484 | "cell_type": "markdown",
485 | "metadata": {},
486 | "source": [
487 | "# Challenge\n",
488 | "\n",
489 | "Write a function `matrix_add(matrix_A, matrix_B)` that performs matrix addition if the dimensionality is valid. Note that the dimensionality is only valid if input matrix A and input matrix B are of the same dimension in both their row and column lengths. \n",
490 | "\n",
491 | "For example, you can add a 3x5 matrix with a 3x5 matrix, but you cannot add a 3x5 matrix with a 3x1 matrix. If the dimensionality is not valid, print this error message \"Cannot perform matrix addition between a-by-b matrix and c-by-d matrix\", where you substitute a, b with the dimension of the input matrix A, and c,d with the dimension of the input matrix B.\n"
492 | ]
493 | },
494 | {
495 | "cell_type": "code",
496 | "execution_count": null,
497 | "metadata": {
498 | "collapsed": true
499 | },
500 | "outputs": [],
501 | "source": []
502 | },
503 | {
504 | "cell_type": "markdown",
505 | "metadata": {},
506 | "source": [
507 | "### Identity Matrix\n",
508 | "\n",
509 | "A Diagonal Matrix is an n x n matrix with 1s on the diagonal from the top left to the bottom right, such as \n",
510 | "\n",
511 | "``` \n",
512 | "[[ 1., 0., 0.],\n",
513 | "[ 0., 1., 0.],\n",
514 | "[ 0., 0., 1.]]\n",
515 | "```\n",
516 | "\n",
517 | "We can generate diagonal matrices with the `eye()` function in Python: \n"
518 | ]
519 | },
520 | {
521 | "cell_type": "code",
522 | "execution_count": 80,
523 | "metadata": {
524 | "scrolled": true
525 | },
526 | "outputs": [
527 | {
528 | "data": {
529 | "text/plain": [
530 | "array([[ 1., 0., 0., 0.],\n",
531 | " [ 0., 1., 0., 0.],\n",
532 | " [ 0., 0., 1., 0.],\n",
533 | " [ 0., 0., 0., 1.]])"
534 | ]
535 | },
536 | "execution_count": 80,
537 | "metadata": {},
538 | "output_type": "execute_result"
539 | }
540 | ],
541 | "source": [
542 | "np.eye(4)"
543 | ]
544 | },
545 | {
546 | "cell_type": "markdown",
547 | "metadata": {},
548 | "source": [
549 | "When a matrix is multiplied by its inverse, the result is the identity matrix. It's important to note that only square matrices have inverses!"
550 | ]
551 | },
552 | {
553 | "cell_type": "markdown",
554 | "metadata": {},
555 | "source": [
556 | "# Challenge\n",
557 | "\n",
558 | "```\n",
559 | "A = [[1 2]\n",
560 | " [3 4]]\n",
561 | " \n",
562 | "B = [[-2. 1. ]\n",
563 | " [ 1.5 -0.5]]\n",
564 | " \n",
565 | "C = [[1 2 3]\n",
566 | " [4 5 6]]\n",
567 | "``` \n",
568 | " \n",
569 | "1. Given matrix A and B, mutiply AB - call this `mat1`. Mutiply BA - call this `mat2`. Are these matrix inverses?\n",
570 | "\n",
571 | "2. Given matrix C, create an identity matrix - call it `id1` to multiply C*id1- call this `mat3`. \n",
572 | "\n",
573 | "3. Given matrix C, create an identity matrix - call it `id2` to multiply id2*C- call this `mat4`. "
574 | ]
575 | },
576 | {
577 | "cell_type": "markdown",
578 | "metadata": {},
579 | "source": [
580 | "### Inverse Matrices\n",
581 | "\n",
582 | "The matrix A is invertible if there exists a matrix A-1 such that\n",
583 | "\n",
584 | "A-1A = I and AA-1 = I\n",
585 | "\n",
586 | "Multiplying inverse matrix is like the division; it’s simply the reciprocal function of multiplication. Let’s say here is a square matrix A, then multiplying its inversion gives the identity matrix I.\n",
587 | "\n",
588 | "We can get the inverse matrix with numpy: "
589 | ]
590 | },
591 | {
592 | "cell_type": "code",
593 | "execution_count": 81,
594 | "metadata": {},
595 | "outputs": [
596 | {
597 | "name": "stdout",
598 | "output_type": "stream",
599 | "text": [
600 | "[[ 0. 0.5 ]\n",
601 | " [ 0.25 0. ]]\n"
602 | ]
603 | }
604 | ],
605 | "source": [
606 | "inverse = np.linalg.inv(matrix1)\n",
607 | "print(inverse)"
608 | ]
609 | },
610 | {
611 | "cell_type": "markdown",
612 | "metadata": {},
613 | "source": [
614 | "# Challenge\n",
615 | "\n",
616 | "Write a function `matrix_inverse(matrix_A)` that outputs the inverse matrix. "
617 | ]
618 | },
619 | {
620 | "cell_type": "code",
621 | "execution_count": null,
622 | "metadata": {
623 | "collapsed": true
624 | },
625 | "outputs": [],
626 | "source": []
627 | },
628 | {
629 | "cell_type": "markdown",
630 | "metadata": {},
631 | "source": [
632 | "# 3.0 Subspaces and Their Dimensions"
633 | ]
634 | },
635 | {
636 | "cell_type": "markdown",
637 | "metadata": {},
638 | "source": [
639 | "### Kernels & Images\n",
640 | "\n",
641 | "#### Images \n",
642 | "\n",
643 | "The image of a function consists of all the values the function takes in its codomain.\n",
644 | "\n",
645 | "#### Kernels\n",
646 | "\n",
647 | "The kernel of a matrix A is the dimension of the space mapped to zero under the linear transformation that A represents. The dimension of the kernel of a linear transformation is called the nullity.\n",
648 | "\n"
649 | ]
650 | },
651 | {
652 | "cell_type": "markdown",
653 | "metadata": {},
654 | "source": [
655 | "### What is a subspace?\n",
656 | "\n",
657 | "A vector subspace is a subset of a vector space. That subspace is also a vector space, so it follows all the rules we reviewed above. It's also important to note that if W is a linear subspace of V, then the dimension of W must be ≤ the dimension of V.\n",
658 | "\n",
659 | "The easiest way to check whether it's a vector subspace is to check if it's closed under addition and scalar multiplication. Let's go over an example:\n",
660 | "\n",
661 | "Let's show that the set V = {(x, y, z) | x, y, z ∈ ℜ and x*x = z*z } is not a subspace of ℜ3.\n",
662 | "\n",
663 | "If V is actually a subspace of ℜ3, that means it must follow all the properties listed in the beginning of this section. Recall that this is because all subspaces must also be vector spaces. \n",
664 | "\n",
665 | "Let's evaluate the first property that stays the following:\n",
666 | "\n",
667 | "If vectors u and v ∈ V, then u + v ∈ V\n",
668 | "\n",
669 | "Now, is this true of the set we've defined above? Absolutely not. (1, 1, 1) and (1, 1, -1) are both in V, but what about their sum, (1, 2, 0)? It's not! And because it's not, it does not follow the required properties of a vector space. Therefore, we can conluse that it's also not a subspace. \n"
670 | ]
671 | },
672 | {
673 | "cell_type": "markdown",
674 | "metadata": {},
675 | "source": [
676 | "# Challenge\n",
677 | "\n",
678 | "1. Write the representation of ℜ2 as a list comprehension - use ranges between -10 and 10 for all values of x and y. \n",
679 | "\n",
680 | "2. Write the representation of ℜ3 as a list comprehension - use ranges between -10 and 10 for all values of x, y, and z. \n",
681 | "\n",
682 | "3. Write a list comprehension that represents the the set V = {(x, y, z) | x, y, z ∈ ℜ and x+y = 11}. Use ranges between -10 and 10 for all values of x, y, and z. \n",
683 | "\n",
684 | "4. Choose three values of x, y, and z that show the set V = {(x, y, z) | x, y, z ∈ ℜ and x+y = 11} is not a subspace of ℜ3. These values should represent a tuple that would be in vector V had it been a vector subspace. Each value should also be between -10 and 10. \n"
685 | ]
686 | },
687 | {
688 | "cell_type": "markdown",
689 | "metadata": {},
690 | "source": [
691 | "### What is Linear Dependence? \n",
692 | "\n",
693 | "A set of vectors {v1,...,vn} is linearly independent if there are scalars c1...cn (which aren't all 0) such that the following is true:\n",
694 | "\n",
695 | "c1v1 + ... + cnvn = 0\n",
696 | "\n",
697 | "#### Example\n",
698 | "\n",
699 | "Let's say we have three vectors in a set: x1 = (1, 1, 1), x2 = (1, -1, 2), and x3 = (3, 1, 4). \n",
700 | "\n",
701 | "These set of vectors are linear dependent because 2x1 + x2 - x3 = 0. Why is this equal to zero? Again, because 2*(1,1,1) + 1(1,-1,2) - (3,1,4) = (2+1-3, 2-1-1, 2+2-4) = (0, 0, 0). If we can find some equation that satisfies a resultant of 0, it's considered linear dependent!\n",
702 | "\n",
703 | "### What is Linear Independence? \n",
704 | "\n",
705 | "A set of vectors is considered linear dependent simply if they are not linear dependent! In other words, all the constants from the previous section should be equal to zero. c1 = c2 = ... = cn = 0\n",
706 | "\n",
707 | "### What is a basis? \n",
708 | "\n",
709 | "Any linearly independent set of n vectors spans an n-dimensional space. This set of vectors is referred to as the basis of ℜn. \n",
710 | "\n",
711 | "#### Under vs Overdetermined Matrices\n",
712 | "\n",
713 | "When `m < n`, the linear system is said to be underdetermined, e.g. there are fewer equations than unknowns. In this case, there are either no solutions or infinite solutions and a unique solution is not possible.\n",
714 | "\n",
715 | "When `m > n`, the system may be overdetermined. In other words, there are more equations than unknowns. They system could be inconsistent, or some of the equations could be redundant. \n",
716 | "\n",
717 | "If some of the rows of an m x n matrix are linearly dependent, then the system is reducible and we get get rid of some of the rows. \n",
718 | "\n",
719 | "Lastly, if a matrix is square and its rows are linearly independent, the system has a unique solution and is considered invertible."
720 | ]
721 | },
722 | {
723 | "cell_type": "markdown",
724 | "metadata": {},
725 | "source": [
726 | "# Challenge\n",
727 | "\n",
728 | "```\n",
729 | "A = [[1 1]\n",
730 | " [0 1]]\n",
731 | "\n",
732 | "B = [[1 2]\n",
733 | " [3 6]]\n",
734 | "```\n",
735 | "Note: `linalg.det(A)` gives the determinant of matrix A. \n",
736 | "\n",
737 | "Note: `linalg.inv(A)` finds the inverse matrix of A. \n",
738 | "\n",
739 | "Note: `linalg.solve(A,b)` will solve for x. (Ax = b)\n",
740 | "\n",
741 | "Recall: A nonzero determinant is equivacal to the matrix being invertible. \n",
742 | "\n",
743 | "\n",
744 | "1. Consider a 2-by-2 identity matrix, I. We see that this is a basis of ℜ2 spanned by vectors [1,0] and [0,1]. Solve the unique solution for b = [3,4] - call this `sol1`. \n",
745 | "\n",
746 | "2. Given matix A, compute the determinant - call this `det1`. Find the inverse of this matrix - call this `mat1`. We see that this is a basis of ℜdim. What integer is `dim`? This is spanned by two vectors, one being [0,1]. What is the other one - call this `bas1` Solve the unique solution for b = [3,4] - call this `sol2`. (Observe how matrix A and the identity matrix give two different solutions.)\n",
747 | "\n",
748 | "3. Given matix B, compute the determinant - call this `det2`. We see that matrix is noninvertible and the rows are linearly dependent. Infact we see this matrix is reducible if we perform the following operation on row 2: `alpha` x row 1 - row 2. What is the value of `alpha`?\n"
749 | ]
750 | },
751 | {
752 | "cell_type": "code",
753 | "execution_count": null,
754 | "metadata": {
755 | "collapsed": true
756 | },
757 | "outputs": [],
758 | "source": []
759 | },
760 | {
761 | "cell_type": "markdown",
762 | "metadata": {},
763 | "source": [
764 | "# 5.0 Orthogonality and Least Squares\n",
765 | "\n",
766 | "\n",
767 | "## QR Decomposition with Gram-Schmidt\n",
768 | "\n",
769 | "\n",
770 | "QR decomposition (also called a QR factorization) of a matrix is a decomposition of a matrix A into a product A = QR of an orthogonal matrix Q and an upper triangular matrix R. QR decomposition is often used to solve the linear least squares problem and is the basis for a particular eigenvalue algorithm, the QR algorithm."
771 | ]
772 | },
773 | {
774 | "cell_type": "code",
775 | "execution_count": 73,
776 | "metadata": {
777 | "collapsed": true
778 | },
779 | "outputs": [],
780 | "source": [
781 | "A = np.matrix([[1,1,0], [1,0,1], [0,1,1]])"
782 | ]
783 | },
784 | {
785 | "cell_type": "code",
786 | "execution_count": 74,
787 | "metadata": {
788 | "collapsed": true
789 | },
790 | "outputs": [],
791 | "source": [
792 | "Q,R = np.linalg.qr(A)"
793 | ]
794 | },
795 | {
796 | "cell_type": "code",
797 | "execution_count": 75,
798 | "metadata": {
799 | "scrolled": true
800 | },
801 | "outputs": [
802 | {
803 | "data": {
804 | "text/plain": [
805 | "matrix([[-0.70710678, 0.40824829, -0.57735027],\n",
806 | " [-0.70710678, -0.40824829, 0.57735027],\n",
807 | " [-0. , 0.81649658, 0.57735027]])"
808 | ]
809 | },
810 | "execution_count": 75,
811 | "metadata": {},
812 | "output_type": "execute_result"
813 | }
814 | ],
815 | "source": [
816 | "Q"
817 | ]
818 | },
819 | {
820 | "cell_type": "code",
821 | "execution_count": 76,
822 | "metadata": {
823 | "scrolled": true
824 | },
825 | "outputs": [
826 | {
827 | "data": {
828 | "text/plain": [
829 | "matrix([[-1.41421356, -0.70710678, -0.70710678],\n",
830 | " [ 0. , 1.22474487, 0.40824829],\n",
831 | " [ 0. , 0. , 1.15470054]])"
832 | ]
833 | },
834 | "execution_count": 76,
835 | "metadata": {},
836 | "output_type": "execute_result"
837 | }
838 | ],
839 | "source": [
840 | "R"
841 | ]
842 | },
843 | {
844 | "cell_type": "markdown",
845 | "metadata": {},
846 | "source": [
847 | "# 6.0 Determinants"
848 | ]
849 | },
850 | {
851 | "cell_type": "markdown",
852 | "metadata": {},
853 | "source": [
854 | "### Trace and Determinant\n",
855 | "\n",
856 | "The trace of a matrix A is the sum of its diagonal elements. It's important because it's an invariant of a matrix under change of basis and it defines a matrix norm. \n",
857 | "\n",
858 | "In Python, this can be done with the `numpy` module: "
859 | ]
860 | },
861 | {
862 | "cell_type": "code",
863 | "execution_count": 77,
864 | "metadata": {},
865 | "outputs": [
866 | {
867 | "name": "stdout",
868 | "output_type": "stream",
869 | "text": [
870 | "0\n"
871 | ]
872 | }
873 | ],
874 | "source": [
875 | "print(np.trace(matrix1))"
876 | ]
877 | },
878 | {
879 | "cell_type": "markdown",
880 | "metadata": {},
881 | "source": [
882 | "which in this case is just `0`. \n",
883 | "\n",
884 | "The determinant of a matrix is defined to be the alternating sum of permutations of the elements of a matrix. The formula is as follows:"
885 | ]
886 | },
887 | {
888 | "cell_type": "markdown",
889 | "metadata": {},
890 | "source": [
891 | "\\begin{bmatrix} \n",
892 | " a & b \\\\\n",
893 | " c & d \\\\\n",
894 | "\\end{bmatrix}"
895 | ]
896 | },
897 | {
898 | "cell_type": "markdown",
899 | "metadata": {},
900 | "source": [
901 | "\n",
902 | "\n",
903 | "$$ = ad - bc $$"
904 | ]
905 | },
906 | {
907 | "cell_type": "markdown",
908 | "metadata": {},
909 | "source": [
910 | "In python, you can use the following function:"
911 | ]
912 | },
913 | {
914 | "cell_type": "code",
915 | "execution_count": 78,
916 | "metadata": {},
917 | "outputs": [
918 | {
919 | "name": "stdout",
920 | "output_type": "stream",
921 | "text": [
922 | "-8.0\n"
923 | ]
924 | }
925 | ],
926 | "source": [
927 | "det = np.linalg.det(matrix1)\n",
928 | "print(det)"
929 | ]
930 | },
931 | {
932 | "cell_type": "markdown",
933 | "metadata": {},
934 | "source": [
935 | "Note that an n×n matrix A is invertible $\\iff$ det(A) $\\ne$ 0."
936 | ]
937 | },
938 | {
939 | "cell_type": "markdown",
940 | "metadata": {},
941 | "source": [
942 | "# Challenge\n",
943 | "\n",
944 | "Write a function `matrix_det(matrix_A)` that calculates the determinant (an integer) of matrix A if it is a 1x1 or 2x2 matrix. \n",
945 | "\n",
946 | "- If the input matrix is not square, print this error message \"Cannot calculate determinant of a non-square matrix.\" \n",
947 | "- If the input matrix is square but has a higher dimension, print the error message \"Cannot calculate determinant of a n-by-n matrix\", where you substitute n with the dimension of the input matrix."
948 | ]
949 | },
950 | {
951 | "cell_type": "code",
952 | "execution_count": null,
953 | "metadata": {
954 | "collapsed": true
955 | },
956 | "outputs": [],
957 | "source": []
958 | },
959 | {
960 | "cell_type": "markdown",
961 | "metadata": {},
962 | "source": [
963 | "## Matrix Types\n",
964 | "\n",
965 | "### Under vs Overdetermined Matrices\n",
966 | "\n",
967 | "When `m < n`, the linear system is said to be underdetermined, e.g. there are fewer equations than unknowns. In this case, there are either no solutions or infinite solutions and a unique solution is not possible.\n",
968 | "\n",
969 | "When `m > n`, the system may be overdetermined. In other words, there are more equations than unknowns. They system could be inconsistent, or some of the equations could be redundant. \n",
970 | "\n",
971 | "### Row, Column, and Null Space \n",
972 | "\n",
973 | "The column space C(A) of a matrix A (sometimes called the range of a matrix) is the span (set of all possible linear combinations) of its column vectors.\n",
974 | "\n",
975 | "The row space of an m x n matrix, A, denoted by R(A) is the set of all linear combinations of the row vectors of A.\n",
976 | "\n",
977 | "The null space of an m x n matrix, A, denoted by null(A) is the set of all solutions, x, of the equation Ax = 0m.\n",
978 | "\n",
979 | "### Rank\n",
980 | "\n",
981 | "The rank of a matrix A is the dimension of its column space - and - the dimension of its row space. These are equal for any matrix. Rank can be thought of as a measure of non-degeneracy of a system of linear equations, in that it is the dimension of the image of the linear transformation determined by A.\n",
982 | "\n",
983 | "### Transpose\n",
984 | "\n",
985 | "The transpose of a matrix is another operation that can be accomplished with `numpy`. Its importance isn't so obvious as first, but they're used to . Now, let's take a look at an example. Given the matrix below, let's find what its transpose looks like. "
986 | ]
987 | },
988 | {
989 | "cell_type": "code",
990 | "execution_count": 83,
991 | "metadata": {
992 | "scrolled": true
993 | },
994 | "outputs": [
995 | {
996 | "data": {
997 | "text/plain": [
998 | "array([[1, 2],\n",
999 | " [3, 4]])"
1000 | ]
1001 | },
1002 | "execution_count": 83,
1003 | "metadata": {},
1004 | "output_type": "execute_result"
1005 | }
1006 | ],
1007 | "source": [
1008 | "a = np.array([[1, 2], [3, 4]])\n",
1009 | "a"
1010 | ]
1011 | },
1012 | {
1013 | "cell_type": "markdown",
1014 | "metadata": {},
1015 | "source": [
1016 | "Notice the the 2 and 3 flipped positions. The transpose essentially flips the positions of a matrix in a particular way. "
1017 | ]
1018 | },
1019 | {
1020 | "cell_type": "code",
1021 | "execution_count": 84,
1022 | "metadata": {},
1023 | "outputs": [
1024 | {
1025 | "data": {
1026 | "text/plain": [
1027 | "array([[1, 3],\n",
1028 | " [2, 4]])"
1029 | ]
1030 | },
1031 | "execution_count": 84,
1032 | "metadata": {},
1033 | "output_type": "execute_result"
1034 | }
1035 | ],
1036 | "source": [
1037 | "a.transpose()"
1038 | ]
1039 | },
1040 | {
1041 | "cell_type": "markdown",
1042 | "metadata": {},
1043 | "source": [
1044 | "So what does that look like when we have a matrix that's not 2x2 dimensions? "
1045 | ]
1046 | },
1047 | {
1048 | "cell_type": "code",
1049 | "execution_count": 85,
1050 | "metadata": {
1051 | "scrolled": true
1052 | },
1053 | "outputs": [
1054 | {
1055 | "data": {
1056 | "text/plain": [
1057 | "array([[1, 2, 3],\n",
1058 | " [4, 5, 6]])"
1059 | ]
1060 | },
1061 | "execution_count": 85,
1062 | "metadata": {},
1063 | "output_type": "execute_result"
1064 | }
1065 | ],
1066 | "source": [
1067 | "a = np.array([[1, 2, 3], [4, 5, 6]])\n",
1068 | "a"
1069 | ]
1070 | },
1071 | {
1072 | "cell_type": "markdown",
1073 | "metadata": {},
1074 | "source": [
1075 | "The number of dimensions is now flipped as well. Instead of three columns, we now have two. And instead of two rows, we now have three. "
1076 | ]
1077 | },
1078 | {
1079 | "cell_type": "code",
1080 | "execution_count": 86,
1081 | "metadata": {
1082 | "scrolled": true
1083 | },
1084 | "outputs": [
1085 | {
1086 | "data": {
1087 | "text/plain": [
1088 | "array([[1, 4],\n",
1089 | " [2, 5],\n",
1090 | " [3, 6]])"
1091 | ]
1092 | },
1093 | "execution_count": 86,
1094 | "metadata": {},
1095 | "output_type": "execute_result"
1096 | }
1097 | ],
1098 | "source": [
1099 | "a.transpose()"
1100 | ]
1101 | },
1102 | {
1103 | "cell_type": "markdown",
1104 | "metadata": {},
1105 | "source": [
1106 | "# 7.0 Eigenvalues & Eigenvectors\n",
1107 | "\n",
1108 | "Let A be an `n x n` matrix. The number λ is an eigenvalue of `A` if there exists a non-zero vector `C` such that\n",
1109 | "\n",
1110 | "Av = λv\n",
1111 | "\n",
1112 | "In this case, vector `v` is called an eigenvector of `A` corresponding to λ. You can use numpy to calculate the eigenvalues and eigenvectors of a matrix: "
1113 | ]
1114 | },
1115 | {
1116 | "cell_type": "code",
1117 | "execution_count": 79,
1118 | "metadata": {
1119 | "scrolled": true
1120 | },
1121 | "outputs": [
1122 | {
1123 | "name": "stdout",
1124 | "output_type": "stream",
1125 | "text": [
1126 | "2.82842712475 -2.82842712475\n"
1127 | ]
1128 | }
1129 | ],
1130 | "source": [
1131 | "eigenvecs, eigvals = np.linalg.eigvals(matrix1)\n",
1132 | "print(eigenvecs, eigvals)"
1133 | ]
1134 | },
1135 | {
1136 | "cell_type": "markdown",
1137 | "metadata": {},
1138 | "source": [
1139 | "It's important to note that eigenvectors do not change direction in the transformation of the matrix.\n"
1140 | ]
1141 | },
1142 | {
1143 | "cell_type": "markdown",
1144 | "metadata": {},
1145 | "source": [
1146 | "# Challenge\n",
1147 | "\n",
1148 | "1. Given the matrix below, find the eigenvalues (name these variable `eig1` and `eig2`). For each eigenvalue find its eigenvector (call these variables `eigenvector1` and `eigenvector2`).\n",
1149 | "\n",
1150 | "``` \n",
1151 | " 1 4\n",
1152 | " 3 5\n",
1153 | "```\n",
1154 | "* Don't forget to create the matrix above.\n",
1155 | "\n",
1156 | "2. Consider the rotation matrix for two dimensions. (for example - we see that for zero degrees this matrix is just a 2-by-2 identity matrix.) Find the eigenvalues for a 45 degree rotation (call these variables `eig_rot1` and `eig_rot2`). For each eigenvalue find its eigenvalue (call these variables `eigenvector_rot1` and `eigenvector_rot2`)."
1157 | ]
1158 | },
1159 | {
1160 | "cell_type": "code",
1161 | "execution_count": null,
1162 | "metadata": {
1163 | "collapsed": true
1164 | },
1165 | "outputs": [],
1166 | "source": []
1167 | }
1168 | ],
1169 | "metadata": {
1170 | "kernelspec": {
1171 | "display_name": "Python 3",
1172 | "language": "python",
1173 | "name": "python3"
1174 | },
1175 | "language_info": {
1176 | "codemirror_mode": {
1177 | "name": "ipython",
1178 | "version": 3
1179 | },
1180 | "file_extension": ".py",
1181 | "mimetype": "text/x-python",
1182 | "name": "python",
1183 | "nbconvert_exporter": "python",
1184 | "pygments_lexer": "ipython3",
1185 | "version": "3.6.3"
1186 | }
1187 | },
1188 | "nbformat": 4,
1189 | "nbformat_minor": 2
1190 | }
1191 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Intro to Linear Algebra with Python
2 |
--------------------------------------------------------------------------------