Scientific Computing with NumPy - Python Data Science | TM Quest | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Scientific Computing with NumPy - Python Data Science

teacher avatar TM Quest, Technology and Mathematics Quest

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

72 Lessons (5h 21m)
    • 1. NumPy Introduction

      4:16
    • 2. Installing Anaconda

      1:21
    • 3. Markdown Cells

      3:53
    • 4. Code Cells

      4:14
    • 5. Importing NumPy

      5:23
    • 6. Working with Vectors Intro

      1:21
    • 7. Creating Vectors

      6:01
    • 8. Basic Operations

      5:41
    • 9. NumPy Datatypes

      5:52
    • 10. Slicing Vectors

      5:17
    • 11. Sorting Vectors

      3:41
    • 12. Copies vs. Views

      4:28
    • 13. Aggregate Functions

      5:01
    • 14. Exercise Set - Temperature Data

      0:59
    • 15. Universal Functions Intro

      0:46
    • 16. Universal Functions

      2:53
    • 17. Function Plotting

      7:13
    • 18. Bar and Scatter Plot

      6:56
    • 19. Exercise Set - Temperature Data II

      1:58
    • 20. Randomness and Statistics Intro

      1:31
    • 21. Generators and Random Integers

      5:29
    • 22. Random, Shuffle, and Choice

      5:04
    • 23. The Normal Distribution

      5:35
    • 24. Basic Statistics

      5:46
    • 25. Finding Unique Values

      3:26
    • 26. Exercise Set - Linear Regression

      1:16
    • 27. Matrices Intro

      1:01
    • 28. Making a Matrix

      5:44
    • 29. Attributes of a Matrix

      6:42
    • 30. Changing the Shape of a Vector

      6:50
    • 31. New Matrices and Specifying Axis

      5:44
    • 32. Boolean Vectors and Matrices

      7:15
    • 33. Exercise Set - Rain Data

      2:08
    • 34. Broadcasting and Indexing Intro

      1:13
    • 35. Basic Broadcasting

      5:00
    • 36. Broadcasting Rules

      7:12
    • 37. 2D Slicing

      4:50
    • 38. Advanced Indexing

      3:53
    • 39. Exercise Set - Monochrome Images

      1:34
    • 40. Basic Linear Algebra Intro

      0:50
    • 41. Basic Linear Algebra

      4:57
    • 42. Cross Product and Length

      7:28
    • 43. Matrix Operations

      7:24
    • 44. Solving Linear Systems I

      5:50
    • 45. Solving Linear Systems II

      4:47
    • 46. Exercise Set - Basic Linear Algebra

      2:15
    • 47. Understanding ndarrays Intro

      1:22
    • 48. Making Higher Dimensional Arrays

      5:47
    • 49. Slicing and Aggregate Functions

      4:51
    • 50. Colored Images

      7:16
    • 51. What are Strides?

      5:27
    • 52. Exercise Set - Color Images

      1:32
    • 53. Fourier Transforms Intro

      1:21
    • 54. Complex Numbers

      4:41
    • 55. Fourier Transforms I

      5:54
    • 56. Fourier Transforms II

      6:56
    • 57. Smoothing a Signal

      6:00
    • 58. 2D Fourier Transforms

      8:03
    • 59. Exercise Set - Fourier Transforms

      3:24
    • 60. Advanced Linear Algebra Intro

      1:49
    • 61. Eigenvalues and Eigenvectors

      7:11
    • 62. Types of Matrices

      9:13
    • 63. QR Decomposition

      7:27
    • 64. Partial Least Squares

      5:56
    • 65. Exercise Set - Advanced LinAlg

      1:24
    • 66. Saving and Loading Data Intro

      1:17
    • 67. Loading Data

      4:28
    • 68. Saving Data

      5:12
    • 69. Saving and Loading NumPy Arrays

      6:20
    • 70. Exercise Set - Boston Data

      2:42
    • 71. Neighboring Libraries Intro

      5:31
    • 72. Further Topics and Goodbye!

      1:45
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

28

Students

1

Project

About This Class

e7003d5b.png

Hi there!

We're a couple (Eirik and Stine) who love to create high-quality courses! In the past, Eirik has taught both Python and NumPy at the university level, while Stine has written learning material for a university course that has used NumPy. We both love NumPy and can't wait to teach you all about it!

What this course is all about:

In this course, we will teach you the ins and outs of the Python library NumPy. This library is incredibly powerful and is used for scientific computing, linear algebra, image processing, machine learning, and much more. If you are interested in one of these topics, or simply want to get started with data science in Python, then this is the course for you!

Topics we will cover:

We will cover a lot of different topics in this course. In order of appearance, they are:

  • Introduction to NumPy

  • Working with Vectors

  • Universal Functions and Plotting

  • Randomness and Statistics

  • Making and Modifying Matrices

  • Broadcasting and Advanced Indexing

  • Basic Linear Algebra

  • Understanding n-dimensional Arrays

  • Fourier Transforms

  • Advanced Linear Algebra

  • Saving and Loading Data

By completing our course, you will be comfortable with NumPy and have a solid foundation for learning data science in Python.

Don't forget to check out the exercises in this course. Link in the class project.

Meet Your Teacher

Teacher Profile Image

TM Quest

Technology and Mathematics Quest

Teacher

Hi there!

We're a couple who are passionate about teaching topics related to mathematics and informatics. Are you perhaps interested in data science or mathematics? If so, why don't you follow us?

Currently, we have published the following courses:

 

Mastering LaTeX: Academic Typesetting for Beginners Creating Figures in LaTeX Using TikZ Python 3.9 - What is New? Get Started with Higher-Order Functions in Python. Scientific Computing with NumPy - Python Data Science

Do you have a suggestion for us for a course? Don't hesitate to contact us :-)

See full profile

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. NumPy Introduction: Hi, and welcome to this course. My name is ironic and I'll be one of your instructors in this course. So first of all, what is NumPy? So NumPy is a Python library and it's an abbreviation for numerical Python. So if you go to NumPy as homepage, they give the following description. They said that NumPy is the fundamental package for scientific computing with Python. In addition to this, it's also the default library for linear algebra and numerical computing in Python. Finally, it's also one of the core libraries of the Python data science stack. So it's really common to do data science in Python. Then you typically work with a bunch of different libraries and NumPy is one of them. In fact, numpy is so essential in this stack. The stack is sometime called the NumPy stack. So this is what NumPy is. Next question is, why should you learn NumPy? And the first reason is that it's very compatible with other Python libraries. So it's used by a bunch of different libraries here I've just listed five of them. This is matplotlib, which is used for plotting, Pandas, which is used for data handling. And additionally, we have three more libraries, namely TensorFlow, scikit-learn, and PyTorch, which are all machine learning libraries that heavily uses NumPy. Additionally, numpy is relatively easy to use. It's not completely trivial to learn. Otherwise you probably wouldn't need as course, it is not a very difficult library to master. So Python is open source, meaning also that it is free to use. This is in stark contrast with MATLAB, Mathematica, and Maple that are all programs that do similar things to NumPy that are not free, that require a subscription. Numpy is also what I would call it mathematically mature at implements a lot of different things like random number generators, a lot of linear algebra routines, and we'll look at Fourier transforms and so much more, and we'll look at all of these things throughout. Finally, it's also very performant. So NumPy is really fast as a core of NumPy is really well optimized C code. So here we get the best of both worlds as we have fast code, but also in high level syntax, very similar to the Python syntax you're probably used to. So here I am in a Jupiter notebook. Stinger will tell you all about Jupiter Notebooks soon. But instead of just telling you that NumPy is fast, I really wanted to just show it. You don't need to worry about the details here. I just really want to show you that NumPy is incredibly fast. So as import numpy as np. So what I do here is to make a list of the first 10 million numbers. And when I multiply each element in the list by the number three by using what's called a list comprehension in Python. So when I run this cell, you can see now this took 2.8 seconds to run this with usual Python. Now let's do it numpy through here and make what's called a vector with the first 10 million numbers and then I multiplied them by three. So notice first of all, the syntax is actually a lot more simple here in NumPy, learners in Python, that's because NumPy is optimized for doing linear algebra. When I run this, you can see here that the running time is almost a tenth of the running time in Python. So NumPy is incredibly fast. So before we begin, I just really wanted to show you an outline of the course that we've made. So here's a diagram and it starts all the way at the top here with the introduction. Next, vectors is introduced. Notice the color indications there. I'll be teaching the ones with green, as we can see here, while syllable, but teaching the blue ones. So I'll be teaching you about vectors then Steven, we'll talk about plotting. I will talk about randomness, random numbers and statistics, sustainable talk about matrices and how they work in Numpy, I will talk about broadcasting and advanced indexing stenotic tissue about basic linear algebra. After linear algebra, you have ND arrays, which is the basic data structure that NumPy uses. Also notice that you have a few optional sections, namely 9 and 10, which are Fourier transforms and advanced linear algebra. I highly recommended to, of course go through these topics, but I just wanted to let you know that these are optional after that signal go through a bit about saving and loading files into NumPy and also saving Numpy arrays so that you can use them later in other programs. Finally, we'll give you some further resources, talk a bit about neighboring libraries, and then say goodbye. Finally, I just wanted to mention supplementary materials throughout the course. We'll give you a lot of exercise sets at a build on the topics we've just lectured here on Skillshare. If you go to the class project and you can find all of the exercises in a single zip file. So I just strongly encourage you to go there right now and just don't know this and have it ready. I hope you are really eager to jump into NumPy and we'll see you in the next video. 2. Installing Anaconda: Hi and welcome. In this video, we are going to go through how to install Anaconda on your computer. So here I am at the Anaconda webpage, which is anaconda.com. And I'm going to navigate to the Anaconda installer. So first of all, I go to products and individual addition. So here you see that you have the Download button. So let us press this one and we scroll down all the way to the end of the page. So here you can choose your installer. For me, it's Windows 64, but you also have like Mac and Linux. Just choose the one that fits your computer and go through the entire installation. After you have installed Anaconda, you can go to Anaconda Navigator. So either you can search for Anaconda Navigator on your computer or hopefully you will have a desktop icon named on the navigator. So hey, you can see several different programs. For instance, you're put the notebook, which is the one we are going to use. But you also have other program like spider and so on. So in the next video we are going to go through how you've been a notebook works. So see you again then. 3. Markdown Cells: In the last video, we left off in the Anaconda Navigator. So first of all, we go to your notebooks and press Launch. So Jupyter Notebooks should be now opened in your web browser. So here you see your file directory. So this is on your computer. It's not on the webpage even though it's opened in your web browser. So to create a new Jupyter Notebook, you got Pear press knew Python 3 Notebook. And now it opens on you, your notebook for you. So here you see the title, which is Untitled 2. So let me replace the type bool and let me call it my first notebook. And go down here and press rename any of the nose pick. There are two kinds of cells. We have markdown cells and we have code cells. So a code cell always have this thing here on the left to make this cell here a markdown cell, we can go off pare down there and press Markdown. So the difference between a markdown cell and a code cell is that a markdown cell is fair. You explain your code and write text or some mathematics. And a cool cell is where your Python code comes. So this is now markdown cells since it doesn't have this IM and then square brackets. So let's write some text. So now I have written some text here, and what they can do now is to run this cell. So now we can see that the text got formatted and we jumped down to an other code cell, selected me, switch to another mark themselves and go through some markdown syntax. So first of all, we can make headers in our Jupyter Notebooks. We may cutters with the Oct4 symbol, or commonly known as the hashtag symbol. So here you have a header. And if you have one, it's a big header. If you have two, it's a bit smaller header. And if you have free, it's an even smaller header, and so on. So let me also run the cell here. And now you see that you have a big header, a smaller Hadar, and an even smaller header. So let me double press here and you see that we go into R Markdown again. And now I can edit as I want inside here. So let me write some mathematics. So you can write later code in your markdown cell. So let me write here is some math. And as you always do in Late Tech, we have $2 signs. So inside the dollar signs now I can write later code. So for instance, if I want cosine, I can write backslash cosine of x. And if I now run the cell, you see a deaf, I have cosine here. I can also write things like sums, like this and compile. And now we see that we have the sum symbol here. So if I have $2 signs at the beginning and the end, so if I now run this cell, I end up with the sun on a separate line. So this was everything I wanted to say about the markdown cells. So you can write math and they use latex. If you are familiar with latex. 4. Code Cells: So let us now move to the code cells. So here we have a code cell, which you can see by this EN and square brackets here. You can also see that appear it's on code. So let's try with a small Python program. So let me make a list in Python, which is just going to be 13401. Here we have a list and to run now would do the exact same thing. We go up here and press Run. So now you see that this fin here changed a bit and we have the number one here. So now this cell has been run. So if I'm now in a new code cell, right, print, and then my list, then I can access my list in the new cell here. So let me try to run this one. And now we see that we have the number two. And then my list here which is printed below. So let us now redefine my list by using slicing. So I write my list. And I don't want to take the slice from the 0 index to, but not including the third index. And the notation for this is semicolon, which means take everything before and then free. So now the endpoint here is not included. So let me run this cell and you see the number three here again. And let me try to run this cell again here, the second cell. So after I run this cell, you see that now only the first three numbers are printed out and not the entire list. And the recent four, this is the run order. So if you see the numbers here, we have one which is the first cell we run. And then we've run this 11 time, which was the second time, rebrand one cell. And this is the first cell rerun, and this is the fourth one. So these numbers is kind of the run order of the program. So since we've run this cell before here, where we redefined my list, we end up with mylist being something different than it was originally. So this might cause a bit of problems that the running order and the order which the code is is not necessarily the same. So if you want to run the entire document and everything in order as it is written, what you can do is go into kernel and then press restart and run all. And this will restart the numbering and just run everything in order. So let's press on. And it will have a warning because you're overwriting a lot of things. But let us just press restart and run all cells. And now you see that everything is run a pair as well. And we have the order again, 1, 2, and free. And we have the entire list here. So what you might have noticed is that I do not always go up here to run myself. And recent for this is that there are several shortcuts in Jupiter notebook to find a list of all the shortcuts you can go to Help. And then Keyboard Shortcuts. And now you get all the shortcuts here. And there are several of them. So what they usually do is that when I want to run the cell, I press Shift Enter to run the cell and make a cell below. And this is exactly the same as pressing run this. You also have similar sort of commands like Control Enter, which runs the selected cell and so on. So when you are really comfortable with Jupiter notebook, you should try to learn some of these command to make coding faster. For now, I will start only using Shift Enter when I want to run myself. So let me go down here and close the keyboard shortcuts. 5. Importing NumPy: Finally, I wanted to talk about the main theme of this course, which is NumPy. So let me just write and hetero there. So I have a markdown cell and let me write to NumPy and then Shift Enter to run the cell. And what do we want to do now is to import the NumPy package. So you do this with the import keyword, the NumPy. And usually when you import not pi, you imported with the alias np. So I will do this as well. So this means that instead of referring to the NumPy package as NumPy, which is a bit long. You can instead referred to the package just quit and p. So let me import the package by running this cell. And now I can use NumPy. So the first thing I will do is to make a list. And let the list consists of 1, 10, 100, and 1000. And let me run this solid like this. And what I want to do now is to make my first NumPy array. So this is just to make sure that everything is working. So to make an array, we write np for a NumPy. Remember that we said that instead of writing num pi, we can now write np array. And what I want to do is to take my list and make it into a NumPy array. So I can write my second list and now run the code again. So that worked perfectly. So let me now print out the array like this. And now you see that you have an array. I will go more into what a NumPy array actually is and how to create them. But for now the important thing is that we don't get any errors. So what we can also do just to test a bit about my array is to take the area and multiply it by two, and then run the cell. And now you see that the oft Patel is just all these numbers multiplied by two and you have this area in front of it. So an important thing that we are going to use a lot in your pet or notebook is that whenever you are returning things like here, it will take the last thing you returned and actually printed out below. So instead of writing a print statement, you can just write my array as the final thing we're going to go through how to get help. So often, when you're doing programming, you'll have some function or something and you're kind of do not remember what it does or are unsure of what it does, then it's very important to manage to actually find the information you are looking for. So let me make a markdown cell here with the header help. To symbolize that we need to know how to find help. So let's say that we have the function np dot arrange and we do not know what this function does. So I will go for this function, but for now, we do not know what it does. So let me take in the number four and just see that it does something. And what it gives us up to East that no par with the numbers 0, 1, 2, and 3. So let's say that I want to know more about this function np.arange. What I can do is to write help and then the name of the function which is np dot arrange and run this cell. And here I get a lot of information about this specific functions. So I get that it's returns evenly spaced values within a given interval and that it takes in a start and stop and stuff. So you have a lot of information here about the function. So I'm not going to go through all the information, but you also have some example of usage here. Another way to do this in your notebook is to write np dot arrange and then just a question mark instead of entire health thing. So let me run the cell here. And now you see that docstring or the information about the function comes up in a separate window here, and it's the same information from before. So this was the second way to do this. But my favorite way to do this is if I have a function is to just press Shift plus Tab. So now I have the doc string here with all the information about the function. So this is probably the quickest way to do it in the Jupiter notebook to just like, Oh yeah, here is to start it and the second argument is to stop and the third one is the type and so on. The final find a way to get help is to go into NumPy and find the documentation for NumPy. So here I am not a NumPy webpage which is numpy.org. And I can go appear press documentation. And here you have a lot of different tutorials. So in the documentation, you can find like the Quickstart tutorial and the setup and so on. And you have a lot of information available on NumPy page. So this was everything I wanted to go through in this video. So see you again in the next video. 6. Working with Vectors Intro: Hi, So in this section we're really getting started with NumPy. We're going to work with vectors. So the key thing in this section is religious getting comfortable with vectors in NumPy. So what does this mean? This means that we should be able to, first of all, create vectors in NumPy. Secondly, do basic vector operations between different vectors. Thirdly, we should be able to understand NumPy is different datatypes. So NumPy has its own type of data types that you should be somewhat familiar with. Additionally, you should be able to access values in a NumPy array and also set values and perform slicing. Slicing is incredibly important in NumPy is a gallery. Just get comfortable with it straight away. Finally, we will also understand the differences between what's called copies and what's called the views. So the 3 second explanation is that copies is when NumPy copies information while views or when NumPy doesn't copy the information. We'll talk a lot more about this in the actual video. So at the end of each section we have exercised sets and the exercise sets for this section, we'll actually work with temperature data and ideas that you get to test out what you've learned in this section in the exercise sets, you'll be slicing and accessing and creating and so on and so on all to reinforce what you've learned in the lectures. So this is what we'll cover. I hope this looks interesting and I'll see you in the next video. 7. Creating Vectors: Hi. So in this video, we're going to talk about creating vectors in NumPy and extracting value from them. So I'm here in a new Jupiter, no quick cheat. I'm just going to start by essentially creating a NumPy array. So let's call this basic creation. And what we'll use is what's called numpy dot array like this. So first of all, of course, we need to import NumPy as np. As soon as I showed you previously, this works fine. And now I want to take a basic Python lists and converted into a NumPy array. So let's write our list of numbers. This is just a made up lists of numbers in Python. Let's say this is 4, 8, 15, 16, 2342. The way to convert this into a NumPy array is to use the command np.array. And let command just takes in our list like this. Let's assign this to new variable. Let's call it just array for now. And here we have the array and let's print it out. And so far it seems very, very similar to just a Python list. But you should convince yourself that it's not anymore a list by simply using the type function. This is just a Python function that lets you check the type of an object. And you can see here that the class is NumPy dots AND IRA. What we've effectively done is to take a Python list and converted into a NumPy array. Before going further, I just want to explain some terminology and will interchangeably use towards a vector and airy and NumPy area and ND array. The first couple of videos is because in the beginning of the course, create one-dimensional arrays and in this case are also called vectors. Later on, all create two-dimensional structures which are typically called matrices. Null tried to be a bit more careful with saying matrix or vector and so on. And the area can both referred to a two-dimensional, one-dimensional, or as the name suggests, an n-dimensional area of vectors, since we're just doing one-dimensional. So for now, I'll just probably use vector the most. Before doing NumPy stuff, I just want to convince you that we can extract values and set values in NumPy arrays in much the same way as with Python lists. So let's first extract from a NumPy array. So we can, for instance, take the first element and set that to be the array of 0. Let's do precisely the same as for lists. Lists are numbered from index 0, 1, 2, 3, 4, and 5. In this case, we can take the name of her numpy vector and simply just access the first element, meaning the one that has index 0. And if I now print out first element, and you can see that I indeed get the value four. And we can do the same for, say, the last element. This is array of five. Let's try this out. And then you can see that I get 42. You should note that for NumPy vectors, you can also use the negative indexing that is very popular in Python. So if I want to access the last element, but I don't really know how many elements are in the array. I can simply write minus one. This does the exactly same thing. If I want the second to last one, I can do minus two and so on. So kinda side-by-side with extracting values is setting new values. So I can prisons just reach into my array, into the first element, which is at index 0, and then just set this to be equal to 100. Now, if I print the array again, we can see that indeed it has changed and now we have 100 here instead of four. Notice it's permanently changed. Similarly, I can just go in, say, to the last value. Let's put minus one here and set that to be equal to 15. If I run this, you can see that the 50 here has changed and also the 100 is still applied. So this permanently changes my array. The summer of these two cells here is that when it comes to extracting values and setting values, it works exactly the same for arrays and the dots for the typical Python lists. Before we end, I want to show you one more new function. So here, if I want to make a numpy vector, then I can do the np.array. This is convenient if I already have a list present like here. Say I want to make a NumPy array with the first 50 numbers and actually typing all of them are just not a good idea. There is a special function in NumPy for doing this. This is the np dot a range function. So I think this dance for array range and it's very similar to a range function in classical Python. So let's make a variable called sequential numbers. And I'll use the np dot arrange function or a range. And the first argument here, I'll just do 17, and then for now nothing more. So if we print out sequential numbers, I made a small spelling mistake, so let me just copy this and paste it here. Yeah, and this is all the numbers starting from 0 all the way up until 17. But you can see not including 17. If I pass in two numbers, say from 17 to 23 and I get the numbers from 17, which is included all the way up to 23, but that one is not included. So this works pretty much exactly the same as for the classical range function in Python. After this here is now a vector or an array, not a Python list. Finally, you can pass a third argument indicating the stack. So for instance, I could pass this to be equal to two. Then I get every second number and actual difference between the arrange function here and the classical range function in Python is a dysfunction, can take in decimal numbers for steps. So I can say 2.5, then I get 17.52219. If I remember correctly, this is not possible in the usual range function in Python, this is really, really convenient, as we'll see later when we do plotting. This, is it for this video? In the next video, we're going to look at basic operations between numpy vectors and how this is really, really efficient. Thanks, and I'll see you then. 8. Basic Operations: Hey guys and welcome back. In this video, I'm going to talk about the basic operations in NumPy. So here we have an empty cells. Images make two vectors. The first one I'll make with array range function will take the numbers between 15 excluding five. And the second one, I can actually use the area function. So this resonance between two functions we looked at last time. Here I'll just manually pass in a list. Let's say the numbers are 6832, something like this. So the first operation we can do is addition. So let's say I make a new variable called summation like this. And then just, I'll do first plus second. Let's print this out and see what has happened. So I'll make a print statement. Let me just call it sum. And the first argument sort of just prints out pretty nicely summation. And here you can see the sum and this should be essentially what you should suspect. So just to clarify, this one here is an array with the numbers 1234. So we first have 1 plus 6 making seven, we have 2 plus 8, making 10, and so on. And this works perfectly just because they're both of the same length. If I tried to make this say slightly longer and run it, then I'll get a value error saying essentially that these operands could not be broadcast together. I'll talk a lot more about broadcasting later and show that in some cases, this could actually work. But in this, so for the beginning, you should just make sure that if you add two vectors, they should be of the same length. Let's go back to both being of length 4 is here, really should be contrasted with typical Python lists. Let me just quickly do this. Let's just make them really, really short. So this is 1, 2, and the second one is 34. And if I print out list1 plus L2, then I get this. The default meaning of a plus sign between Python lists is just concatenation. This mean that I'll take the second list and just add it at the end of the first one, as you can see here, when it comes to vector manipulation and linear algebra and all these kind of stuff is very solemn. What you want, it might be what you want if these represents a songs on a playlist, pretty thinks we're working towards having plus meaning lists. Concatenation is not a good idea at all. We definitely want to be working with the NumPy stuff. Let me just delete this. This was just for reference, such checkout. The other operations we have, we of course have subtraction. First minus second. Let's print is also out. So this is the subtraction, as you should expect to take one minus six, that gives you minus five, and so on. Then we have multiplication. Just the first times the second. So let's print that out. So here you can see the multiplication. So again, it's one times 662 times eight is 16 and so on. And we have division. And this also works as expected, but we could say a few more things about this. First of all, you can see here that NumPy is kind of under the hood, converted these into floating numbers. We'll talk a lot more about this in a future video. Secondly, you might not really want all of these decimals here. So what you could try to do is to remember, oh, but Python has a rounding functions. Great. Let's just do that. Round this easy-peasy, and it does not really work. To be honest, the thing here is that the rounding function doesn't work on NumPy arrays, a for-loop and for each iterate in a for loop round the number. This is a bad idea for two reasons. First of all, we don't want to write for loops that much when doing NumPy want to find other solutions and this will also be talking more about later. Secondly, there should just be a function that does this and it of course S and is np dot a round. Here's kinda funny. I guess it stands for array rounding, but then it just becomes around. So I always say np around. That's just how it is. And this works, great. The default here is rounded to 0 digits, which is probably a bit extreme. This now becomes 0, 2. As usual, specify a second argument, same number of decimals you want. So let's say two is fine. The final one, I just want to show that this can be done this exponentiation. So first, then just use the usual exponent symbol in Python with the second. Let's print this out. And here you can see the exponentiation is what's happening. Hearing baggage just scroll slightly up, is that one is taken to the sixth power, that's 12, is taken to the eighth power, does 256, and so on. This is strictly speaking possible, but I very seldom see that's being used. These are all the basic operations in NumPy. You don't need to memorize them at all because we'll be using them all over the place. So far we have a few operations. We have two ways of making arrays by specifying a range, say from one to five or an array. We also have np around function for rounding. So we're going to be doing is to gradually build up a repertoire of two things. One, a little methods in NumPy does really useful and to a bedroom fundamental understanding of how NumPy works. In the next video, we're going to go slightly into the second part by looking at which datatypes NumPy and holder represented. So thanks and I'll see you in the next lecture. 9. NumPy Datatypes: In this video we're going to talk about NumPy datatypes. So this isn't one of those more theoretical videos that is not really that hard. It's just about getting a very brief understanding of the native datatypes that comes with NumPy. So the question we are looking at is, what datatypes thus numpy have? This is a question. So let's just try it out. Let's make a new array. Can again just call it array. Let me just make it with the same numbers we had in the first video. It doesn't really matter. Numbers are not important. Let's run this. Now let's check out an attribute of area, namely array, then dot dtype. This is short for datatype. So here you can see that the datatype is int 32. So this is not just like the datatypes in Python where you have ints or floats and booleans and so on. Here do a more refined. Now I'm at NumPy documentation page does dinner showed you? And here we have the datatypes. So you can see here that NumPy supports a much greater variety of numerical types than what you shall Python does. So below here is the primitive data types, but they are platform dependent source we'll mostly focus on is the platform independent ones. So for instance, it has a numpy int 8, and this is an integer from minus 128 to plus 127. So you probably recognize eight bits in size or one byte. So in 16 is two bytes of integer information into 32 is four bytes, and so on up to 64. So hopefully this monster here is more than sufficient for what you're doing. It also has unsigned integers is essentially gives you just the positive ones. Here you can make more clearly see that it's from 0 to 255. It's essentially 256 or two to the eighth possibilities. So this again represents one byte or two bytes or three bytes, four bytes, and so on. We can also notice there is a floating point version or just float 32 and hundreds of float 64 can see here that this float 64 matches the built-in Python float. There is also a complex 64. This has to do with complex numbers for those, you know, where you store to 32-bits floats of the real and imaginary part of that complex number. We're not going to go into complex numbers for quite a while. So we don't need to understand this at all. And the most important ones are segregated into integers, unsigned integers, floating points and complex. And also variability in terms of how much storage is provided, in terms of bytes are back in our documents. And if you look at this creation here of area and never really specified the data structure of the array to the number. We just try to guess what I want. I drew only specified really integers, but if I would say make this 4.5 and run it, and it will just assume that yeah, you probably want floats. So if we want to take more control, we can also specify the data type. So how do we do that? Let's again make our array np.array. Here I pass in my list of numbers. Just copy it from above. If you want me, just write it as a second argument. You can pass in a datatype. So dtype just set this to be equal to np dot. And now we can access all data types as we looked at. So we sorted by default I will get an integer 32, but I don't really need that much storage, which would probably be sufficient with the eight here. That will allow me numbers all the way up to 120 sevens. Let me just do that. This and now I can look at array dot dtype. You can see that it has been manually set to integer eight. If you're a beginner to NumPy, then this is really need to know. However, you don't really want to set your own datatypes unless you know what you're doing. Say for instance that I have this array now upset the datatype to be integer 8. This means that it can store numbers up to 127. So if I now take my array and just set it equal to my array plus 100, this will just add 100 to all entries. Here I have 104, one hundred eighty one hundred fifty One. 116123 seems good. And here I have 140 to the problem now, if I print my array is here, Here just overflows. So instead of having 142, I get minus 114 because it's a bit loops around. This can create subtle bugs unless you have very good control of what you're doing. So I would actually suggest not to set your own datatypes which is observed. This is something one can do, still, really nice to know because later on if you want to optimize a certain algorithm, then you can really squeeze out a bit more performance by specifying your own datatypes. So finally, in this video I want to talk about two more attributes that's kind of cute. So one of them is the size of a vector. So to access the size of a vector, you can just do array and then the attribute size in here I get six. So you might be wondering, well, doesn't length work a typical length function in Python? And here the answer is yes, it does actually work, but it won't work for the higher-order areas that we'll talk about later. We shouldn't really use length that much when we're doing Numpy, you'll be a lot more preferable to just use the dot size attributes, and we have this in a print statement. Secondly, you can also access the number of bytes that is used. This is the area, dots and bytes. Number of bytes is six, because each of the numbers here are essentially eight bits, which is one byte, one byte, two byte, and so on, all the way up to six bytes. So this, as you probably understand, changes depending on the datatype. So if I set this to an integer 32 and run this cell, then here the array size doesn't change at all. It's still six elements, but the number of bytes does change because each element here in our represents four bytes sugared, 4, 8, 12, 16, 20, 24 bytes. So these two attributes are just very convenient if want to check out a vector r2 to see how big it is and you want to see how much storage it contains. In the next two videos, we'll talk more about practical things, namely slicing and sorting. So see you then. 10. Slicing Vectors: Hi everyone. So in this video we're going to talk about slicing. Slicing is something you might have done already in usual Python with lists. This is also possible with NumPy arrays. If you know about slicing from before from Python, then you can just skip this video or just tag along and see what we do. So let's start by making an array. So this will just be the same array we have previously used. Let me just manually pass in a list here. What slicing is, is that instead of extracting a single element from an array, we can extract multiple elements. So what I can, for instance, do is to take everything after a specific index. So to do that I will make my array. And then instead of like taking in the number three, which is definitely possible, I can take in everything after the index 3 by writing three colon. So now we'll get everything after the index three, index 3, I have 16, then I also get 23 and 40 to sort the syntax so far is that I specify one number and then colon, and I'll get everything after that number. So for instance, if I do too this, if I do 1, I get this. If I do 0, I get everything. So if I don't specify a number at all here under default will also be 0. So this will just give me the same. I could actually specify an index that's way too big. So I could say everything from the 18 tooth number and so on. And of course, this will not give me anything, but I'll just get an empty array back. This is a bit different from just selecting things. Whereas if I tried to select something at the H2B index, I will, as you can see here, get an index error. But if I slice at the wrong point, I'll just get an empty area back. So let me return this to three-quarter can also do is take everything before an index. So the way to do this is to take my array. And now instead of specifying a number and then colon and I'll specify colon than a number. So this takes everything up until the fourth index. So if I print this, I'll get 4, 8, 15, 16. Notice a 16 is at the third index. So this takes everything up until, but not the fourth index. So I can again play with this. So up to two gives me the 0th first index and so on. Again, if I specify a number that's just way too big, say AD2, that'll just take everything off to AD2 that it can find an index which is definitely all of these. So again, let me just return this to say for first we took something before an index, now we took it after an index. You can also do in-between. In this SAS, I think in this case I can, for instance, due to colon, this gives me everything from the second index and onward, but I want to also stop it at five. This means that I'll get to things at index 2, 3, 4, but again, not at five. So it's always exclusive at the last one, this gives me 15, 16, and 23. For me, it's a really good idea to just play around with this a bit. So if I do, for instance six, I'll get one more here. That gives me the last one. Doing higher than that, like 10 doesn't really make a difference at this point. I could also move this one upwards, say to one, or I can just remove it completely to 0. So let me go back to the one we had between 251 thing you can note is that you can also use negative indices. So let me write that. So let me take everything starting from the second index all the way to the minus second index. If you see here, this will give us 15 and 16 will start at 15 because that's the second index and it will get to 16. That's the third one button here. 23 is the minus second index. Remember get minus1, minus2, and it's always exclusive at the last one. So this here, the 23 one will not be included in my slice. So a very common way to now write, say, everything except the last one is just, yeah, I want to start from the beginning and I want to go all the way up until the final one. From a few videos back, we saw that array range function. And that function should take in a third argument indicating like the step or how much you want to jump at each point. You can do the same here for slicing. So for instance here I want to go from the second to the fifth one. Then I just specify another colon and I want to do jumps of two. Now, we'll just get 15. I'll jump over 16, and I get 23. Combining these remarks about jumping and negative indices, you can do some pretty nifty things. Let's reverse an array. Let's see how we can do this. So I make a variable covers array. I have my area here, but world just do is to say, I want to start from the beginning. I want to end at everything. Refer, just have destiny. I mean, I've just made a copy of my array because this goes from the beginning to the end. But if I do another colon, then I can specify a step and the step is minus1. So I do a negative step, just means that I take my whole array, but I'll do it in a negative order. And you can see here that it's reversed for now. This is what I want you to know about slicing when we deal with matrices later in the course. So two-dimensional structures, then we'll kinda revisit this whole slicing thing and see that it still works in that general setting. And thanks, I'll see you again in next video. 11. Sorting Vectors: Hi and welcome back. So in this video, I want to talk about sorting, and this will be a really quick video. So her essentially two ways to sort things in NumPy. So I've already made an array here, which is essentially the one we've been using previously, except that I've shuffled the elements a bit and repeated 15 twice, so there is not sorted. So there are two ways to sort things in NumPy. And I think it's actually a bit important to grasp the difference between these two methods. So the first one, let me just write it as a comment. This is to take an array and unused the method sort on it. This is a method for in-place sorting. That means I want to apply it to my array. It will be sorted in place, so will not return a new array that is sorted or simply modify my original array as is so loose the original information. This might be what you want or not depending on the context. So to do that, it's pretty simple. You just call Arrays.sort and that's it. So a common mistake in the beginning is to think that, Oh, I should probably sorted, that's fine too. Now it should return it in some way, call it like sorted array, something like this. So this is not what you should do, and it will be clear if I print this. Here, we can see that it's not. The reason for this is that the sort method modifies in places where it doesn't return anything and not returning anything in Python is the same as returning non-value to this will just be assigned none. It's kind of a general design principle in Python that if a method modifies the original array, then it will not return anything. So you don't need to do any of that. And just remove that. Now the original array is sorted, we can just print. You can see now that the original array has been sorted. Soldier is also a second way for doing the second way. Let me just copy this one because again, the original area has been modified and I want to illustrate this on a non-sorted array. So here we have it again. Now the areas again not sorted. And the second way to sort something is to use the np dot sort function. This is a function for returning sorted arrays. This was not sort in place, so it doesn't modify the original area and it creates a new area that is sorted. So to release, we did what was wrong previously and just do sorted array and set this to np dot sort array. Now if you print sorted array, here, you can see that it's also sorted. So let me indicate here that this is the sorted array. But I can also now print out the original one like this. And you can see now that the original one has not been changed. So this is not sorted, but we have a sorted array as well. So it really depends on what you want. If you want to sort in place, then use the sort method. If you want to sort not in place, but return a new array that is sorted and you can use np dot sort. A final interesting tidbit is that you can actually specify the specific sorting method here as an optional arguments, what you can do some specified kind. I think that NumPy accepts among four or five of the common sorting methods. So what you could do, for instance, as Heapsort like this, you can't really tell the difference, but there is a difference in speed in these methods. I don't want to go into this at all really here because this is more of a special tip bit preferred know about sorting methods, then you can specify your own here. So it's pretty convenient if you're a beginner, then I would just recommend to do the default one. Naming, don't specify anything and I think the default one is quicksort. But if you want to really squeeze out at extra performance and this can be really useful. So this is all I wanted to say about sorting in NumPy. It's pretty straightforward, but you just need to keep track of what Arrays.sort or np.zeros. What is really the difference here? Thanks, and I'll see you in the next lecture. 12. Copies vs. Views: Hi. In this video I'm going to talk about copies and views and what I are in Numpy, I think this is best explained by looking at a concrete example. Let's recap the example of reversing an array. So let's make our trusted array just going to use the np array method like this. And recall, we could reverse the array by using the slicing syntax like this. Let me just call this reverse Eric. So far this is fine. I can also just print this out so that you can see it and it's been reversed. Now the interesting thing is what happens if I try to modify the reverse? Let's say that I take the element that the 0th position and set this equal to 1000, then I can print out the modified version and have it here. But you can also now see that if I look at the original, let me print out as well. Something kind of strange has happened if you're not used to this already, original has also been changed. You can see here that at the original we have 1000 here at the last entry, which corresponds to reverse areas entry at position 03. Important thing is that this has also changed. So we would say that doing a slicing here to reverse the array is creating a view. This is a terminology that NumPy uses. Modifications on the slice also affects the original array. The reason for NumPy doing this is that it's really, really efficient computationally. So when you're creating a slice, you're essentially just viewing the information in a different way and then modifications to the new one also affects the previous one. So this is what we mean when we say that slicing creative use a NumPy array is also copies, say again that I have an array. And let's say that this time it has minus four here. And otherwise the same usual numbers I've used, 1516, 23, 42. Then there is a function called ABS, which is an abbreviation for absolute value, essentially turning all the negative numbers positive and call this positive array. This is np dot abs and pass in the array. And now, if I look at positive array, you can see that it's become positive. Let me just make the headline here. Make a positive note. Could do the same thing here where we can start to modify it so we can take our positive array and at 0, just assign it the value 1000 as before. And now we can again print the modified one from we get from making the elements positive. And we can print the original one. But now something different has happened. The original one has not been changed. You can see in a modified version of the absolute value one has changed, but the original one has not changed. So this is different behavior from slicing and slicing in the modification affected original one because there was a view. But for the absolute value function, it does not affect the original one because this is a copy. Is always a good idea if you're dealing with a NumPy construct to check whether it makes a copy or a view. If it makes a copy and you can safely modify the new one without it affecting the previous one. However, if it creates a view like slicing does, then you should only modify the new one if you want the original want to be modified as well. So in a much later video, we'll talk about some of the internal structures and NumPy in the strides and see actually that it makes sense that slicing will return a view while the absolute value will return a copy. For now, just good to keep in mind that some methods, return copies are other methods or constructs like slicing returns abuse. In the next video we'll talk about aggregate functions like summing and taking averages and so on. How we can do this very efficiently and smoothly in NumPy. So thanks, and I'll see you in the next lecture. 13. Aggregate Functions: Hi and welcome back. In this video, I want to talk about aggregate functions. So aggregate function is a function applied to an array that essentially aggregates the numbers, are, combines them to create a single number. To motivate this, let's say we have an array. It's the same area I've used previously. Now say we want to take the sum. So just a side note in Python, you can use a DIR function, check out an object. Let me do that. Let me also just print this. You can see all the methods that the object has required a lot of them. And we'll go through a lot of the ones that are down here during the course. Additionally, if you know about object-oriented programming in Python, then you will know that you can use a for-loop on an object and iterate through it if it has the iterator method and it does so areas are iterable objects. That means that we can use for loops on them. So let me just comment this out to get some space. And now we can write a for loop. Let's initiate a sum to be equal to 0. This is not good because some means something specific in Python. Let's just call this some of array. Let's add it to be equal to 0. And then for each number in my array, this should work fine. I'll take the sum of everything I made and add to it the number. And finally I can print out the sum of the array and it becomes 108. And this is perfectly valid, is just not very optimal. In NumPy, we prefer to write as few FOR loops as possible is much preferred to use the built-in NumPy methods and using explicit for loops. This is mainly because it's shorter, but also because they're a lot more optimized than the usual for loops in Python. So instead of doing all of this, Let's find the sum. Again. We can make some kind of parable for 80 some of the array. And we can use the NumPy function, just called sum takes in our array and this is everything we need to do. So again, let's just print it out. We again get 108 and this is a lot shorter. Let me just make this a bit more clear. And there's a bunch of other methods like this. So notice that this is an aggregate function in the sense that it takes in an array and an aggregates or combines number to make a single number, namely the sum. We can do this for a lot of functions. Tom just mentioned a few of them. One very common one is the mean, which is also called the average. So let's again do exactly the same. This is np dot Min. So this gives us the average. And you can see here that the average is 18. Since the sum function only involves placing integers, will give out an integer like here at the mean, essentially needs to divide by the length of the array. So this will automatically convert it into a floating point number. It's not really that important, it's just nice to keep in mind. We can also take the product of an array. And here it's promptly as an abbreviation for product, and it works exactly the same way, product. So you can see here quite clear that if you know one I read function and you kind of know how to use all of them. It's just a question of knowing that they exist. So just want to show you two more. This is finding the maximum and the minimum in an array, and this is me, just do it directly. So here we have the max1. And this is given by np dot max of an array. So you can see that the maximum number in this thing is 42, it seems right? Then we also have np dot Min gives us the minimum, which in this case is poor. Additionally to knowing what the max and Min values are, usually very important to know the index where it takes place. So this is the argmax and also the arg Min function. And they weren't more or less exactly the same way. Here is the argmax. And this is the argument. So you can see that the arg max is five. This is because if we scroll up a bit and 42, which is the biggest number, has index five and the arg Min, we can see here is 0 as because the minimum number is for an in-class position 0. In the next lecture, we'll work with a bigger exercise regarding temperature data. In that case, the maximum might indicate the highest temperature, minimum might indicate the lowest one, but argmax and arguments might indicate said a day or month or year where this takes place depending on how your data is to arg max and Min is usually very important. So this is what I wanted to say about aggregate functions in NumPy, they make your code really short and really slick and it's really easy to use. So I really hope you like them and I will see you again in the next video. 14. Exercise Set - Temperature Data: Hi, so now it's time to look at the first exercise set. So in the first exercise that we're going to look at temperature data from New York. So this is just to show you how it looks. So here's Jupiter notebook, and here you can see as Silva says, don't modify this, only run it. So of course is you just run the South. This gives you the data here called record low list. This is a list of record low temperatures. And then you should just follow along with the guided exercises here is it's pretty self-explanatory. Then Exercise 1, you should import numpy here. Exercise 2, you should convert the list you're given above to a NumPy array. In exercise 3, you should convert the data from Fahrenheit to Celsius using the formula here in exercise 4, you're asked to extract some values. In exercise 5, you should extract more values. Exercise 6 is about sorting. Exercise seven is about finding maximum and minimum values. Exercise 8 is about using arg, max and argument to determine specific months. Exercise 9 is about calculating means. And finally, exercise ten is a challenge. 15. Universal Functions Intro: Hi, and welcome to this video which is all about universal functions and plotting. So the theme of this section is to use a combination of NumPy and Matplotlib to plot functions and to make bar plots and so on. The things we are going to go through is how to use functions like cosine, sine and the exponential. We're going to learn how to use pi and e. We of course are going to plot functions like to cosine, sine and so on. And we are going to learn to make Bartlett's, the exercise set is going to be a combination of the previous exercise set. But this time we are going to focus more on plotting the data rather than finding the max and Min and so on. So I hope this seems intriguing. So let's get started with the section. 16. Universal Functions: Hi and welcome. This video is about universal functions. So first of all, what is a universal function? So a universal function is a function which acts on a vector element by element. So all the standard functions in the math library has a universal function equivalents. So examples is cosine exponential logarithm. And so before we start, we need to make an NP area. So let's make the vector. And let's just make a director because it's saving off the numbers from one to four. Let me also return the vector so we can see what it does. Okay, so here we have my area for numbers 1234. And if I want to take the exponential of each of these numbers, I can do an XP which is stamps for the exponential of the vector here. And if I run the cell now, we end up with two points, 7, which is e1 and e2, e3, f3, and e to the power four, which is approximately 54 numpy, has also integrated a lot of the standard constants like pi and e. So for instance, I can take my vector and multiply it by np dot py, which is numpy, comes and return. And now I end up with pi, two pi, three pi and four pi. So for instance, now a 51 to take the cosine of this vector here, I could do np dot cosine for taking the cosine element-wise. And P dot py types my vector here. And if I run this cell, it will take the cosine of Pi, the cosine of two pi, and so on, up to four pi. So let me run it. And now we end up with minus 1, 1, minus 1, 1, which is exactly what we want. Similarly, we can also take and P dot logarithm, which is the natural logarithm of np dot e, which is the number e times my vector. And run this and then we get the first number, which is one, because the natural logarithm of e is by definition one. And then we get 2 times e and undo the logarithm, this, and so on here. So you might wonder why we have defined all this function by acting elements bys. And hopefully it will make more sense of to the next video where we are going to go through plotting. So see you in the next video. 17. Function Plotting: Hi and welcome. In this video we are going to go through how to plot using Matplotlib. So what is Matplotlib? Matplotlib is a plotting library, so we can use it to make a bar plot, so scatter plots or functions plots and so on. So the first thing we need to do is to actually import matplotlib. So the way to do it is to use the import keyword and then met plots dot pyplot. And it's customary to install it with the alias PLT. So let me run this cell. So now we have imported matplotlib. The first thing we need to do is actually to have something to plot. So remember when plotting, you need x values and corresponding y values, and then you draw them into a coordinate system. And this is the plots. So let's do exactly that. My x values is going to be np dot arrange. Fine. So let me also returned the x values. So here we have just the numbers between 04 and my y values is going to be np dot sin of the x values. So let me also return the y-values. So remember what we get out is sine of 0, which is 0, sine of one, which is 0.84, and so on. Sine of two, which is 0.9 something, and so on. And all these values in radians. So the standard in NumPy is to take cosine, sine, and so on in radians, not in degrees. So now I want to use matplotlib to plot these x values corresponding to these values. So the way to do this is with the PLT dotplot function. So if we take Shift Tab, we end up with a list here. So it's plus y versus x as lines. So we just have straight lines between them. So let's see how it works. First of all, I take my x values and my values. And to actually show the plots, if you're not using Jupiter notebook, you will need PLT. Dots show like this. And let's run the cell. And what you can see here is that we have a plot with the coordinates 00 here and a straight line towards one comma sinus of one, and so on here. So it looks kind of boxy, it's straight lines. So the way to make the plot look smooth is to have more values between 04 here. So let's do another plot, but this time let us try to make it look smooth. So I want to plot the function. And I want to plot the cosine function of x multiplied by 2. So 2 cosine. And I also want to domain. So you want to do it between 0 and Pi. So we are going to do it in several steps. First of all, I want to make a 100 points between the value 0 and the value pi. And way I'm going to do it is to use the new function linspace. So my x values is going to be equal to np dot Kotlin space. So linspace takes in a starting point and print and the number of points you want between the starting point and the endpoint. So for instance, in this case, I want to start at 0. I want to end at np.array. And let's say I want a 100 points between 0 and np dot py. So let me also just print out the a 100 values like this. And here you have 100 acute distributed points between 0 and Pi is so quick note is that you can also do this with using the range function, which we have gone through previously. The only thing is that you actually need to compute what the step is going to be to make a 100 points. So when plotting and you want a specific number of points between the endpoints, then it's a lot easier to use linspace instead of using a range. So here I have my 100 points. So let's do something with it. And the next thing I want to do is to define my y values, which is going to be two types. And then the cosine function, which is np dot Cos of the values x values. And let me also return. So here we have all the corresponding y values, which is by taking the x values and plug them into this function. So now, since I have a 100 values or graph is going to be Smith. So let's try again with plt.plot x values, comma y values, and run the cell. And now you noted that I did not use the plt.plot show. If you're using something else, then you put the notebook, you will need the plt.plot Show to make a joke. But since we are returning a plot, we can also just run this cell without the plt.plot Show. So I also want an x label and y label, and this is done with the x label and y label functions. Let me do PLT xlabel. And then I take in the string, which is going to be my x label. So let me just call it x values and run the cell. And now we see down here we have an x label. So let me also give it a vial label, which is going to be the function. And also since we can give in later code here. So let me also do that by writing both sine cos 2 times cosine of x and then end with a dollar sign. So this is just the later code for two times the cosine function of x. And let me run the cell again. And now we see that we have available, which is 2 times the cosine of x. So this was everything I wanted to go through in this video. The next video we are going to go a bit more fruit plotting. So we are going to go through barplot and scatter plots, which are used a lot in statistics. So see you again in the next video. 18. Bar and Scatter Plot: Hi, and welcome to this last video on plotting functions in Python. So this video, I'm going to go through two more plots, namely the bar plot and the scatterplots. So before we begin, we need a vector. So let me have my vector, which is essentially going to be some numbers. And let me take the numbers five comma one comma 12, 0, free for instance. So let's say the vector symbolizes how much did it rained each day for five days. So the first day he trained, I'm millimeters, second day, one millimeter the first day and it rained a lot, so 12 millimeters and so on. So what we want to do is to make a bar plot of your data. So a bar plot takes in vector, which is this one, and some categories. So Cadbury's can also be string, but let us have just the number days and it's going to be P dot arrange. And let me start at one and take the length of the vector and then add one since the end point is not included. So let me also just to return here so that you can see what it is. So here we have the numbers 12345 corresponding to the base 12345. Okay, so now we have our categories which I still face and my measurements which are saved in this vector. So let us make the barplot and the command for making a bar plot is just PLT dot bar. So plt.plot. And then we have our categories, which is number of theta and r vector, or our measurement which is saved in the vector vector. So let me just run this. And now we have the plot for how much you'd run each day. And remember if you're not in Jupiter, you need PLT. Show like this to get the blood. Additionally, if your code do not run, you probably haven't installed one of the packages. So remember is that appear in the previous lecture, we installed matplotlib as PLT, and in the first lecture in this section, we imported numpy as np. So let me go down again to my plot. So as we did last time, we can make some axis labels and bilabials. So let me do a left. And the x label is going to be the day and my y label, It's going to be reign in millimeter. So let me run the cell again. And now you see that you have a y label and the next label. You can also give this plot a title. So the command for giving it the title is just PLT title. And then you can give in your title as a string. So let me just give it the title, rain and again, compile. And now you see that above the graph you have the title, which is train, your y label and your x-label. So this was everything I wanted to say about the barplot. So let's move on to the scatter plot. So first of all, what is a scatterplot? A scatterplot is just taking in a bunch of coordinates and give me out adapt at each coordinates. So it will be more clear when we actually do a scatterplot. But first of all, we need some coordinates. So let us first give in all the x values. And my x values is going to be one comma, two comma three, comma v dot 556979, like this. And let me also just give it back so that we actually have an output layer. And my y values corresponding to each x value is going to be 1.522.54567.28.5. And again, let me just give out my y-values like this. Okay, so if I now make a scatterplot, first of all, I didn't have a dot at the coordinate one comma 1.5, another dot at two comma two, the coordinate two comma two, and under data F3 comma 2.5 and so on. So let's try in this new cell and make a scatter plot. And the command for making a scatter plot is scatter. And it takes in the x values and y values. And let us just try to run the sun. Remember, again, if you do not use your notebook, you will need plt.plot Show for time using each button off pics. So I'm just going to run it. And here we have our scatter plots. So this point here has coordinates 1 comma 1.5. The coordinates of this one is two comma two and so on. Here, which is the last coordinate, nine comma 8.5. This is used a lot if you have some experimental data and you want to make a plot, for instance, to see tendencies if it's linear, quadratic or so on. So here you see from the point that it's almost linear serve as an approximation of these points. You could use linear regression or something like that, but more of that later. And again, if you want, you can also have some more data like the axis. Or you can have DWI label. And finally, if you want, you can have a title, which is going to be my experiment like this. And if I run this elegant and actually managed to spell title correctly, title like this. And now we're on myself. I have some x label and y label, and the title. 19. Exercise Set - Temperature Data II: Hi and welcome to this second exercise set. This is a combination of the previous exercise set which tackled temperature data. In New York. This time we will focus more on plotting the data and not so much on finding the Min and the max and so on. For your convenience, we have copied a lot of the things we did in the previous video because we're going to use them further. So let me start by running the cell here to import the NumPy package and the dataset. So let's quickly go through the exercises. So the first exercise is to make the month for a NumPy array containing the months. So that is just the numbers from one to 12 in the NumPy array. Secondly, it's importing the matplotlib package as PLT. The third exercise is about making a bar plot of the temperatures and giving us an x label and y label and so on. And the effect size is a bit tricky and it's about making a simple approximation function with the cosine to the temperature data. So I have divided the exercise into several small step for you. First are going to find the amplitude and the month with the highest temperature. And then you're going to compute this vector here. And finally, you are going to set everything together in this exercise to make an approximation of the temperature using cosine. In the last part, you are going to plot the differences of the real data and approximate the data. And finally, you're just going to plot the function which we found above here. So now since this is a continuous function, you can take in whatever values you want and plugged it in those specific values. So I hope you will enjoy the exercise suggests tried to do it on your own. And when you're ready, come back and look at the exercise solution. 20. Randomness and Statistics Intro: Hi, welcome back to a new section. In this section we'll talk about randomness and statistics, and now we can implement this using NumPy. So before we start, let's just look at what we will cover. So this section is really all about generating random numbers and calculating statistics and NumPy. More specifically, we'll learn how to generate random integers using NumPy. We will learn how to shuffle an array and also how to choose numbers randomly. Pulmonary, I noticed Lena has told me about plotting. I want to use this and will create normally distributed vectors. If you don't know what normally distributed means, that's completely fine. I'll explain it individual. So I also said we should calculate some statistics. And specifically this means calculate means which we have seen previously and also very answers and medians. These are important summary statistics of data that you really want to get your hands-on. Finally, I'll show you how to find all the unique values in an array and how we can use that to plot a histogram of the frequency of values. As usual, we have an exercise set and the exercise set this time geared towards data analysis. So in this exercise, we'll work with what's called linear regression is very simple and standard machine-learning algorithm will implement that using numpy. Of course, the focus will be on randomness and statistics in NumPy, Also for the exercise set. But we'll use this in a context where we can have some fun with linear regression. So again, you don't need to know anything about this from before. It will explain it all in the exercise sets. So I hope you're ready for this and I'll see you in the next video. 21. Generators and Random Integers: Hi, so I'm back in Jupyter Notebooks and here I have a new sheet called randomness and statistics. And for the first three videos, I'm going to talk about random numbers in NumPy. So the first video is about making generators, random integers. So let us start first of all by importing the correct thing to in this case, I'm going to go into the NumPy package and specifically import a module called random. And inside this module to be able to generate random numbers, will need to make as kind of generator object. So I'll make a variable called R and G, which stands for random number generator. This will be equal to random. Then we'll use the function default R and G. And this here runs fine. What this does, the default R and D function is to kind of initiate a generator object. Let me just type this, that this initiates generator object and we'll use this generator object to create random numbers of different sorts. So first of all, let's just check the type of RNG. You can see now that this is inside the random module and it's what's called a generator. If you want to be really precise than the generator object is actually a container for a kind of lower-level object called a bit generator. And we don't need to concern ourselves with this. So what we just need to work with that random generator. Now we have this orangey, the random number generator, and we can call methods on it. So if I just press period here and then press Tab, then I will get up a list here of possible methods that I can use an attributes. And what I will first do is to do the integer one. Integers. If I press here, Shift Tab, also get up at docstring. And here you can see I have some information. This takes in a low value, high value, and a size and some other things. So this essentially creates a lot of random numbers between a low value and high value. So if I want random numbers between 0 and 10, then this is the thing. When I run it, they'll just get one number and that's fine. That's not too bad, but typically want full areas of random numbers. So I can specify a size attribute here. Let's say I want a ton of them and then I get back an array. And you can see here that these random numbers between 0 and 10, you might notice that if I run this several times, I get different numbers. So that's good because it should be random. Also the tendinous never include that. If you look again at the docstring, it says that a high values exclusive, if you really want that to be inclusive, you can either say yes, go to 11, this is one option or it can pass in end point. I think. Let's just try this and I want the endpoint to be true. This means that the endpoint, meaning the high here, should be included now considered ten also appears. So RNG, the random number generators is kinda new, scary object. But once you call a method on it, like integers is thing here. Just again to make sure this is really just our classical NumPy arrays. We know what to do with these. We can sum them, we can take her product, we can use all the functions that we have developed so far. So let me just have it like this. And as a simple example, we can make random bits. Recall that the bits can be at least modeled as being either 0 or one. And we can make a lot of random bits by just doing orangey calling integers. And now I want only from 0 to 22, not inclusive. So if you just pass in one number, namely to them by default, this will be a high number. And let's say I want 64 of these. And you can see that I get 64 bits and there are random. One thing to note is that say this is perfect. This is precisely the numbers I want. And then I just run the cell again and I get new wants to hold. Do I get the old ones back? As it stands now I can't do this as an easy way. This because I didn't provide a seed. So initially here, if I do the default random number generator, they look at the docstring. You can see that I can pass in a seed. So a seed essentially means a reference point. Rare can always go back to this. You might have noticed that if you're following along, you will get different random numbers than I do. But let's say we pass in a seed and say 40 to the specific number is just a reference. We can pick any number you want. Let's say that we choose. In this case, if I run this cell now, I've initiated the orangey with 42 as seed, let's say an hour on this one, the first thing that happens is 0 87 can run it again and I can get new stuff. But if I want to get back to original starting point, meaning 087, I just run this again with seed 40 to run it. Now I get sewer H7 again. This is also nice because if you're tagging along, you'll get exactly the same numbers as mean, as long as you pass in the same seat, if you choose a different seeds, say 101, you'll have a different stream here going on. So this is the way to create random integers. Just to be clear, randomness means that each number here from 0 to 10 equal chance of appearing in each of these. To see her that you will get repeated entries like aids appearing three times. You will also have entries like to, I guess it's not appearing at all. So randomness in general is used in a lot of fields. For instance, either in game design or let's say for doing machine learning with splitting a test and training set for a vote to know about that. It should also be pointed out here that this is what's really called pseudorandom number generator. This means that the numbers here are constructed based on an algorithm. So they have good properties relating to randomness, but they are not secure in any way. This means that you shouldn't use this for cryptography to relate to things, but you could safely use them in machine learning and related fields. Thanks, and I'll see you again in the next video. 22. Random, Shuffle, and Choice: Hi, welcome back. So in this video I want to talk about three functions that we have eliminated random function, the shuffle function and the choice function will also get a chance to visualize some of this randomness by using Matplotlib. So let's start by the random function. The random function is kind of like this integer function, except that it produces random floats. To run on floating point numbers is typically between 01. So let's make a variable, let's call it uniform floats on a Saturday, RNG. So our random number generator and use the method random inside the random method. So again, I press Shift Tab era can see what I need to pass in. So it should pass in at least the size. So let's do 50 of them. This works fine. So let's print this out. Here. You can see that I have a bunch of numbers between 0100, all uniformly distributed. This means that each number has an equally probable chance of appearing here. So what we can do to get a kind of insight into how this looks is to use matplotlib as the inner taught you in the previous sections. So let's talk about drawing randomness. So let's first of all import matplotlib. So I'll use a typical convention PLT for matplotlib. So let's make an x variable and y variable, both of them just being run numbers. Let x be, again go into orangey and do random. Let's pick, say, 300 of these, and let's do the same for y. Notice that since I'm using this function twice, x and y will not have the same numbers. Both have numbers drawn from this uniform random distribution. I noticed the natatio about this. So in muffled live we have the scatter function. So I can write plt.plot scatter and then plot x against y. And I'll have plt.plot show here. And here we can see our numbers. So you can see that on both the x-axis here and the y axis, we have it ranging from 0 all the way to one. So this is what randomness looks like when you have uniformly distributed. If the points lie on a nice grid equally distant from each other, then that's a very structured thing. Randomness actually means that in some areas you will have nothing, in some areas will have clutters of more of them. So to make this, you can imagine placing a blindfold on someone and ask them to throw a dart at a board. And we will record a point and ask them to do it again at 300 times. And we will get hopefully something looking like this. Some of the errors will actually be close, but in some places you simply won't hit anything. So this is the random function, and we also have two more functions here. We're kind of short and cute to have the shuffle function. And we have the choice function. Let me actually just import NumPy, the whole library as np so that I can make my array. This is NumPy array. And again, let's do the usual one that I do, which is 4, 8, 15, 16, 23, 42. Now we can take our random number generator and use the method shuffle array. Let's print this out. Shuffled array. I hope this is a verb. And let's print out the array. Now we can see that I've shuffled it, meaning that I've taken these things here and just reshuffled, eminent arbitrary order, sort of word shuffled come from playing cards were just shuffle the deck before you play it out. So now everything is in a kind of a random order. So if you want to do model like playing cards and this could be useful. This is actually also useful in machine learning. If you have a model and you have a lot of data, and you want to shuffle your data before sending it into your model to the data does not depend on the way you collected it. So edition to the shuffle function, we have the choice function. And the choice function essentially chooses a number of elements from a given array. Let me make an variable called three elements from array, a very long name. I think this tells you what is going to do. So I'm going to go into my random number generator and do the choice function, going to act on my array. And I'm also going to specify a size here, and I want to size to be three. Running, this looks good. So let's print out three elements. Just autocomplete this here you can see that three elements have been chosen, putting 316 and then 23 again. So this choice here is what's called width replacement. This means that I've taken 23, that I tried to take an under 16, then I tried to take another that each time I have all of them as possibilities to choose from. This is called width replacements. So you can see here if you go to the choice function and just take Shift Tab and you can see the optional arguments and the default is replaced, true, meaning width replacement. If I specifically don't want replacement, then I would say replace equals false. In this case, however many times I run it, I will never take the same thing twice. In the next video, I'm going to show you that you have a lot of statistical distributions built into NumPy. And this is really one of the things that separates it from the default random module in Python. The thanks, and I'll see you again in the next video. 23. The Normal Distribution: Hi everyone. In this final video on random numbers, I want to talk about normal distributions and also other distributions that are present in the numpy library. We've previously seen two ways of generating random numbers. The first one, if I scroll up, was the integer methods are integers, and the second one was the random method. And both of these ways of generating random numbers are uniform in the sense that each number has an equal chance of appearing. But not all distributions in statistics are like this. The most famous distribution in statistics is a normal distribution, and this is not like this. The classical example of normal distributions is height in adults. So if you go out on the street or pick a random person, and the height of that person might be say, one meter and 75 centimeters. If you pick a lot of people, you might find that something around that is the average. It's not equally likely to find a person who's won 75 as it is to find someone who's 140, as it is to find someone who's to 15 people on the end of the spectrum, meaning people say, say it all slower than 150 rehired and 210 is really, really rare. There's a really short and easy function to make it normally distributed random variables in NumPy, we can draw normally distributed random numbers. Let's actually tried to model the height example, heights. And now I go to random number generator and use the method normal. And inside a normal variables, let me just shift tab here. I can specify a location which is the same as the mean. I can specify a skill which will be the same production noises standard deviation, and the closest specify a size. So let's say with a high-tech sample that without researching this, Let's say that for adults is one, 75 for the height. And this is in meters. And then the standard deviation, Let's say that it's probably something like 0.15 maybe. And let's say I pick 100 people like this. So here you can see it and I think a guest rather goods. We can see a lot of people in the range of say, 175, one seventy four seventy one, lot of people slightly over 180 on 8600, 160. It is a very common, it is really, really uncommon here, even if I run it multiple times to find someone who's two tan. And this models kind of a real situation that if you see someone who is two meters and 10 saturations would probably also notice. So to get a good understanding of the normal distribution can be a good idea to plot this and seen as told you about several different plots like that. Plt.plot, PLT dot scatter and plt.plot bar at risk. Also the plt.plot test, which is called a histogram. So let's start by making a bunch of randomly normal distributed numbers. Let me just call it y for simplicity, are in G0 normal. Again, we do exactly the same, 175, 0.15, and let's take a 1000 of them, so a bit more. Now, we use PLT. This is for plotting, recall, and we have already imported matplotlib. Just call a bit up here. I have imported matplotlib here as PLT, so it's fine. So I do PLT. And instead of the ones you've learned about like plot, scatter and bar, and we also have hist. So first of all, let's just specify the variable which is y. And then we can do PLT, plot show. And here you have a histogram. You can see that the average is roughly here at 175, and then it becomes less and less usual to see people here. So it's very common to see an adult less than 140 or over 220. Let's add a title with PLT title, call this normal distribution. Like this, looks good. You can also specify the bin size. So the bin sizes, how many of these should be grouped into one kind of Ben. So I've been starting here. It's one of these bricks here. So we can just experiment, let's say bins equal to1. I think that's slightly more than what we had, but not that much. Let's do 20. I can see that we have a lot more of these small bends. And let's do quite lots of 50 is quite much, as you can see, that it has this kind of bell shape where it starts low and then increases, increases to a certain point and then it decreases again. This is an important property of the normal distribution, that it's symmetric, meaning that they're equally likely to observe things below the average done above it. So this is normal distribution. But if I just look at all the methods I have here, R and G dot, then I have a lot more. So here I am at NumPy documentation page on the random generator. And here we can first of all see some information about this generator that we talked about and how to initiate it as we did and so on and bit about its connection to this lower level component called a generator. Case. If we scroll down a bit here past examples, and you can see all the methods that we've seen, quite a few of these we've seen random choice and shuffle and integers. So if you scroll further down, we can see a lot of distributions here, and we've just seen a single one of them in the normal distribution. So if you're really a statistics person, then this should be pretty familiar if you're not, and that's completely okay, but this is just a lot of the common distributions that pop up around in different disciplines. So some of you might have heard of the binomial distribution or the xi square distribution for a geometric distribution or the gamma distribution of these are pretty common or not go through any more than the ones I have because they all work more or less the same. So for instance, if you look at binomial distribution here, then it says that it draws samples from a binomial distribution and it can pass in parameters n and p in the usual binomial distribution. If you know what that means. 24. Basic Statistics: Hey, welcome back. So in this video we're going to talk about statistical functions in NumPy, if you remember quite a few videos back when I talked about aggregate functions. So aggregate functions in NumPy or functions that take in a NumPy array and return a single number and basic statistical functions or typically all like that. So just a special case of something we've looked at previously. We've actually seen one of them. So we have previously seen the mean, or sometimes called the average of a vector. So again, let me just initiate my favorite array. And we can then print out the mean of the array by using np dot Min and passing in the array. You can see that the mean is 18, and this is one of them. We've seen this previously. There are also three motor I want to show. One of them is the standard deviation. So if I have an array, I can use the function np.array td and pass in the array like this. And here I get a number, and this is what's called the standard deviation. So if you recall the example with the normal distribution, and we actually had to pass in something here as a second argument. And this is essentially the standard deviation. So this is how much of a spread it has. So if you place a large number here, it can be good to just visualize this. Let's say 0.5, then this here is thicker so it's more spread out. If you do it like an extreme amount can be a bit hard to see here because Matplotlib automatically readjust the axis with looks kind of the same prefix. See here that it really goes now from minus 2.5 to slide 6 meters. So it's pretty, pretty spread out. This was what we had and now if you compare, the standard deviation is actually just 0.15. So it's just from 0.75 all the way to 0.6. So this is the distance of the standard deviation. So it's how much it spreads out. And you can find out of any array, you can do easily NumPy, but just doing the std here. This has at the spread here is 12, which seems kind of reasonable. So most values lie within six and 13. There is also related notion called variance. And variance is just the square root of the standard deviation. So let me illustrate this. We can write std and let's do np dot, std, array and square this. This is one thing you could do that you can also do the variance function. So this is np dot bar. And you can see that if you're under arrest and you get precisely the same thing. So you can either use the variance function or just square the standard deviation is completely up to you. This thing, the variants kind of measures the same in the sense that if you know the variance, that you know the standard deviation is just a question of squaring it or not. Sometimes the variance is more naturally calculations, while the standard deviation is more natural to represent or presented data, this is in some sense in the same scale level as the mean finding function I want to talk about is the median. So the median is the middle observation. So let's go up to our function here and say you want to find the median of this is especially simple. If it's already sorted as it is here, then you just throw away that element and that element smallest and the largest new throw away the second smallest and the second-largest all the way until you get to the center here. If you have one thing remaining, then that is the median. If you have three things remaining here, 15 and 16, you take just the average of those two, so that will be 15.5. So we can check this, of course, a NumPy array by using a guess what you would expect, namely the median functions we can do np.me and then do this on the array. 0.5 is really easy to read off if it's already sorted or if it's not sorted. And this is a really convenient and easy function to get the medium. I really wanted to point out something that I think is really important. So it printed more properly by saying the median. And then print this. We also previously had the mean or the average to be printed out out. Like this. It's really important that these two are not the same. This is often confused for beginners and that's completely natural because they both give some kind of measure of what's the middle of all of my observations, but I give it in different ways. So the median is by arranging them and picking the middle one. And the mean is simply by averaging all of them. To really convince yourself that this is different. We'll, first of all, we can look at the numbers and say, yeah, these are clearly different. If you want a more extreme example, which is of course very silly, but it helps me remember it. Say that you go up to someone who's selling chocolate and they sell three bars of chocolate. First bar costs $0. The second one also called $0, but he also have a third one. That one costs $100, you have to free ones and one that costs $100. In that case, I'm just writing this as comments. The mean will be 0 plus 0 plus 100 to sum all of them. And then you divide by the number of observations. So this is 1 third times this nonsense here. And as you can see, this is roughly equal to 33, right? But if you do the median approach, then you first remove the lowest one, which is 0, and you move the highest one which is 100. So we've removed one at each point and you're just left with 0 through completely different. So the mean here would represent the seller just pushing a chocolate at you at random, just you have to pay for this. And this will be the average amount you would have to pay. But the median would tell you that if a typical person went over, it would typically pay 0 in the sense that most people will pay 02 out of three people. So they're just different measures of finding come center in your data. This is what I wanted to say about statistical functions in NumPy. In the next video, we're going to look at a really nice function for discovering how many unique values there are in an array. 25. Finding Unique Values: Hi and welcome back. So this will be a pretty short video where I just explained you how to find all the unique values in a vector. Soon as opera just producing vectors, Let's do np.array. And it's just a variation of my favorite areas where let's say four, they have some repetition, again for handsome eighths. And then I have 115, then I have three 23s and I have 440. T2's like this. Say no, do I just want the unique values here, not the duplications. I could do a for loop. There is also really neat function which is mp dot unique pass in the array, and this returns all the unique values. So you can see here that I get my standard array except for the number 16, which is not present here at all. And that's more or less it for this video, except that there is a really, really nice optional argument that we can pass into this unique function here. Say no, that I want a plot of how many of these individual values appear. So you should have some kind of barplot stimulatory about where this here should have the height for this number here should have the height to our no, sorry, this number should have the height three, this number should have the height one and so on. So how can we do this? There, of course, manual ways of doing this, but also there's an optional argument that you can pass in here. We'll just scroll down and this is the return counts. This is by default set to false. So let's just do it here. We have the return counter variable and set this equal to true. Now you can see that I get back to arrays returned as a tuple. The first one is the one I got previously. And the second corresponds to how many of these appeared in the array. Since I have a two here that indicates that two of the value for appeared. Namely here, it doesn't matter if it's sorted or not. The original array will still pick up the same information. So that is really convenient because now I can draw a bar plot. Since they return a tuple, I can do what's called tuple unpacking sometimes purchases just say I have my a unique values, just call it counts, and then do this thing here is let me just copy it. And if I do it like this and this value here or be assigned to the first one. And this value counts will be assigned to the second. Let's do this. And now I can repeal t. Remember that I have imported matplotlib as PLT in a previous lecture and it can do plt.plot our esteemed told me about. And for x values I would have my unique values. For y values should be how many of them are, namely Accounts. And here you can see the bar plot and the highest bar is here at number 42. This signifies for, because I had four entries of 42. So the fact that you can use this optional argument return counts as somewhat new. I think there's came about in NumPy 1.9 to make sure that your version of NumPy is higher than that. If you installed NumPy through Anaconda in the beginning, then definitely OB higher than this. But you can always, as a side note, you can always check your version or just doing np dot double underscore version here you can see that I have 1.18. So usually there are only minor updates from ASA 18 to 19. But actually if you go from 1.9 to 1.18 and there are quite a lot of things that have changed, so you should try to keep it up-to-date. So let's say np dot unique function. It's really easy to remember and it's really easy to use. So I love it and I hope you do as well. Thanks, and I'll see you again in the next video. 26. Exercise Set - Linear Regression: Hey, and welcome to this second exercise set. In this set we're going to look at linear regression. Linear regression is machine learning method, and it's also just a basic statistical method for predicting new values. So in the beginning of the exercise setup included this brief description of linear regression. If you still feel like you don't completely get it, then I would just suggest to go through the exercises and get some practice with it. If you want to learn more about linear regression afterwards than it is after all, one of the most important and popular machine learning methods. So if you just Google linear regression or go to a YouTube video, or probably find hundreds of resources explaining the topic. In any case, in the exercise set refers just asked to import NumPy here. And then we should make a random number generator. For exercise 3 and 4, you're asked to create random inputs and outputs for this linear regression. In exercise 5, you're asked to calculate some means and standard deviations. Exercise 6 is about plotting and also about creating a specific line that is essential for linear regression. After that, the task is to predict a value at a new point. So this is the main goal of linear regression. You have some observed data that you already have, nearly linear regression. With linear regression, we are able to predict the value at a new point. Give the exercise set an honest Cole if you're stuck. And of course you can look at the exercise solutions. 27. Matrices Intro: Hi, and welcome to this section, which is all about making and modifying matrices. So the things we are going to go through in this section is how to make and modify matrices. As the title suggests, we are going to learn to create 2D arrays, also known as matrices, handle attributes of a matrix. We're going to learn to specify an axis in an aggregate function like Max, the mean, and so on. So now we are going to learn how to take the mean of specific columns instead of mean of the entire matrix. We are going to learn a bit about Boolean matrices and how to use them. And we are going to learn how to work with missing values in the exercise left of this section, we are going to work with weather data from Berlin, and this is saved as a 2D array. So you're going to have the opportunity to practice what you have learned in this section in the exercise that I'm really excited to start working with matrices. So let's keep going. 28. Making a Matrix: In this lecture, we are finally going to work with matrices. So what is a matrix? A matrix is a 2D structure, which means that we have both froze and columns. You can think of it kind of like an Excel sheet. So if a vector is the equivalent of the list, then a matrix or a 2D array is the equivalent of a list of lists. So here I have created a list of lists. And what I want to do is to make this list into 2D array. This is done very similar to what we did in the 1D case. So when I want to make my matrix, I write matrix equal np array. And then I just plug in my list. So let me also return matrix. So now we have created our first matrix. So the way it prints it, it's very similar to how it prints lists down. The thing is that in the front we have written airy and we can also check out the type of the matrix. And we get out that it's a non pi and D array, and in this case it's a 2D array. So in this course we will use the words matrix and 2D arrays interchangeably. So now I have the matrix and what I want to do is to go back to List. So let me just quickly recall how it worked for vectors. So if you have a vector and let me just let it be the first five numbers like this. And let me also return the vector. So here is the vector from 0 to four. So if I want to make it back into a list, I can just use the list constructor and place in the vector and from the sun. And here we have the list. So if I tried to do the same with the matrix, we can see what happens. So now you see that instead of keeping your bucket list of lists, we get a list of 1D arrays. So here you have the first element in the list is the array 1, 2, 3, then 4, 5, 6, and so on. So it makes a list, but not the exact list we're looking for. So the way to make it back into a list is to use the two list function. So if I write my matrix again and dots to list and run this one, we end up with a list of lists, which is the original object. You can also use the two list function on vectors. And it gives you back the same thing. But here you can really choose if we want to do the two list or you want to do the list constructor. So the last thing I wanted to go through in this video is how to get values out of my matrix. So if I have my matrix again, so let me just print it out. So it was the numbers from one to 12 arranged in this pattern. So let's say I want to take out a specific role. For instance, the first one, what you can do is to take the matrix and then just plug-in the CEO entry and run it. And here you see that we got the first row. So this is exactly the same syntax as for lists. Additionally, I can reassign the role. So I can write matrix 0 equals and then np.array and then assign it to be a new list of dimension three. So let's say I want three comma F3 comma free to be the first row instead of 123. And if I run this and write out my matrix again, you see that the first row now have been assigned to be free, free, free. So let's say I want to give out a specific value in my matrix so I can use now the same notation as I would do for lists. So let me write matrix than I would like to give out the third row and second column. And if I run it, it gives out the value eight. But there is an easier way to do exactly this thing. So you can write matrix and then two. And then instead of writing another pair of square brackets, you can use comma and then one. And if we run this cell, we get out eight, which is the same entries here. So this means that we can reassign specific entries. So let me write matrix and try to reassign the seven here to be 100. So the seven is on the first row which went counting from 0, gives us two. And it's in the FirstColumn, which when coffin for Sarah again becomes 0. And let me reassign it to be a 100, run this cell, and then give out the matrix again. And now you see that instead of a sudden we have 100 here. So you might wonder, how do we get out two columns? So the easiest way to do this is to use slicing, which we'll get more into in a later section. But for now, we will just use the notation. So if I have my matrix, then I can use colon to kind of tell it. Take all the rows. And let's say I want the third column. Select me run this cell and then they get the array 3, 6, 9, and 12, which is the last column, 369 and 12. And note that when it gives out to froze and columns, it gives me back and 1D array or a vector instead of giving Rebecca 2D array. So this was everything I wanted to say in this video about matrices. In the next video, we will go through the attributes of the matrix. So see you again then. 29. Attributes of a Matrix: Hi and welcome to this video on attributes of a matrix. So in the last video, we saw how to make a matrix. And this time we are going to go through the different properties of matrix have. So remember, as always, in this series, we have imported the NumPy package at the top of the document. So when I talked about 1D arrays, he talked about a bunch of different properties 1D arrays have. When you check the type of for today is the same type as one of the areas that are just some differences in the properties. So first of all, if I have a vector like this, I can ask for the dimension of the vector. And that is dim. And for vector, the dimension is one because it's a 1D array or one-dimensional array. So for a matrix, the ND array should be two because it's a two-dimensional array. So let's check that as well. Here I have my matrix. So let me run this off and then write matrix dot and m, and we get the dimension two. So at the later part, we will go for ND arrays or higher-dimensional areas, like free day areas and so on. And they will have higher and higher dimension. The next thing we talked about was the dtype. So the type of all entries in the matrix need to have the same type, same as for vectors. So if I have my matrix here and ask for the dtype, we get that the type of each entry is integer for 22. And if we ask for the vector, it should be the same. And yes, it gets integer 32. So one thing to note is that my machine might be a bit different from your machine. So you might get integer 64 instead of 32. So this has more to do with kind of the operating system and stuff like that. So the next thing I wanted to go for is the size of a matrix. So remember that the size of the vector is just the number of entries. So in this case five, since we have five entries in our vector. So the question is, what happens when we do it on a matrix? So the size is always the number of entries in the matrix. So in this case we get and six, because of matrix has 123456 elements in it. So currently we have not gotten information about the number of columns and the number of rows in our matrix. And here comes the most important attributes in this section, namely the shape attribute. So let's write matrix dot shape and run it. And what it tells you is that this matrix here have three rows and two columns. And if we actually write out the matrix, we can check we have 123 rows. Two columns. So one quick note is that the thing we get out of the shape is what's called a tuple. Tuple is a Python datatype, which is like a list, except that you can not change the entries. So if I try to have matrix, then I can take out the first entry, like in a list like this. But if I try to reassign it to be one, then I get a type error. So tuple did not support assignment. So let me delete this one. So one thing you might wonder is what happens if I ask about the shape of a vector instead of a matrix? So if I write odd shape, then I get the tuple five. So if we go off, we see that here. We have that the size was also fine. So this shape attributes do not give us any new information when it comes to rectors. So the last thing I want to touch upon in this section is a bit technical, and that is how to go from an 1D object like a vector to a 2D object. So the thing is that you can represent this vector with justified here as a matrix in two different ways. So first of all, you can write the last column vector or you can write it as a row vector. And sometimes it's useful to go from a 1D array, 2D array by just viewing it as a row vector instead of like a one-dimensional thing. Sort of way to do this is if I write row. So what do we want to do is to take this vector here and change the shape to a one comma five here. And the way to do it is to introduce a new axis without introducing any new values. So if I write vector, and in the first entry, I write new axis, which just creates a new axis. And then the last one, I write everything with this semicolon and run this cell. So now I can ask for the shape of this row vector. And what you see is that now the shape is one comma five. And if we look at the row vector, what we see that is that is true set of parenthesis instead of the vector where it was only one. So if you are familiar with lists, this is like having one list with one item, which is another list. So at the recent for having two sets of square brackets is that you have the list inside the list. One thing you might notice that while I took the np dot axis in the first entry, what you can also do is to have it in a second entry. So let's do that as well. And this is kind of like having a column vector. And let me also ask for the shape of the column vector. And now we have the shape five common one. And let me also print out two column vector. So now you see that you have a list of lists, but each inner list only contains one item. So the reason I actually go through this is that sometimes specific functions actually ask for 2D arrays. So additionally, when we go through broadcasting, this way to creating new axis comes into play. So this was all I wanted to say in this section. In the next section, we are going to go through how to change the shape of a matrix. So c or Gemba. 30. Changing the Shape of a Vector: Hi and welcome to this video. In this video we're going to learn how to change the shape of a matrix or a vector. Let me begin by an example. So let's say that we want to create the matrix containing all the numbers from one to a 100, and you want to lay it out in a 10 by 10 grid. So how do you do this? We know how to create the numbers from one to a 100 in a 1D array. So this is just by creating vector equal np dot arrange. And then we start at one. And remember that the end point is not included, so we need to go up to a 101. So let me also just return the vector. And now we have all the numbers from one to a 100, but it's not a matrix, and it's certainly not in a 10 by 10 grid. So what they want to do is to reshape this vector into a 10 by 10 grid. So my matrix is going to be defined by a vector. And the way I'm going to reshape this vector is by applying the reshaped function. So the reshape function takes in the shape you want your matrix to be. In. This case, I wanted to be a 10 by 10 matrix. So let me also return the matrix so we can see what happens and what we get back numbers from one to a 100, but each row has just 10 numbers here. So let's say that we want to go back to a vector again. So the way to do this is also by the reshape method, but this time we want to have the shape for just a 100 consecutive numbers. So we write reshaped and then 100 and see what happens. And now we get us off posts, the same thing we started with. So let me print out matrix again. The one thing to notice by using the reshape method, you're not creating a new matrix, you are just creating a view into your old vector here. So if I define an entry, for instance, the entries 0 comma 0, and I wanted to be minus 20, like this. And I look at the original vector Lambda first entry here is minus 20 as well. So this means that using this reshape method, rate severe and after copy, okay, but we can reshape matrices as well. So let me say that my matrix a, I want to reshape it to be in the shape of, for instance, 50 comma two and run the cell. So now I have 50 rows downwards with two entries each. Okay, sometimes it gets a bit tiresome to do all the math. For instance, let's say that I know I want to 50 rows, but I don't know necessarily what I need to multiply 50 way to get 100 or I don't want to type it into the calculator. What you can do is to write matrix dot reshape. And then we specify what we know. We know the number of rows is going to be 50. And then instead of writing out two, we write out minus1 and let me compile it. So now you see that we get the same thing. Here. And a recent for this is that by writing minus1, you are actually telling num pi, just figure out what you need to put there to make up 100 entries. So one thing you might be wondering about is what happens if I try to reshape it into something which do not have a 100 entries. So let me try with dot reshape. And let me write 23 comma minus1 tried to run the cell. And then you see that NumPy is really not happy with you. It gives you back an error which says that you cannot reshape this area here, which shape 100 into shape with 23. And the reason is 123 is co-prime, so it doesn't have any common factors. So what you are asking numpy to do, it cannot do. So in last video, we talked a bit about what are we going to do to go from a 1D array into a 2D area with introducing the new axis and so on. It happens just as often that you are given a 2D array or even a higher-dimensional array. And you want to go down to 1D array because the function you are trying to apply only accept one day arrays. So what we have learned is that what we can do is to use the reshape. So I can write matrix dot reshape minus one, and it will give me out to 1D array. But what we also can do is to use the flattened method. So let me write new vector and write matrix that flatten like this and run the code. And let me just write new vector. And you get the flattened version of the matrix matrix. But there is one difference between doing research method and doing the flattened. And that is that the flattened method gives me a copy. So if I try to reassign the first value of new vector, and let me say it's equal to 100 thousand. Then if we look at new vector and it has 1 thousand inside the first entry for different right matrix. Then it's still minus 20. So indeed, we see that using the flattened method gives us a copy instead of a view. So if you at anytime wanted to force a copy, you can use the copy function. So for instance, if I want new matrix to be equal to np dot copy of just my original matrix. No new matrix is actually a copy. So to test this, we can write new matrix 0 comma 0 and just say that it's 0 again. So now the first century of the new matrix is 0. But if I write out copy, then we see that for the original matrix, it's still minus 20. In the next video, we are going to learn several new ways to create new matrices. And additionally, we are going to learn to take the max, the mean, and so on, on a row whitespaces. So see you then. 31. New Matrices and Specifying Axis: Hi and welcome back. In this video, we are going to learn how to create some special kind of matrices and how to specify the axis in some functions like the mean and the max and so on. So there are some matrices that pop up so often that we have a special command in making them. So one of them is to create a matrix with only 0 values. And to do this, we will use the np.zeros and then you give him the tuple with your dimensions. So for instance, three comma seven. And if we run it, we will create the free by Southern matrix. We can also use the np.zeros on vectors. For instance, if we only give in the number 10, it will create a vector with 1000 entries. A similar sort of command is the ones command, which creates a matrix with only once. So it works exactly the same. So right, np.array. And then you can give in a tuple with the numbers. So for instance, ten comma five, and run it. And here we have a 10 by five matrix. And also we can make vectors by just giving in a single number like 12. Run this. And here we have a vector with only once. So if we want a vector with only two, you can simply take this vector here, multiply it by two. And now we have a vector, we'd only twos. Another matrix that we use often, especially in linear algebra, is the identity matrix. So the identity matrix is the matrix of one along its diagonal and zeros anywhere else. So for instance, if I want the free by three matrix with 1s along its diagonal and 0 everywhere else, I can write np dot for that entity and then free run the cell. And then I have a three by three matrix with 1s along the diagonal and zeros everywhere else. So the identity matrix has always equal amounts of columns and rows. So the next thing I wanted to go through is how to use the sum function and the mean function when it comes to matrices. So first of all, I needed a matrix. So here we have a matrix and let me also just give it back to print it. So here we have a free by four matrix. So what I want to do with this matrix is to take the sum of the entries. So you can simply write matrix dot sum and compile. And this will give you the sum of all the entries. So it for more or less exactly the same as it did for vectors. But let's say that you want to sum that only over the rows. So you want to take seven plus eight plus seven plus three. Give out the number 4 plus 5 plus 2 plus F3, give out a number and so on, on the left, stroll. To do this, you can specify the axis inside the sum function. So you write matrix, does some, and inside here you write the argument axis. And you want to give in the number corresponded to the axis which vanish. So if I go how pair? If I want to sum over all the rows, I want the columns to vanish and the columns have the axis equal to one. So if I now run this with Ax is equal to 1, I end up with 25, which is the sum of seven plus eight plus seven plus three, 14, which is four plus five, plus two plus three. And 11, which is 0 plus four plus three plus four. If I want to sum over the columns instead, I can write matrix that sum. But this time I set the axis equal to 0 because I want the rows to vanish. And if I run this cell, I get 11, which is 7 plus 4, 17 which is 8 plus 5 plus 4, and so on. So this works with several different functions. For instance, I can do the mean and right axis equal to 0. And now I get the mean over all the columns. So 7 plus 4 plus 0 divided by 3, which gives me out the mean is 3.666678 plus five plus four divided by three is, which is the mean of this column is 5.6667 and so on. So you can do this with the max. For instance, you can write matrix dot max axis equal to one from this, and it gives me out the max over all the rows. So the first row have MAX 8, the second has max five, and the last one halves max four. The last thing I wanted to say is that if you're not completely sure if you can specify the axis inside your function, you can ask for help. So for instance, if I write matrix dot Min and I want to see if I can put in an axis here. I can write shift tab. And this will give me out the docstring and open it here. And then you see that you have this axis which you can specify. Okay, this was everything I wanted to say. So see you again in the next video. 32. Boolean Vectors and Matrices: Hi and welcome to this video where we are going to go through Boolean vectors and matrices. So as you probably know, a Boolean value has either the value true or the value false. And you can create vectors which have only true and false values. So you can write vector equal and P dot array and then take in a list of true and false values like this. So let us run this cell and let me also give back the vector. So heavy you have an area with only true and false values. So the way NumPy does it is by setting the DIY Type 2 billion. So if we ask what is the dtype? We see that the deep pipe is equal 2 billion. So we can also create matrices with this D35. Select me, just write matrix equal to vector dot reshape. And then I want to first value to be two. And I want an empire to compute the loss value. So let me run this cell and give out matrix. And now I have a matrix with only true and false values. So usually we Billy and matrices are not made in this way where you are setting true and false values. They usually pop up as an answer to some question you might have. For instance, if I create my matrix with entries and let me reshape it to a matrix like this. And let me also just show you the matrix. So now I have a matrix with values from 0 to nine. So what I want to answer is which of the entries are smaller than five? So to do this, we can simply write matrix smaller and five, run the cell. And you see that what you get out is a Boolean matrix. So the true entries here is if the value is smaller than five. So for instance, the first entry is true because 0 is smaller than five. The second entry there you have is true because one is smaller than five and so on. And the later entries of falls and reason as five is not less than, than five, and so on. So I will show that this is really useful when we're trying to get out specific entries from a matrix. For now, I will just go through some of the operations associated with Boolean matrices. So let me make another Boolean matrix by writing pool matrix. And it will be equal to matrix with all the values less than five. So this is basically this matrix of pair. So now I can begin asking some questions. For instance, are all the entries inside this matrix true? And the way to answer this is to write a Boolean matrix and then write two dot all function. And this keeps me out false because there are false values here. So the old function can take in an axis, as we saw in the last video. So we can write dot all and that ask if all the entries along a specific axis is true. So for instance, we can ask if all the entries along the rows or is true. So there we write axis equal to one because we want to remove all the columns. And now we get that for the first row, all the entries are true because we get true, true, true, true, and true. And for the second, not all the entries are true, so we get false. We also have the function f, which answer the question if any of the entries, and it works almost the same, we write bool matrix dot n. And then we get true because there are true entries here. And we can also specify an entry like and let me write the axis equal to 0 from the cell. And then we get only true values because the first column has the true value, the second column has the true value, and so on. So there are true values in all of the columns. The last practical theme that I wanted to touch upon in this video is the non value. What is the non-value? So the non-value is non-price equivalent of the non-value in Python. So it is when you do not harm the specific value in your matrix. So this happened often when gone missing data from new datasets to get the non-value, you write np dot and then we get back. So this here is the non pi notation for the non-value-added. So we can make a matrix which contains the non-value. So let me say that matrix contains the information of how much it rained each day. And we make two observations each day, one in the morning and one in the evening. In the morning on the first day, a train one millimeter, and then the morning on the second day, it rained free millimeter. And then five in the evening. This first day trained to millimeters than free. And then the last day in the evening, the neighbor's cat destroyed or measurements. So we end up with a NAN value. We do not have the value for that day. So let us run the cell and let me also print out the matrix. So have you seen the values 1, 2, free, free, and then five, and then finally this new value. So when you have a rather large dataset, it's often difficult to see have none values in your dataset. So one question you might ask is, do my dataset contain a non-value? And this is important for doing further data analysis because if your dataset has missing values, you need to handle them in a special way. So luckily, we have a function in NumPy which gives us the answer for this question, which is, is numb. So we can write is none and then take in our dataset rain. And here we see that the first value is not null, so we get false. The second one is false for false and so on. But the last value here is true. So if we want to see if there are any NAN values in your dataset, then you can write any. And you see that yes, there is indeed some NAN values in my dataset. And if you want to get somewhat more specific, you can write axis equal to one to get out to Rome. And now we get that while the non-value is in the second row, and similarly, you can see which columns which contain null values. This was everything I wanted to say. So see you again in the next video. 33. Exercise Set - Rain Data: Hi, and welcome to this exercise set. And in this exercise set, we are going to work with 2D arrays. So to be a bit more specific, we are going to work better data for Berlin, and it has three rows and the weather data has three rows. The first one contains the record high each month. The second one is the daily mean or the average over all the months. And the last one is to record low for each of the months. So here we have printed it out and here we have saved the weather data as a list. So the first column is the data for January, the second one is the data for February and so on. Okay, So we have several exercises. The first one is to actually make this list here to NumPy array. And thereafter you're going to find the shape area. The next one is to correct a mistake in the dataset because the daily average for March should not be fairly free, which it says here, it should be 4.3. So there's some mistake and you are going to correct it. The next one is to just print out the column containing the data for June. So you want to take the array which contains the data for June and print it out. Next one here it's a little bit about reshaping and how you can do, and how you can use research shaping to take average of pairs of months. The fifth exercise is a bit more about taking Min and max over the rows. And finally, we are going to use Boolean matrices to answer some questions. For example, how many rows has an average temperature above 10 degrees? And are there any months with a record high which is sub-zero or within daily average which is below 0. So good luck with exercise. And if you add any time become stuck and don't know what to do, you can either look into the exercise solutions or you can ask in the comments and we will answer as good as we can. 34. Broadcasting and Indexing Intro: Hey, and welcome to this new section. This is one of my favorites. This is about understanding broadcasting and advanced indexing in NumPy. So these terms don't mean that much now, but it definitely will after you finish this section. So in more detail, we'll learn how to become comfortable with what's called basic broadcasting. Secondly, we'll understand NumPy rules for how broadcasting is handled in this part out clearly lay out the precise rules of NumPy uses for handling this broadcasting thing. This will be really helpful. Thirdly, we'll work a bit with slicing for 2D areas. We've seen this previously for 1D arrays and the same principle carries over. We just need some practice. Instead of indexing by using single numbers, you can also index by using lists. Finally, we'll learn how Boolean indexing works. This would be an incredibly powerful tool in your toolbox and will really help you working with NumPy. As usual, we have an exercise set and in this exercise, we will work with monochromatic images. So monochromatic images are a great example of 2D arrays. Later in the course, I'll show you the usual colored images and how they can be represented by a 3D array. So working with images and basic image processing is really convenient when working in Numpy. So really hope this looks interesting and I'll start right on it in the next video. 35. Basic Broadcasting: Hi everyone. Now I'm in an empty you better notebook sheet, and I've just called it broadcasting in advanced indexing. So just to clarify, there will actually be no new functions or even attributes used in this sheet for the next couple of videos. Just because we'll be working with broadcasting and kind of under the hood techniques like NumPy uses and more advanced indexing features. So let us first just make a cell and of course import numpy as np. And we'll also briefly need the matplotlib library. So this is importing matplotlib dot pyplot as PLT. The first thing we'll talk about is basic broadcasting. And what is really means. Broadcasting is what happens if you try to do an operation seemingly on compatible dimensions. But NumPy just finds a way to handle it under the hood. So I wanted to first of all, just look at a few examples and then we'll go more structurally into this. So first of all, this one thing you've seen previously is to add constants, two vectors. Let's say that we have some x values. So let's make them from the linspace command. And let's say that they're from minus one to one. Let's pick 100 points. Then you can also take the y-values. And let's just say there are the x-values to the third power. Now, we can also just plot them with PLT. This is just the usual line plot. And here you can see it. So setup, we know want to add one to the, all the y values. And we could do it individually, but we can also just say add one. So what happens now is that we're actually adding a vector and this thing here with a constant. But what NumPy does is just to add a constant to each component in the vector. So you can see now that if I rerun it, pay attention here to the y-axis, then it shifted one up. So now it's centered at one here in the middle. And you can also do this concept by matrices. Let's first just make a five-by-five matrix consisting of sevens. So stimulated we have one of these commands called NP ones, which makes matrices with ones in them. First, make a matrix of ones. This is NP, and then should pass in a tuple, five-by-five. Let's just check out. Now I have my matrix are ones that I can know. Just multiply this by seven. So if I do that and run it, then the same kind of thing happens. I'm really multiplying a matrix with a number of seemingly not compatible. But what NumPy does is it just a broadcaster Southern all over the matrix. So that's why it's called broadcasting. It kind of stretches this to do it. And each entry, so I get 7 times 1 is 7, 7 times 1 is 7, and so on. I can of course assign this to a matrix of sevens. So here are two very simple examples of broadcasting and the interaction between a vector or a number, or a matrix and a number. This always works, but there are cases where it doesn't work. So let's say that we have a matrix plus a vector. And this is often not possible. So let's say that we take our matrix of 7's. Remember that this is a five-by-five matrix and we try to add a vector. So let's make it with a range with 25 elements. Now you can see that if you try to run this, they will not work, will get a value error saying operands could not be broadcasted together with shapes five-by-five and 25. So you can see that it's not always possible to make sense of this, but in some cases it is possible. So let's again take our matrix of sevens and then add to it and p.volve range. But now just do five. Here we can see that we've taken or matrix of sevenths and added 0, 1, 2, 3, 4. Emily, what's in here and done it on each simple row. So in this video, I just wanted to illustrate that broadcasting sometimes works and sometimes not resilient. Understand the rules of how this is being done in NumPy. You can also ask ourselves, okay, So this is one way to do it. You're stretching this np arange over each row, but it could also be done over each column. Why is it done over each row? Going into the second video about broadcasting, we have two questions. The first question is, when can we broadcast? The reason that is sometimes works and sometimes not? We also have a second question, which is which directions? All the broadcasting, they place them. So can we predict this before actually seeing the result and say we wanted to do it along the columns, could we change that in some way? So these are the questions we'll answer in the next video. 36. Broadcasting Rules: Hi, Welcome to the second video on broadcasting. In this video, I'll carefully explained the broadcasting rules in NumPy by going through a specific example first. So let's say that we have a matrix. Let me just make a matrix of zeros. And let's say that it has three rows and seven columns. So just to clarify, hair, this is three by seven in shape. And here we have a vector, this is np.array range. And let's say that it has all the numbers from one to seven. So in this case this is simply a vector with seven entries like this. So let's just print them out so we can see them. This is our matrix. And let me drew a line break here just to make it more clear. And we also have our vector Islam again, just add in a few line breaks. Something, maybe something like this. So here we can see our matrix and our vector. The question we want to answer is can we add matrix and this vector and make NumPy do some kind of broadcasting. So let's look at the rules. So the first rules is what I would call padding. And what this does is adding on to the left of the shape of the smaller and the array. So in our case, we have the bigger one which is seven by three, bigger because it has now two entries since it's a matrix. So number doesn't do anything to this one. But for the smaller one, just the 71, this is now transformed into a one by seven matrix. So the padding means that they are now converted to be of the same shape. It's very important to the ones that are added to the left is how numpy does it by default. Secondly, we have a comparison stage. So the broadcasting happens if a now we compare these two and comparing goes from the right. The first thing is either they have to be equal to 77, That's equal. Each slot, say each pair of entries are equal. So 77 are equal. Or we come to a pair where one of them are one. So in this case, yeah, that works out because seven is equal to men and 31 in that pair we have a 1, 2, it should be doable. So if it's clears this check, this is essentially non-price broadcasting rural than is possible to broadcast it. So if I try it out by just do matrix, simplest vector. And you can see that this works wonderful. And what happens is that the vector is broadcasted over each row. So that means that the vector is added to firstly this row, then this row, and this row. So to get some more practice, Let's do an example where it doesn't work. Let's call this non-example. So let's say now that we have, again our matrix. Let's again just zeros matrix, but let us do it with seven rows and three columns. Let me just write it here as well. So this is seven by three, and we have our vector. Let's do np.array range from 12 to 13. So this here has 12 entries. So let's just take a look at what happens now. In the first stage, we have the padding or the smaller one or padded out by ones on the left. So let's just write this thing here. Doesn't change at all in the first stage and just again becomes 7.3. But this thing here, so let's just align it nicely. This becomes 1.12 because once they're added to the left, that's the first stage. And the second one is comparison. And the comparison starts here and it already fails because in this step, three and 12 are not equal and neither of them are one. So this here is not possible. So they can't be broadcasts and intuitively learns no way to add this to this. That makes sense. So if you try to do this, you'll get a value error saying operands could not be broadcasted with these shapes. So let's example. There are cases we're broadcasting does not work just to the default one, but we have an idea of what say addition between a matrix and a vector should mean. And we can also enforce this in some cases. So to see this again, let's do the matrix and vector, so here. And then just a matrix of zeros and our students seven by three version for the matrix and for the vector, Let's do and build area range from one to eight. Now, just to clarify, let's see if this works. So this thing here is of course, seven by three vector here is just 7. So intuitively I have now a vector with seven rows and three columns, and I have a vector with seven entries. So it shouldn't be possible that I could simply just add these together down the columns. Maybe it's easier if I visualize this. So this is the matrix and this is the vector. So here we have the matrix. Should definitely add some new line here. Here you can see the matrix and here you can see the vector and should be possible for me to like take one at it here, take to add it here. So essentially doing it down the columns. However, if I check the rules. So first we have this padding stage were once they're added to the left of the smaller one. And you can now see that this is not compatible because here they're not equal and neither of them is one. The reason this is not working is simply because we added wants to the left by default. We could also manually add a 1, 2, right? So this would work. So let me see how we can do this. So what we can do is to take your vector and simply add a new axis. We're going to use np dot you access in this way. And let me just reassign this to vector. And now if we look at its shape, so now I run it twice. So let me just run this again. And then this. Now we can see that it's seven column one. So if we had started with southern common one from the beginning, they would both be of the same size. So there wouldn't be a padding stage, so this wouldn't happen. So if you just look here and this is perfectly fine because these two are equal and these 21 of them are one. So if you do this here, and now, we can do matrix plus vector. And this works the way we wanted to. So I really hope that's clarified broadcasting rules. So you're either in the case where it just works or in the case where it doesn't work for you, in a case where it doesn't work, but you can add a new access to make it work. It really depends on what you wanted. This can be really powerful tool for you when working in Numpy. Thanks, and I'll see you again in next video. 37. 2D Slicing: Hey everyone. So in this video we're starting on an advanced indexing. And first of all, I want to talk about 2D slicing. So we saw slicing way, way back when I talked about vectors. Let me just give you a very short recap. So let's say we have our vector and let's just do np array range. Let's do the first 10 numbers. So here we have our vector. So now we can do slicing. So let's take our square brackets and let's say that I want to start from the third entry and go all the way up to, but not including the seventh, like this, and like get this thing here. I can also specify a stack. So let's say here that I want to take steps of two, get 35. So the first is where I start, second is where I end. Third is the stack. The moral of this video is that the exact same thing works for matrices is exactly the same principle. So let's make our matrix. So let's make it with first doing an array range up to 25. So this gives me a vector. Let's finish for you. We can use the reshape method, and now we'll just pass in a five-by-five. So if we print this out, then we get this matrix here. So let's say now that I want to slice out sub-matrices, first of all, they want to try to grab the first four entries here, so that is 0, 1, 5, and 6 limiters make it into variables. Let's call it upper two-by-two corner. What I'll do is to do micro brackets and the comma, since I know I will need something for a roast and something for the columns. So for the rows all need the first two rows, so that's 01. So I can write this as everything up to but not including 24 columns, it's exactly the same. So I want the 0th one column. So everything up to but not including two. Let's print this out. You can see here that I get the upper corner. Let's try to do the lower corner. So it means that I want these four numbers here. So 18, 19, 23, and 24. So if you want to take a shot at this, just pause the video and try for yourself. So what I will do is to do the matrix square brackets. And I want to go from this row here. So again, we first split up into rows and columns. I want to do the rows first, and I need these two rows here. So that is starting at 0, 1, 2, 3, I going all the way out. And here it's exactly the same. So for the columns I want to sort it the third one and going all the way out. So if we just print this out and we get the lower corner. So it's a good idea to just play around and try to grab things. So again, let's do something where it's not exactly the same in rows and columns. Let's say I want 17, 18, 19, but also 22, 23, and 24 then split up into rows and columns. And for the rows I sold just want the last two rows does everything from three and onwards. And for the columns I want this, this, and this is everything from 2 and onwards. So here you can see that I get this. Let's just do a final example where we actually use the stack Islamic tried to make every other column. That means that I want this column here starting at 0. And all of these, I want to call them starting with two and all of these numbers. And I want to call them starting at four and all of these numbers, but I don't want the column starting at 13. So let's do our matrix. And always with these problems, you just try to separate them into rows and columns and do one of them each. So instead of having one difficult problem, you're left with two slightly easier ones. So let's first think about the rows. Are the rows. I want all of them actually, because for the chosen columns I need all the numbers. So for a row, I'll just do all of them. And for the columns I want to start at the beginning. I actually want to end at the end. So that's good. And I could potentially do this, but this will of course just give me everything. And that's not what I want. So I want to execute a column starting at 13. So I want to make jumps of two like this. That means I'll go from the start to the beginning, but I'll do it in steps of two. So if I now print out every other column or get Y1. So being comfortable with slicing is really good skill to have when working in Numpy. Just pick something inside here and try to reach it by using slicing. Not every sub-matrix here can be reached very easily with slicing. We'll talk more about this in the next video, where we will use lists and what's called a boolean indexing to handle this. So when you're ready, go ahead and jump to the next video. 38. Advanced Indexing: Hi and welcome back. In the last video, we talked about slicing in how this is a great tool for extracting submatrices of a given matrix. But not every sub-matrix can be extracted in this way in an easy manner. So let's take a look at our matrix here, CIDR. We want to extract this row, this row, and this row. So that means the one with index 0, 1, and 4. To do this with slicing is a bit complicated because you don't want all of them, but you don't have this kind of regular steps you can take all the way. A different way of indexing is what's called indexing with lists. So what you can do then is to do our matrix, but inside here. So what you can specify here is not just a single number or a slice. You can also specify it lists. So I want to specify that I want the 0th row, the first row, and the fourth row like this. And for the columns I just want in these specific roles, all of it. By doing this, I get exactly what I want. So this is a good example if you want to extract a certain number of rows or columns, but they don't come in this uniform step fashion. So just try this around a bit. I don't really have much more to say about it other than it can be really useful. Secondly, we also have another method of doing advanced indexing, and that's what specifically called boolean indexing. So what is boolean indexing? Some videos ago, Cindy told you that if you have a matrix and we can use, for instance, a comparison operator like greater than and say, okay, let's take matrix greater than 15. And what you get back is done a matrix of Boolean values. Here you can see you get false values all the way up to the one corresponding to 16 in the original array. There we get true, and this is pretty neat, but what's even better is that you can extract values based on this Boolean matrix. What I can do is to just the matrix. And instead of passing in lists or slices here, I can pass in this expression here. What will happen then is that what will be extracted as everything that corresponds to true. Can see now that if I run this, I get 16, 17, 18, 19, 20, 21, 22, 23, and 24. So every number in the original matrix that had a value bigger than 15, this is incredibly useful. So if you look now at the number of dimensions here, and you can see that this is a one-dimensional structure. So what happens is whenever this condition is true, these are essentially picked out and then it's just flattened to a one-dimensional array. Let me just remove this and it is a great way to extract information. So if you actually want to specify more than one condition or a soul ways of doing this say that I want now in the elements greater than 15, but also I only want those less than 20. What I can then do is to do matrix greater than 15. And then I can use ampersand symbol matrix less than, let's say less than or equal to 20. If I run this just as it is, it won't really work. The reason for this is that I need to use parentheses here. So in parentheses around each condition. So you have matrix greater than 115 and also matrix with less than 20. For do this, I get all the numbers between 15 and 20. So the ampersand here illustrates an AND operator. And you also have an OR operator illustrating plaguing either one or two of the conditions for the OR operator is indicated by the pipe symbol. And of course here it just gives me everything because every number in this matrix is either greater than 15 or less than 20. Let me change this back to an AND operator was take our matrix and say I want the elements greater than 15, or I want the elements that are less than seven. Here we can see that I have 0, 1, 2, 3, 4, 5, 6. Everything between seven and 15 is now excluded because they don't satisfy either of these conditions. This is a really powerful way of extracting information from our matrices. And you'll see them used quite a lot in the exercises. Thanks, and I'll see you again in the next video. 39. Exercise Set - Monochrome Images: Hey, and welcome to this next exercise, set. This is all about working with monochromatic images. So a monochromatic image is an image with a single color channel. This is in contrast with what you typically think of as colored images, which has typically three color channels, namely red, green, and blue. The fact that monochromatic images just have one color channel makes them ideal to model as 2D arrays. So I'll give a bit more explanation about this in the beginning. Here you have a cell you that usually run without modifying this as importing NumPy. It's also important for SK image data sub-module. The reason for this is to get a predefined image. Additionally, you should also run this cell. You will specifically get that image, which I will call it camera. As you can see, you can use the function plt.plot. Show, short for image, show you show the image. So here you have the image camera, which is here you can see a 512 by 512 image, a man with a camera. And then the exercises goes as follows. Firstly, you're just going to check out the image, see that it's actually a NumPy array and find its shape of the NumPy array. Secondly, you're supposed to inspect the values of the image by printing out the maximum and the minimum values. The third exercise is about cropping the image. The fourth exercise is about removing specific rules. And the fifth exercises about changing the intensity of the image. The six exercises a bit of a challenge, and it's about inverting an image. So we can do a lot of the basic image processing with NumPy, give this exercise has an honest shot. And of course, if you're stuck and you look at the exercise solutions. 40. Basic Linear Algebra Intro: Hi, and welcome to this section which is all about how to do basic linear algebra in NumPy. So in this section we are going to learn how to do basic linear algebra in NumPy. And the fixed we are going to learn is how to compute the dot product and the cross product. So to be able to perform more complex linear algebra, we are going to learn how to import the library. We are going to learn how to find the determinant and the trace of a matrix. Also, we are going to learn how to invert a matrix. And finally, we are going to focus on how to solve a linear system using numpy indexes. I said we will focus on how to solve standard linear algebra exercises using NumPy just to get some practice doing it in NumPy. 41. Basic Linear Algebra: Hi and welcome to this video on how to do basic linear algebra in NumPy. Before we begin, remember that we have, AS always important the NumPy package as np. And for simplicity, I've also taken the liberty of defining two vectors, which I'm going to refer us to the first vector and the second vector. And also I have defined two matrices, which I'm going to refer to as the first matrix and the second matrix. So the first thing I want to convince you about is that we already know some linear algebra from before. So for instance, we know how to do vector addition. This is just by using the plus, like this. So here you can see that all the entries are summed together. We can also do entry wise matrix addition plus the second matrix. So here we have the result. We can do vector subtraction, matrix subtraction. And finally, we can do scalar multiplication. So for instance, we can take and multiply all the entries by two. This is simply two times the first. And we can take a matrix and multiply all the entries by two as well, like this. Okay, so let's start at the first new operation we have, namely the dot-product. So let us quickly recall what the dot-product is. So first of all, the dot-product is just multiplying all the entries together and taking the sum. For instance, here we have the dot product between the vector 1, 2 and 4 and the vector two minus 19. And what you get is 2 times 1 plus, minus 1 times 2 plus 9 times 4. And if you just simplify the expression, what you end up with is 46. Some facts about the dot-product is that the dot product is the product of the length times the cosine of the angle between the vectors. So in this case, the angle between the vectors are 0.5603 and so on. And the dot-product is exactly this product. And the second thing is that the vectors are orthogonal, meaning that the angle between them are pi divided by 2, the dot-product is exactly 0. So you can see this from the expression above here. If the angle is Pi divided by 2 here, and you take cosine of it, you get exactly 0. So let's move back to Jupiter notebook. If I want to take the dot product between two vectors, I use np dot, dots, and then I can take the first vector and the second vector. And when you take the dot product, you get exactly first is six. So as an example of using the dot product, we can make a function which tells us if two vectors are orthogonal. To define a function, we use the def keyword and then the name of the function. Inside the parentheses we have the input. So let me call it vector 1, come back to and then end by a semicolon in Python. And in here we write what the function is going to do. So what I wanted to return is true if the vectors are orthogonal and folds if the vectors are not a funnel. A very short way to do this is np dot dot liked 12. And then ask if this is equal to 0. And this expression here is true exactly when the dot-product is equal to 0 and false if it is not equal to 0. So let us from the cell and let me now try to use the function. So let us take first vector, second vector, like this. And now we see that the function gives out false because the vectors are not orthogonal. This was already known for us since the dot-product here is 36, which is not equal to 0. This was everything I wanted to go through in this video. In the next video we are going to go through the cross-product and the length. So see you again. 42. Cross Product and Length: Hi and welcome back. Before we begin, I have imported mind NumPy package, and in the top of the document, I have defined these two vectors. And I have defined these two matrices, which I'm going to use throughout this section. So let's start with a quick recap about cross products. The first thing I wanted to state above the cross product is that it only works for three-dimensional and two-dimensional vectors. I would love to find the cross-product in this video because everyone has their different way of defining it. One way is to take the determinant of this matrix where the first vector is here, second vector is here, but it's not the only way of computing it. So let's leave it at that. So the one thing that I'm interested in is that NumPy can do cross-products for us and that it satisfies some properties. For instance, if you take the length of the vectors which the cross-product gives out, then you get the length of the first vector, the length of the second vector, and sine of the angle between them, which in this case is approximately 0.56 oh, free. The second thing is that if all the vectors are parallel, the cross product is 0. This is because then sine of the angle 0 is 0. So it necessarily need to have length 0. And the 0 vector is the only vector with length 0. So the first thing I want to state is that the cross product between two vectors are always on each of the vectors. So for instance, 22 minus 15 is on this vector and this vector. So let's move back to Europe in the notebook. So the wave to do a cross-product is with a function and P dot cross. And we can take in two vectors, for instance, the first vector and the second vector. And you see the resulting. So you can also do the cross-product for two-dimensional vectors, but it works a bit differently and it's not that useful. But just to see how it works, we can take arrange two and np dot arrange one comma free and just take the cross-product between 0112. And what we get is the 0 dimensional array consisting of the number minus one. But as I said, taking the cross-product between two-dimensional vectors is not as useful as doing it for freedom mentions that what we can do now is to check some of the identities I mentioned in the slides. So let's name the vector cross is equal to np dot cross of first vector, second vector. Like this. And let's try to take the dot product between the first vector and a cross-product. So what we expect to happen is that the cross-product is a phenomenal on the first vector, and hence we would get out 0. So let's run this cell. And that is in fact what's happened. We can also do it with the second vector. And again, we get 0. To do more complicated linear algebra, we will need an under package of NumPy, namely the library. So what we want to do is to from numpy import the library Linux and run this cell. So now we have imported a lot more linear algebra functionality. So for instance, we can now do the length of a vector. So remember that the length of the vector is just taking the square of all the entries, summing enough and then taking the square root. So in this case, we get 1 squared plus 2 squared plus 4 squared, and then the square root, and under the square root we get 21, and as a result, we get the square root of 21. You can define the length of a vector entirely by using the dot-product. If you take the dot product of a vector with itself, you end up with the length squared. So the way to take the length of a vector is to use from the note, use the pnorm function. And then we can take norm of the first vector. And here we end up with 4.582 and so on. And this is exactly the length of the first spectrum. We can also take the length of the second vector. And we get that the length of the second vector is 9.2736 and so on. The non-function can also take in matrices. And what it does is to take all the entries to the power of two and sum them and then take the square root. So for instance, if I take the norm of the first matrix, I end up with 12 comma six something. So let us use what we have learned to do an example. So what I want to do is to take into vectors and give out the angle between the vectors. So again, we use the def keyword to define a function. And I want to call my function angle because it gives us the angle. And it takes in vector 1 and vector 2. We know that the cosine of the angle is the inner product between the vectors divided by the product of the length. So let us write this by cosine angle equal and P dot, dot vector one, vector two. And then we need to divide by the length. So Linnaeus ge dot norm times then dot norm. And finally, we need to take the cosine inverse and return that value because this will be the angle between the vectors. So we want to return and p dot r cos of the angle. So let's run that. And now I want to find the angle between two vectors. So let's right angle first vector, second vector. And run this. And what we get is that the angle between the first, second vector, you say, well point 56 something. This was everything I wanted to say in this video. In the next video we are going to go through and matrix multiplication. So see you then. 43. Matrix Operations: Hi and welcome. In this video we are going to go for a matrix operations. So remember as in all the other videos, if we go to the top, we have imported numpy as np. We have defined two vectors, which I call first vector, second vector. And finally, and most importantly for this section, we have two matrices which are called first matrix and second matrix. So let's go down again. So one of the first operation you learn about when you're doing matrices is the matrix product. So since it's a product, you can think that you could use the multiplication symbol, but this symbol is already taken. So if you try to do first matrix times the second matrix, what you end up with is the first-century times the first entry, the second entry times the second entry. So you get for the first entry times the first entry, which is 0, and so on. So you can get the entry wise product, which is not the same as the product between two matrices. Let's quickly recall how the matrix product is defined. So if you take the matrix product between a matrix and vector, then you end up with kind of the vector folding over the matrix. So I mean that you'd get the first entry here times this vector. The second entry here times this vector. And deferred entry here times this vector here. And then you just sum all the actors together. So in particular, you get 1 times this vector here, plus two times this vector here, which you can see here. And four times this vector here, which you can see here. And if you sum it together, you end up with this new vector here. So if you tried to do matrix multiplication between two matrices, then you end up with a definition which is a myth more complicated. But essentially what you do is matrix multiplication with this vector here and this matrix, and this ends up in the first column. In the second column, you end up with a matrix multiplication of this vector times this matrix, which end up with this result and inferred column, you end up with the matrix multiplication of this factor times this matrix. So if you do not remember, you can probably Google it or look at Wikipedia to see the full definition of the matrix product. One thing to note about the matrix product is that we have a very special matrix called the identity matrix. And what the identity matrix does is essentially nothing. So if you take the identity matrix, multiply it by a vector, you end up with the same vector. And if you take the identity matrix and multiply it by a matrix. You end up with the same matrix. So the identity matrix does nothing and it's very important matrix. So let's move back to you open a Notebook. So if we want to do the matrix product, we will use the at symbol. So for example, if we take the first matrix and then we can rate at and then the first vector. And the result is this vector here, which indeed is the matrix product between the first matrix and the first vector. If you want to do the matrix product between two matrices, it's the same deal. So we end up with this matrix here, which is the matrix product between two matrices. So one thing I should probably mention is that there is another notation for doing matrix product and that is np dot mat multiplication. So if I take first matrix comma second matrix and run this cell, I end up with the same result. So these two ways of doing matrix product, totally equivalent. And essentially this at symbol here is just a short way of calling this method here. So we talked a bit about the identity matrix. So it would be nice to actually write it here, and we have seen it before. It's this I function here. So here you get one set the diagonal and 0 everywhere else. And if we try to do the matrix multiplication between the identity matrix and the first matrix, we end up with the first matrix. And the same thing if we do matrix multiplication between the density and the first vector, like this. Okay, so let's move on to make tricks powers. If you want to take the product of a matrix like four times, for instance, what you can do is first matrix and then add symbol first matrix, first matrix, and finally first matrix. And from this, but luckily there's a simple way to do this so that we don't need to repeat this first matrix as many times. So the way to do it is to use the blend our module. And then a matrix power function. And then taken the first matrix and then the power, you want to erase the two, so in this case four. So here we get the same result. So if the code does not run, remember that from the previous lecture, we imported the module linux from the NumPy module. So if your code does not run, import this module and it should run. So the final thing I wanted to talk about in this video is how to transpose a matrix. So if I have my first matrix, then the transpose of the matrix is reflection about the diagonal. So the way to take the transpose of the first matrix is to write first matrix dots and then the big T for transpose. And you see now that D2 and a free here has been switched. The 0 and the minus 3 last pin switch from the original position and then minus two and the five has been switched from their original position. However, the diagonal remains the same. Again, this is just a short way to write first matrix transpose. So I forgot S here, so let's run again. And you see that this way to transpose it and this way is identical. And this dot t notation here is actually just the same as calling this function. So see you again in the next section where we are going to learn how to solve linear systems using numpy. 44. Solving Linear Systems I: Hi and welcome. In this video we are going to learn how to solve linear systems using NumPy. So the first thing I wanted to go for is somewhat attention to fear, which is how to compute determinants in NumPy. So determinant of a matrix gives you a way to tell if the matrix is invertible or not. So if the determinant of the matrix is 0, then it's not invertible. And if it's non-zero, then the matrix is invertible. So remember that you can only take the determinant of an n by n matrices. The determinant, you need the linen module. So remember that previously in our document, we have imported the linen molecule from numpy. And up the top of the document we have imported numpy and additionally defined some vectors and some matrices. So from Linac, we are going to use the determinant function and let's try it. The determinant of the first matrix. Here, the exact values should be 34 if you compute it, but we get 33.991. We have that 34 is not equal to 0. So this means that first matrix is invertible. We can also test the second matrix. And again we get 28 and then a lot of zeros and one here, the exact number should be 28. So again, we get an approximation and not the executive determinant. So let's also try with a non invertible matrix and see what happens. So let me define the array consisting of one comma two comma 0 and then minus two comma ten comma free. And finally, minus 3 comma a comma free. And I know that this matrix is not invertible because the middle entry here, so the MIT vector is just the sum of this vector here plus this vector here. So we have that two rows are not linearly independent, which means that the matrix is not invertible. So let's try to take the determinant. And let me also correct the spelling mistake here from the sun and then run this cell. So what we get out is this very, very small number here, which is essentially 0, but we don't get 0, we get an approximation of 0. So this is a bit dangerous that you do also get 0, but not exactly. But if you test and actually compute the matrix, you get 0. Additionally, you see all these mistakes here. I'll kind of rounding mistakes. So to get 0, what you can do is to round the number with np.array round and let me have 10 decibels and just run the cell and now we get actually 0. But again, this fact that when you take the determinant, you do not get exact numbers is kind of a returning theme. Okay, So now we have gone through the determinant which checks if the matrix is invertible not so let's actually find this inverse. And to do this, we need again the linolenic module. And the function we are using is in, which is short for inverse. And let's try to invert the first matrix. Run this cell, and here we get an approximation of the inverse. So now we can multiply this with the first matrix and see if we get the identity. Again, this is only an approximation of the inverse, not the exact inverse. So what you get is 1, 1, 1 at the diagonal, but here you get very small numbers of diagonal. So these numbers here are very small and should be 0. But since we are not working exact, we get just almost 0. If we want to get 0, we can use the np dot round or every round, which is the actual name. And let's take 10 decimals and run the cell. And now we'll get the identity matrix. Okay, So we have a matrix here which is non-invertible. So let's try to take the inverse and see what happens. So what you want to happen if we run this cell is kind of getting an error or getting some approximate inverse of something. But if we try to run this cell, so what you end up with is a matrix with really big entries. So here you get ten to the power 15 and minus 10 to the power 15 something and so on. So since we know this matrix do not have an inverse, you might wonder what is happening here. So if it has an inverse, numpy stills try to find one. And what it actually finds is something that has really big entries, approximately infinity in NumPy terms. So my goal here is to just explain that you should be skeptical of really small entries and really big entries for Kiersten, they are either non true, like here, you do not have an inverse, so it makes no sense of actually giving one out. And if you get very small entries, they should probably be 0, like in this first example here. 45. Solving Linear Systems II: So the final theme here is actually getting to solve linear systems. So let's go quickly through what a linear system is. So a linear system is a system which is a matrix times some unknown x equals some vector B. Here we have an example where we have this first matrix here, times unknowns and then equals this matrix here. So this equation here appears very often. For example, if you want to balance a set of chemical reactions, you end up with this sort of system here. So there are three things which can happen when you are talking about linear systems. One case is that it has a unique solution, which happens if this matrix here is invertible. Otherwise it has either no solution. This can happen that your system is not solvable or it has infinitely many solutions. So these are the three cases. Okay, So let's move back to your printer notebook. Let's start with seeing what happens when we have a problem with one unique solution. So let's say that we have a system with the first matrix times some unknown vector equals the first vector here. So let's try to solve that system. So then from Linux, we use the sole function. And we have the matrix first comma and then first vector. And let us run the cell and see what happens. And then it returns this vector here. So let's make a new cell and see if this actually is a solution. Then matrix multiplication. And let me just copy this line here and run the cell. And then I get 1, 2, and 4. And if we move up and see what the first factories, then we see that the first vector is 1, 2, and 4. So it is indeed a solution to the problem. So let's move on to see what happens if the problem has no solution at all. So then we, from Linac, we tried to solve. And then we put in a system which have no solution. And for instance, we can do non-invertible. And then, first vector and run the cell. And I have a spelling mistakes either here or down there, but let me just copy this line like this and run the cell again and we get the solution even though the system has no solution at all. But again, you see that the numbers here a very, very big, which means that we should be skeptical of what we get out here. So let's see if it actually solves the system, which it shouldn't. Just making a new cell and then taking the non inverse matrix times this vector I get out here. So let me just copy it from the cell. And what to get out is the array 1 000, but this is not the vector. So this is not equal to the first vector here because that was one to four, which means that this solution here does not make sense. So again, if you have something that is very big, then some alarm bells should go off in your hand. So the final type of problems is the problems with infinitely many solutions. So to make the system, I will need a new vector, which I'm going to call for defector. And this is simply going to be the area consisting of one minus two, minus three. And now I can ask for the solution of the non invertible matrix comma and then the third vector. And then run the cell. And now I get to this area here, which seems reasonable, but I do not get all the solution. I only get one of them. And let us check if this is actually a solution. So we have the non-invertible matrix and this vector here. And let's run this cell. And what I get back is one minus two minus three, which was exactly this vector here. But again, this system here should have infinitely many solutions and we only get two out one of them. So this was everything I wanted to say about basic linear algebra. We will do more linear algebra at the later point. But for now, you will have some practice exercises to solve to get it into your fingers. 46. Exercise Set - Basic Linear Algebra: Hi and welcome to this video which is about the exercise set seven. So the access asset is about doing basic linear algebra using NumPy. So first of all, we are going to import the sub-module, which is called linoleic to do simple linear algebra. So for example, we are going to define two vectors here. And the question we want to answer, or if they are parallel or if they are orthogonal. And the next exercise is to find the angle between the vectors. And here we are going to define some simple matrices. And we are going to use non pi to define the product. So the matrix product between the matrices and also dismissed tricks product here, which you essentially cannot do by hand unless you want to torture yourself. And here we are going to do it the transpose of a and then compute this matrix product here. And exercise 4 is an application where we are going to balance this set here of chemical equations using numpy. For simplicity, I have written out what this here means in the form of linear algebra. So you have a matrix, an unknown vector, and an answer vector here. And first of all, you are going to figure out if this matrix is invertible, then you are going to set this stuff will be here equal to one, or just remove it and find a solution to this system of equation. And finally, you will end up with a solution which does not make a lot of sense. And basically you are going to find a whole number solution by just starting to multiply with whole numbers. And then the final exercise is about writing out the balanced equation with what the values x, y and set actually is. And value w, which you'll find in this exercise here. Okay, so good luck with solving exercises and you can find the solution. And you could find a solution to the exercise the same place you find the exercises. So see you in the next video. 47. Understanding ndarrays Intro: Hi, and welcome to this section. We've previously seen 1D arrays mean in vectors and 2D areas, meaning matrices. In this section, we're going to talk about ND arrays. This is a general structure that NumPy uses in practice. We'll mostly be looking at 3D arrays, but the principles would give can be easily extended. So as I said, this section is really about working with an understanding the general N-dimensional array in NumPy. Or specifically, we're going to learn how to become really comfortable with the high-dimensional arrays. We're going to be able to slice them, do Boolean indexing, and also use aggregate functions on specifically 3D arrays. The reason for doing this in a 3D arrays, three arrows. You can see the general principle, then we can still keep it reasonably concretes. We will also work with colored images as a great example of 3D arrays will also understand strides of a general and the array. This is one of the more fundamental and theoretical aspects of NumPy, is really nice to understand. The recent strides are great to understand, is that then you can really explain why slicing and transposition a really cheap operations in NumPy. And as usual, we have an exercise that were previously been working on monochromatic images. But now, as we can deal with, three-dimensional arrays were in for colored images. So this is what we'll be working with in this exercise sets. So I can't wait to tell you all about this. So let's jump into the video. 48. Making Higher Dimensional Arrays: Hi and welcome back. For the next couple of videos, we're going to try to understand the NumPy ND arrays. So we've seen previously at vectors meaning 1D arrays and matrices meaning 2D areas. And now we're going to look at a general ND array. So first of all, of course, let us import numpy as np. What we're going to talk about first of all is simply just making the ND arrays. So let us start with three-dimensions. So let us first make 3D list. Let me just make a variable here called 3D list. And now I need to be a bit careful, so I open the brackets and here I will have essentially two matrices. So inside hero build a new two-dimensional lists and the same inside here. Inside here I will have a new bracket indicating the first row, so this is 12. And then I have a new row, 3, 4. Then I move over to the next two-dimensional lists. Very first have a row, let's call him 56, and then finally a new row, 78. And I was lucky. There is no mistakes so far. You can see that this is pretty tedious. But in any case, what I can do now is the same we've done previously in the convert this into a NumPy array. So let's make a new variable, let's call it three dimensional array. So this is again the np array function, and I simply pass in my list to see that this works and to see how it looks, let's just print this out. And here we can see it. So this is what's called a 3D array. And the easiest way to think of a 3D array, at least for me, is to think of them as a list of 2D arrays. So here I have a 2D array, meaning a matrix, and here I have another one, and they're essentially listed down. So I get a new dimension from this listing. Before we move on, let me just say that you can convert back. So if I want to convert AC to a less than what I simply do is to take my three-dimensional array and then I used it to list method. And then I can reassign this to, let's say, back to our list, bit verbose here, but I think you get what I mean this year old and be a list being exactly the same as this one, as you probably realize for ND arrays with dimension higher than two, you don't typically write them in manually. You'll typically important from a file, this can be a CSV file, meaning a file of comma separated values. Or it could be an Excel sheet, or it can also be important in image, will look at importing images in a few videos. Later in the course, we'll look at the other types of files I've just mentioned. So let's jump down to indexing. And again, the moral of the story here is that everything essentially works the same. Just need to be a bit careful. So we have our three-dimensional array. So here is our array and say I want this element here. The first I mentioned I will specify is essentially which of these matrices I will go into it that will be the first access, in this case is the first of the matrices that gives me a 0. Secondly, once we're into this matrix is again the same as rows by four columns. So for rows I want this one as the second row, so it has index one. And for the columns I just want to first column. So if I do this, I get a number three. So let's do one more. Say that I want this number here, the number six. Then I want the second matrix have index 1 in the first position and the two lateral indices here that will indicate where I'm going inside this matrix here. So I want the first row, so distribute turned to a 0 and I want the second column to distribute have index 1. And this is where I get to six year. So I really encourage you to just pause the video and try to grab a few numbers. No amount of watching other people index will give you the same experiences. Just indexing for three minutes yourself and just getting comfortable with the system. Although 3D areas might seem a bit intimidating in the beginning, it's really not that abstract if you've tried working in Excel documents previously have rows and columns. So that's 2D. Do you also have different sheets? So you can select Sheet one, sheet to sheet 3 and so on. Essentially the same we are doing here. We have a matrix, we have another matrix, and we can switch between them by varying this first index. As I told you previously, we'll also look at pictures and a few videos. And images are very often handled as three-dimensional objects because they have both position giving us two dimensions, but also a dimension for color, giving us a three-dimensional total. So of course, if we want to, we can assign this. And remember, this is the same as previous, nothing has really changed. We can also check out the shape of an array. And here you can see that the shape is two times, two times two. That's really a higher-dimensional array. And working with higher than two-dimensional areas is religious and exercise and extending all we know previously to this new setting. So we have a lot of methods for making arrays. I don't want to go through all of them because then I will just rehash everything we've said up to this point, a, just for a quick example, if I want to make a four-dimensional array, what I can do is to do the zeros function. That stint I told you about where you can pass in a tuple here specifying each dimension. So say I want 3322, this runs fine. Let's print this out. Already. We get a rather large output. So here you can see all of this stuff. So what this is indicating that the first three gives us one of these groups. So here we have 1, 2, 3 groups. Say I choose the first group, I'm here and I have three matrices. Say I choose the second one, that I'm inside this matrix. And again, the last two positions specifies rows and columns. Almost everything we've done previously just extends to this new setting. It's not really that much more complicated. In the next video, I still want to repeat a few things. So I want to repeat slicing and boolean indexing and aggregate functions for higher-dimensional areas. Just see that they work the way we suspect them to and get some good practice when you're ready, just jump into the next video and I'll see you there. 49. Slicing and Aggregate Functions: Hi and welcome back. In this video, we'll just illustrate the things we've already kind of done previously. But now in the setting of higher-dimensional areas, meaning typically at three and four-dimensional arrays. So let me actually stop a repeating some stuff we did way back when I talked about random numbers. So I can make a three-dimensional array of random integers. So if you recall previously, what I had to do was to make a random number generator and initiate this. This was to make just a vector of random numbers. But now I want to make a three-dimensional array of random numbers. So what I can do is do np dot random and then default random number generator or just autofill it here. And then I can make my array. I'll say random number generator dot integers is a method we considered in here. I should pass in integers from 0 to 10. So 10 is exclusive and I need to specify a certain size. Let's say 36 is still, just gives me a vector. That what I've done can do is to reshape, it seems, showed you how to do this for matrices and I can reshape it three dimensional array. So I wanted to have shaped four comma three comma three can notice that if I multiply these three numbers, I get precisely 36. If I run, it should work. And I can also now print out the array. This is what it looks like. Let's say now that I want the first two rows of the first matrix and I go into my array. And for the slicing, I just need to again specify each of the dimensions carefully. So in the first dimension, I actually just wanted just the first matrix. So that gives me a 0. And I should have a few commas here, and here is the rows, and here is the columns. So in the case of rows, I want the 0th row and the first row. So one way I can write this, for instance, is from 0 all the way up to two. I write too because the second one is exclusive. So this will just give me 0, 1. Finally, for the columns, I actually just want all the columns. So I can just write a colon here and check, I get this out. This is precisely what I wanted. Let's do one more together. Say that I want into this third matrix. I want the first column here, one starting at 2, third column starting at seven. How can I do this? Let me just erase this and start again. So I went to third matrix. So this is the matrix with index 0, 1, 2 gives me a two. Now I essentially again reduced it to a two-dimensional problem and this we can solve. So for the rose, I just want all of them. Write a colon here, and for the columns, I want the first and the third. So one way to do it is to specify a list of 13. And of course I get an index error because I always forget that number comes from 0, so that should be from 0 to 2. And here we can see that I get these two columns. This is one way to do it. Alternatively, I could just use the slice mutation we talked about and just say do steps of 2. This gives me exactly the same elements. I really encourage you again, just pause the video and just try to fetch a few rows and columns and see that this works fine. This is basic slicing. And we also have a boolean indexing. Say no, that I just want to go into this whole thing and change everything that is eight or higher, 230. What I then do is just grab my array and just say, whenever my array is greater or equal to 8, they'll just simply set this to 30. And if I now again print out my array, you can see now that everything that was either eight or nine previously is now 30. Finally, I want to just briefly mentioned aggregate functions. Aggregate functions or exams, or means we do either along an axis or the whole thing. Easiest thing is just to do. Okay, let me take my array and just do the full sum and printers out. And this gives me a single number summing all of this together. This is very short and sweet, but it's not typically what you want inside the sum command, I can specify an axis and if I specify that to be 0 and as was, Check this out, I get a matrix back. So the actors I specify is essentially the axis that gets compressed. So in our setting, when I specify axis equal to 0, what will happen is that this is the axis that I think it was listing these matrices. So the sun will take this number plus this number, plus this number, plus this number, this gives us 33 and we'll inserted first. You don't need to specify this first axis. Of course you can specify different ones. This will give you different structures. So for instance, in this case, if I take Ax is equal to two, that means that I'm considering the columns here. So now this plus, this, plus this summed, this gives us 36 and so on. So again, I just encourage you to play around with this a bit, whether you're doing the sum function or the mean function or the standard deviation. All of these works for the higher-dimensional arrays. In the next video, we'll have some fun and important image, and we'll manipulate that image based simply on what we already know from NumPy. So thanks, and I'll see you again in the next video. 50. Colored Images: Hi. So in a previous video, I told you that we're typically not manually making three-dimensional or four-dimensional lists. In fact, one of the common ways of getting three-dimensional areas is through images. So images have both horizontal and vertical direction, but they also have colors. This makes them ideal, the model with three-dimensional arrays. So let's get some images into this. So let's bring in an image. What I will do is to go into the package as KI major, which is short for scikit image. I'll import data. This is just to get a predefined image that's in the scikit image library. If you have the Anaconda distribution, then you should also have this library installed. This is for dating the image. You can also find your own image on the web and import it into your notebook using several different libraries. But I'll just use a basic standard image from the data sub-module of the scikit image package. Additionally, to see the image, I will import matplotlib. We've seen matplotlib previously for just making scatter plots and barcodes and so on. But here is just for showing the image. Let's run this and it seems to work fine on make an image of a cat will go into the data sub-module and use Show, see, I think Chelsea is the name of the cat. So once I run this, we can see that it works. And now I can use the PLT and then the method I am Show, which is short for image showing. So if I pass in the class, are getting a really nice picture here, even though this is a really cute cat, is actually just the array. I'm really sorry Chelsea, but you are just an ND array. So I can print the cats shape. Here. You can see that it has 16353003. So let's look at the image. You can see here that it goes from 0 to 300 and this is the rows. It goes from 0 to 451. So this is the columns and a three here represents the RGB colors. Let me just write this down. The first two are precision, and the third is r g b color. So a common conventional images is to represent them using RGB, meaning red, green, and blue. So the first entry here represents the amount of red and each pixel, the second represent amount of green, and the third represents the amount of blue in each pixel. Say first of all that I only want to extract the red from the picture and then I make a red cat. Actually can remember very mentioned this in the beginning of the course. But in any case I know I mentioned views versus copies. So this will make a new copy of the cat and then assign this to red cat. In that way, I can modify the red cat without modifying the original cat. So this is just NumPy stuff so I can start to do slicing. So what I want to do is just extract a red soil. Simply set the green and the blue to be equal to 0. So I'll go into slicing mode. I'll pick all the rows, all the columns, and one, remember that red has the index 0, green has a index one, and blue has index two. So this gives me all the green stuff. We'll just set that to 0. And I'll do exactly the same thing for the blue stuff, everything that has green and blue, and the picture is now set to 0. So essentially removed all the green and blue color from the picture. So if I now do plt.plot image show and do my red Cats. And you can see here there is only the red part of the image that's left. So you can play around with the colors like this, but you can also do is crop the image. Again, I'll work with the original image. A basic cropping thing we can do is a bit known as 300. 451 would in many cases be more easy if it's 450, because then this direction is 1.5 times this direction. So how can I make this 450? What I need to do is you don't remove the last column here. This is really simple. And make a new variable remove last column. This is my cat and I want all rows, four columns. I don't want all of them. I want all of them except the last ones. I can write it like this, but not including the last one. And I want just all the colors. So once I run this notice will give me a new picture, essentially having the correct shape. So if I write print, dot, remove last column, due its shape, then you can see that it has the correct shape. I don't want to show it again because you can hardly tell the differences are only removed. One Pixlr column with now has the correct dimension. So I could do more extreme crop, just cropping out, say, the left eye. So I can just try to gauge here essentially what I need from both the rows and the columns. And when I try it a bit, then essentially what I came up with was to go into my cleft and drew from 80 to 150. This is in the row, so you can see 80 stories like here, 150 is here. And for the columns, I ended up with something like 120 to 220. So I can call this focus on the eye. And this I can plot. So it should be focused on, I just fix this here and run it. And here you can see just the eye. There are actually plenty of well-developed libraries that deal with image processing. This is just to show you that you can do this manual with NumPy if you want to. It's really just a nice excuse to get to look at nice cat pictures and also deal with a bit of cropping and slicing. So say now that I want to do some color modification, we did it previously, but just extracting all the red, we can do it a bit more nuanced. Let's say I make a new variable called copycats, which is of course cats dot copy. Now I have something new I can work on. So now I want to do a green shift. What I wanted to say that everything that has more than 160 should be just completely set to green. And I can do copycats. And this is a boolean indexing. So I want to access the things where the red stuff is greater than 160. Recall that the last one is RGB, so red is 0. And I want to just set this to be completely green, so that should be 0, 255 and 0. So RGB values goes from 0 to 255. So this is 0 red in it, All the amount of green and 0 blue. Again, let's show the image. And here you can see it. So everything that had a reasonable amount of reading that has been converted to complete a green. As a final minor thing, we can transpose the image. So let me just do it inside the PLT image show. So I want to take the cat and I want to transpose it to use the transpose method. Does genitalia about briefly. And the problem now is intuitively I have a three-dimensional areas. What exactly means transposing? Well, for higher-dimensional areas, I can pass in a tuple specifying how I want to transposition to take place. So I have a tuple here. What I actually want is that the first two-dimensions swap, namely the columns and the rows. But I don't want any swapping with the colors to specify that or write 1, 0, 2. This means that the two should be in the same place as it is at a 10 should essentially switch places. That is why I am writing 10 instead of 01. By doing this, you can see that the image gets transposed. Thanks, and I'll see you again in the next video. 51. What are Strides?: Hi and welcome back. In this video, I'll discuss more theoretical concept known as strides. This could have been discussed for quite some time now, but I've postponed it a bit. This is a bit more on the technical side. So let me try to explain this. Say I have an array and strikes as a concept for two dimensions and three-dimensions and really all dimensions. So I'll just do a two-dimensional array to make this clear. So let me make an array range thing here with 12 elements and then I will reshape it into a 4 by 3 matrix. So just to be clear, it looks like this where we have seen previously as a datatype. Remember that we can access the data type by going to my array and using dtype. So in this case is integer 32 areas also have a different attribute called strides. So I can get it by using my array dot strides. And here you can see this tuple here. So what does this mean? This really has to do with how NumPy stores information. I'm just copying the commentary of my areas really stored as a contiguous block of memory. There's not really an underlying concept of dimensions. Conceptually, my area is really stored closer to what you would think of as a flattened array. So let's say that it's stored or like this. So if it's stored like this, how does it have a concept of what dimensions are, what is rosewood its columns and so on. This is a really neat trick. What the first stride store, the 12 here is how far you have to go before jumping down a row. So let me explain why this is 12. So each of the datatypes are int 32. 32 is the same as four bytes. So what does not Baidu goes here, then it jumps four bytes, eight bytes, 12 bytes. And then since it's dried as 12, it will jump down a row here. Notice when I say jump down a row is just conceptual language for us. What NumPy just do is keep track of this 12 here. The four, as you probably suspect, is how far you have to go to get your new column. And in this case is just four, because once you go one over, you get to a new column and that's four bytes. So let me have the other representations up as well. So this is how we see it. Let me add some new lines here. So this is how we see it. But really it's just stored in this way. And the strides is NumPy as underlying mechanism for keeping track of how the rows and columns work. So under the hood, NumPy just stores everything in a row and then just uses these pointers to determine what should be columns or should be rows. And you might think, okay, that's kind of neat. But how does this actually helped me with anything? But it helps you to do, is to understand some operations in NumPy is ridiculously fast by using this system. So one example is transposition. That's fine. You just in my array. And thus we have seen previously, just use the transpose method. Great. But now, what has really changed, you don't think of transposition anymore is flipping along the diagonal or something crazy like this. Simply think of this as the one-dimensional form. What NumPy actually does under the hood, the numbers are all the same. They've just been re-ordered. And the reordering is simply switching these two elements in the stride. So if I illustrate this for print out transpose, and they're strides, it's four by 12. Rows and columns have been interchanged. But for NumPy, you just switch these two numbers here. Doesn't matter if your matrix has a million elements or ten elements. So transposition is ridiculously cheap and non pi when it comes to speed and also slicing, the typical slicing is really, really fast. Say now that I want to do a slice and take every other element. We could have done this in a previous video. I just take my array, then I want every other row and every other column. Era really sliced out a lot of stuff. We seem to have made something completely different, but what has really happened has printed out. Here. You can see that the stripes are known 24 by eight. It's just doubled from what it originally was, simply taking longer steps. Let's just visualize and see how this works. Because here we start at 0 and then we have eight bytes to get to the next thing in our column, and that will be four bytes, eight bytes to next one will be the two to move in a row direction we need 24 will actually move all the way over to this six here. So this will give us this one. I can see now they were actually pick out exactly what we think we pick out. This is the recent slicing is typically our view in Python. We can typically just rearrange your strides to get a slice was incredibly effective and really, really fast to do in Numpy. I will not dwell on strides anymore. I'll probably not mentioned it anymore during the course. Nice to see how NumPy works under the hood. Thanks, and I'll see you again in next video. 52. Exercise Set - Color Images: Hi, and welcome to this exercise sets. In this exercise, we're finally going to be working with colored images. Colored images are a great application of 3D arrays. So usual colored image typically has a height and a width, also has three color channels, typically red, green, and blue. This makes it so that we have three-dimensions to be working with for this can be greatly modeled by a 3D NumPy array. So as usual here we have some background information. Here we have a solid you should run without modifying it. This is just to import numpy, import matplotlib, and also gave you a specified image. So the image this time is the astronaut image here, which you can see is in colors. First of all, we'll just be checking the shape of the image. For the second exercise will be showing the image in different colors. Here again, you have a cell that you should just run without actually modifying it. In here, I'll get older red in the image afterwards. You're supposed to do more or less the same, just extracting all the green in the image and all the blue in the image. The third exercises about color alterations by decreasing the color. While the fourth is about color alteration by increasing the color, there is a more nuanced problem by increasingly color that stems from the NumPy datatype. We can read all about that here. And finally, in exercise 5, I've called this dividing conquer. This is essentially about dividing the image into four quadrants and then modifying each of them separately. I really hope that this exercise, we'll make working with 3D arrays more concrete. So as usual, give this your best shot. If you find yourself stuck none, of course, you can look at the exercise solution. 53. Fourier Transforms Intro: Hi and welcome to this introduction video about the Fourier transform. In this section, we are going to learn how to calculate the discrete Fourier transform using NumPy. So the goals is to understand complex numbers in NumPy because without complex numbers, no Fourier transform. Additionally, we will need to import the FFT library to be able to use the Fourier transform. Thereafter, we are going to learn how to find the one-dimensional Fourier transform of a signal, for instance, a sound signal, an electrical signal or SOA. Then we're going to learn how to smooth a one-dimensional signal using the Fourier transform. This will essentially be just removing all the higher frequency to make the signal smoother. And finally, we are going to move to the two-dimensional Fourier transform. And there we are going to do an example where we compress the signal. So we remove all the lower frequencies to retain as much of the data as possible without that many non-zero frequencies. So in the exercise set, we are going to focus on examining our sound signal and take the Fourier transform and on the sound signal, we are both going to try to do some smoothing of the signal and doing some compression of the signal. So I'm really excited to start. So let's keep going. 54. Complex Numbers: Hi and welcome to this video on complex numbers in NumPy. As you might know from before, you can use complex numbers in Python. So now I have not imported the NumPy package and we'll just use Python for a while. So you denote the imaginary unit by J. But since j is a bit ambiguous for you will usually denoted by 1 j. So here I have the imaginary unit. And if I take a monk to the power two and run this cell, I get minus 1 plus 0 j. So this is the complex number minus 1. So if I want to define a general complex numbers, I can do free plus, for instance to J, which is short for two times j. Run this cell. And now I can, for instance, multiply this complex numbers with the imaginary unit j. And here I get the result minus2, because j times j is minus two plus three j because free times j is, hey, in mathematics, the imaginary unit is usually denoted by i instead of j, but Python is more focused towards the engineers. So it chose to do the j notation instead of the ion notation. Okay, So I have two complex numbers. So now it's time to move to a numpy and see how complex vectors is implemented there. So now I import numpy as np, run the cell. And now I can make the complex vector to be equal to np.array off in mock comma complex. And run this cell. And let's just see how it looks like. So here you see you have 0 plus one j, which is this a monk here, and free plus two j, which is the complex number here. So we can take the real and imaginary part of the complex vector by doing the real. And the real part of the first one is 0 here, and the real part of the second entry is free. So we end up with the vector 0, free. We can also take the imaginary part of the vector. And the notation here is a mike. And here we see that the imaginary part is 12, corresponding to one here and two here. And the final thing is that we can take the absolute value of the complex vector. So EdTech apps of the complex vector. And what we get is the absolute value of the first entry, which is one. And the absolute value of the second entry with just free squared plus 2 squared, which is 14, and under square root of 13, which is approximately free, six something. So the doctorial and dot inline function works in Python. Aswell is just an extension to complex vectors. And the same goes with the absolute value. So you can do complex number dot rel to get the outer real part of the number. And the complex number that it Mike, to get off the imaginary part of the complex number, which was two here. And finally, you can take the absolute value of the complex number to get free 0.6s something. The final thing I wanted to say is that a complex vector has a complex dtype. So if I take the complex vector now and check the dtype, I end up with complex 128. So indeed we have complex numbers as the type pair. This was everything I wanted to say about complex numbers. In this section, we will use complex numbers in the next section when we are talking about Fourier transforms. So see you in the next video. 55. Fourier Transforms I: Hi, and welcome to this video on the discrete Fourier transform. So I'm really looking forward to this video because it's a very cool applications of what NumPy actually can do. So the idea is that you have some kind of signal, let be it audio signal or electrical signal, or even I'm an image. And when you take the Fourier transform or discrete Fourier transform, in this case, what you end up is the frequency. So the intuition behind the frequency is started tells you something about how much the function oscillates, so how much it goes up and down. So what we will do when we are working with the frequency is like modifying them, for instance, setting some of them to 0, or setting the less significant frequencies, 200 or so on. So we've worked in the frequencies, and then we can move back to our original signal and something has happened with it. It has, for instance, fewer frequencies or it's a lot simpler and so on. So this is the idea of the Fourier transform, and here is the formula. So I will not go into it in detail, but there are some things you should notice. First of all, you take in a vector and you get out a vector. Secondly, it is a complex vector because this here, this e to the power two pi j times k n divided by m. This is a complex number. So this means that you have real and imaginary things. So this was everything I wanted to say about the discrete Fourier transform. We will do several examples and see what we can do with this Fourier transform. So see you in Jupyter Notebook. So here I am in Jupyter Notebook and before I do anything about the discrete Fourier transforms, I need to import them. So what we write is from numpy import FFT. So the fourier transforms is in this module FFT, which we are going to use in this section. So you need to import it. And now we can use it. But first we need the signal. So I will start with a simple sign, single node, so designers of width some periods. So first of all, I want to define my times or the samples of the single. So I have the number of samples which I'm going to just arbitrarily take to be 400. So I want to do 200 samples in 1 second. So the samples frequency is going to be 1 over 200. And I want to take samples in two seconds. So a use the linspace from 0 to sample, frequency times number of samples. And let me use tab to auto-complete and then number of samples. So what I do is I have 400 points between 02. So let me run this cell. So the simplest signal so you can make are the ones would constant frequency. So they are usually sine and cosine or some combination thereof. So I will make my very simple signal, which is going to be np.zeros. And let's take a period of 10, which I'm going to do like this. So here we have on the interval from 0 to one, this function here repeats ten times. So let me run this cell. Let us also just for intuition, plot the signal. To plot the signal, I will need matplotlib, so let's import it. And we always imported as PLT. Let me run this cell and now I actually can do some plotting. So let's do plt.plot plots, and let's do the times and the sample signal here. So here's our signal. If you actually count how many buttons there are, it should be 20, because it repeats like one period, two periods, and so on. Okay, So this is our signal and we want to get out the frequencies. And remember to get the frequencies, we need to use the Fourier transforms. So everything up here except importing this Fourier transforms should be known. And we haven't really used the Fourier transform CSS. So let's use it on this signal. So then from FFT, we can use our FFT, which stands for the real Fourier transform. And the recent for me using the real Fourier transform is that this signal here, the snuffed have any imaginary components. It's a real signal. And let me just take in the simple signal like this. And what you see is that I get the out an area with a bunch of complex numbers. So there should be a lot of them, but let's just see the shape. So we have 201 complex numbers here, and let me also save it to be f of f. So the Fourier transform of the signal here and run this cell. So now we have saved the Fourier transform. 56. Fourier Transforms II: So now it would be really nice to actually get some handle on how the Fourier transform looks of a function. So I want to plot the Fourier transform of our signal, but currently I have just the y-values, so I will need to create some x values. And this I'm going to do with FFT again. And there are FFT because it's the real Fourier transform. And then Frac to get out to frequencies. And then I take number of samples, which was 400, if I remember correctly, yeah, For a 100. And then I take the sample frequency, which was 1 over 200. And let me save it as frequency domain and run this cell. And I have misspelled something. So I misspelled the samples here. So let's run again. And now I have my Fourier transform. I have my x values or what I call frequency domain. And let me do PLT dotplot. And since this is a complex signal, I will plot the real values and then plot the imaginary values. So we take our frequency domain comma f of the function f dot to get off the real values. So let's just look at it. And here you see that it's 0 almost everywhere. The only place it has a peak is on this number here, which corresponds to 10, which is our frequency. And let's also just for fun, fluffed imaginary numbers. So then we take dot in my care to get out all the imaginary numbers and run this. And then again, you see that it's 0 all the way here, except at the value 10 here where we have a peak and this corresponds to the frequency here. So this corresponds to how many times the function oscillates between 01. So we get out to frequency when we are doing the sine function. So let's now try to do something a bit more complicated, which is the sum of two sine functions. So I will use the same time domain as I did before, but I will change my signal. So I will call it two signals, or the composition of signals if you want to be fancy, but not today. And I want my single to be np dot sign. So let's take one frequency to be 50, so 100 times and p dot pi times the times, and I want the sum of another frequency. So let's say the next frequency can be 20 and p dot sine of 20, then I should fit in 40 np dot py file like this. And let's just for fun, plot the signal again. And here we have this picture here, and you see it oscillates quite a lot more than it did the previous time. Okay, so let's see if we take the Fourier transform of our signal, what happens then? So FFT dot real FFT. So the real Fourier transform of my two signals. And since I'm doing the same samples and the same frequency of the samples, I can just use the same frequency domain has I did here. So let me just run this one. Now I get a bunch of complex numbers. So let me call it something like f 22 or something, because now we have two signals. And let's again try to plot the real and imaginary part. And then we had frequency. Let me use Tab to complete it. F2 dot for instance. So here you can see we have one top here to 20 and one here at 50. So you can see the frequency is quite clearly here and lets also plot the imaginary. So let me just copy this line and in monk here and run the cell. And here we also see that the imaginary part has a peak at 20 and 10 to 50. So when you take the sum of two things with different frequencies and then the Fourier transform, you see each of the frequencies quite clearly in the frequency domain. So what we can now do is, for instance, isolate one of these frequencies. So let's say that we want to isolate this 20 here, so we can set this part here equal to 0. So then we do f two, and then we do frequency domain. And I want to say that everything greater than, for instance, 40 here, so we cut off the signal here. 40 should be just equal to 0. So the frequency domain here is the values down here. And I'm saying that everything over 40, I'm going to set equal to 0. So let me run this cell. So let me just see the plot once more when I've cut off the higher frequencies. So let me just copy these two lines and put them down here and run the cell. So now you see down here at 40, we do not have anything other than 0 here compared to here where we had one frequency here. So what I can do now is to go back with the inverse Fourier transform. And the notation for the inverse Fourier transform is I are FFT, so the inverse real Fourier transform, and I can do it of my signal F2. And let me call it lower frack for lower frequency because we removed the highway, run the cell and let's try to plot it again. So PLT dot plots the times and then the low Frick here. And what you see is that now it looks a lot more like a sine function. So what's happening here is that if we go off pair to our function here, we are essentially just removing this part here. So the function with higher frequency, we are just removing and we're only ending up with this part here. Okay, So this was everything I wanted to say in this video. And in the next video we are going to go through one more application where we are going to smooth the function using the Fourier transforms. 57. Smoothing a Signal: Hi and welcome to this video where we're going to go through a small application of the Fourier transform. So one of the application of the Fourier transform is to smooth a signal. So if you have a signal with a lot of noise, then you can clip off the higher frequencies and then you end up with a much smoother signal. So first of all, I need my times and I need to find a single. So my time is going to be np dot linspace between 02 and I want it to be 600 points between 02. Let me run the cell. And then I can define my signal, which is going to be np dot x minus and P dot cosine. Then 40 times np dot pi times the times which we defined here. And then I want to take cosine to the second power. And this entire thing, I want to multiply by NP, the cosine. And then I wanted to have period five. And then a signal with period 50, like this. So let's run this and we have also called the signal signal. So the entire signal is NP, the exponential of cosine of 30 pi x to the power two, and then cosine 10 Pi x plus sine pi x. So this is the signal here, and let us plot it with PLT, plot times comma signal like this. So here is our final signal. So you see it goes up and down rather quickly. So just pretend that this is some noise that we want to get rid of. So typically, noise audio signal have very high frequencies and we want to get rid of it. Okay, so what do we do if while we need to go to the frequency signed? And we do that with the Fourier transform. Again. We have imported the Fourier transform module. So we will use it here and we will use FFT that real for your transfer or forest signal here. So here we get a lot of imaginary units. We will give it a name which is going to be F, F equal this thing here. Let's run it. I also want to plot it. So let me define the frequency domain. And this is going to be FFT, FFT, fret. And the first thing we need to take in is how many sample points we have. And this is 600 because we have 600 points. And the second thing is how often do we sample? So we sample two divided by 600, so one over a 100 here. So let me write it in like this. So now I have my domain and my Fourier transform. So let us plot it with plt.plot frequency. And let me use tab to auto-complete and then F subscript f. And let me run this cell. And it's complaints now because this part here is complex. So I will do real to not get the warning. And here we see the real frequencies. And let me also show you the imaginary ones so that we have both. And then we use a mike, run the cell. And here we can see both the real and imaginary frequencies. So what I want to do now is to cut it off. So I want to say that everything above, for instance, 40 here is going to be 0. So we'll take all the higher frequencies and just delete them. So I will do this by asking where is the frequencies larger than, for instance, 40 here. Then take it into the Fourier transform and set it equal to 0. So this should be very similar to how we single out a single frequencies. Only here we remove a lot more of the frequencies. So f of f, Then we take frequency and let me just tap to complete. And I want to ask where they are greater than 40. And I set this thing equal to 0. So I just cut it off, run this cell, and then I can plot the real and imaginary unit once more and run the cell. And now you see that here everything has been set to 0. So we have a lot fewer frequencies here now. Okay, So let's move back with the inverse Fourier transform so we can see our smooth signal. So the smooth signal is going to be equal to FFT dot inverse, FFT, or Fourier transform of the Fourier transform of F, where we have cut off all the higher frequencies. So let me run this cell here and let us also plot the result. So what we see here, we can compare it to this thing above. So this is our original signal and you see that here. Here is just a big mess compared to our smooth and signal, where we only go up and down here once and then continue on our way. So this is a much smoother signal. And if the higher frequencies had been so nice, we would have removed this nice. Okay, this was everything I wanted to say in this video. In the next video, we are going to move to two-dimensional Fourier transforms and looking at Fourier transform of an image and then doing some compression of the image using the Fourier transform. So see you then. 58. 2D Fourier Transforms: Hi, and welcome to this video where we are going to go through the two-dimensional discrete Fourier transform. So the two-dimensional Fourier transform takes in a two-dimensional array and gives us out the frequencies of the matrix. An example of a two-dimensional array is for instance, an image. So let's import an image. So I will write front has k image dot data import camera. Run this and then we will set the camera image to a variable like this. So now I have saved the camera image in the variable camera. Let's see the image by using PLT dot info. And then take in the image and the color map since the camera image is black and white image. So the column is then going to be equal to PLT, but CME, those gray. So this is not very important, is just to see the actual image. So let us run this cell and I misspelled Sima. So let me run it again. And here we have an image of a man standing with the camera. So black and white image is just a two-dimensional array. So what we can do is to take the Fourier transform of the image. So let me do f for camera, which stands for the Fourier Transform of the camera image. And from the module FFT, we are going to use the reel for transform, but this time it's going to be two-dimensional. So we write the two here, and let's take in the camera like this. And let's for fun, check the shape of the camera image null. So again, you see that it has a lot of complex numbers, but this time it is a two-dimensional array. So if you use dot shape, we get 512 comma 257. So if we want to have some picture of how the Fourier transform looks like, it's a bit difficult because you end up with something four-dimensional sorta we'll do is to use a transformation to get an image back. The transformation is going to be taken in logarithm of 1 plus and P dot absolute value just to make the values real and the logarithm is to make the value smaller. And then take the Fourier transform of the camera image. And to have a grayscale image, I need to only take in values between 01. So I will choose to just divide by the maximum value. And let me just save it to be the variable logarithm and run it. So what I do is to take the logarithm of 1 plus and P dot absolute value of f camera. So I take 1 plus 2, not get negative values. And when I take the logarithm and I divide by the maximum here just to get values between 01. So let us see how it looks. Plt.plot Show and then logarithm. And the CMA again is going to be a grayscale image. So we're going to use plt.plot cm dot caret and run it. So here you see how the logarithm of the absolute value of the Fourier transforms looks. And what we are going to do is to compress the image. So we're going to take all the frequencies here with rather low values in absolute value, and we're going to set them to 0. And the point is that if we have a lot of 0, then we can save space by saving the Fourier transform of the image without losing a lot of information on the original image, let us try to actually do it. So what I want is to take the Fourier transform of the camera. And I want to see where np.array the absolute value of f camera. And I want to see very small and just set it equal to 0. So let's say that when the absolute value of f comma u is less than 1 thousand, I want to set those values equal to 0. So let me run this and let me see how it now looks. So I take this cell and just copy it down here. And I take this one and just copy it below. So now I first take the logarithm transformed, which I have here, and then I just show the image. And now we see that we have a lot of black in the image compared to the original one. So that corresponds to the values 0. And since we have a lot more 0, now, we end up with a lot more black. So we can actually just compare for fun and need to run this again so that I haven't done anything. So now my image is the original one and I want to see how many non-zero elements the original image as this I can do with np dot count non-zero. So this function here, and I'm going to take in F camera and just look at the result. So in the Fourier transform of the original image, the number of non-zero elements is approximately 140 thousand. And let me run this cell where we set the left of the image to 0 and this one, and let me do the same count again down here. So after we set a lot of the image to 0, we only have 55 thousand non-zero elements compared to 130 thousand. So about half of the information is deleted. So let us now go back with the inverse Fourier transform. And let me call it compressed. And it's going to be FFT dot inverse real Fourier transform. And it's in two-dimensions. So we use the two here. And we are going to take an F of camera like this. So now we have it and let me also see the image with PLT, the IM show compressed. And then CMAP equal that CM and run the cell. And we see that an almost nothing has changed. So if we look at the original image, it's here. Compared to this image, you can not see a lot of differences here, even though we have deleted almost half the information on the frequency side. So this is kind of the idea behind compression algorithms that you can set a lot of the values equal to 0 and still retain the main features of the image. So let's try to do something even more extreme. So instead of false and here, let us take 50 thousand and set it equal to 0. And let me run this cell. And if we count how many non-zero elements, we have only about 2 thousand of them left. So we started with 130 thousand non-zero elements. And now we have approximately between 1, 2% left of the information. And let me go back with the inverse Fourier transform and show the image. And now you can see the difference quite clearly here, but still you retain most of the main features of the image. So even though you only have like 2% of the information, you can still see the image quite clearly. Okay, this was everything I wanted to say. So see you again in the next video where we are bone to go through some exercises. 59. Exercise Set - Fourier Transforms: Hi and welcome to this exercise set. So in this exercise that we are going to work with real audio signal. So first of all, we need to run this cell here and this cell here and here v are just importing a lot of packages. And the only new one is this package here, which I'm going to talk about in a bit in this cell here. What we are doing is to load some audio files, which I have prepared for you. So this function load here is going to be more fairly explained in a later section. So here we have Exercise 1, which is the Fourier transform module. And the next exercise is to plot one of the audio files, which is named T port. But you can see here. So you have the intensity here and here you have the times and you'll go, just going to plot it, times versus intensity. Here. If we run this cell, you see that you can play this audio single by pressing play here. And here you are using the new package IPython at certain points in the exercise set, you are going to use this function after modifying the sound. So the important thing is that it takes in the NumPy object and the sampling rate, which for my audio is this number here. So you can later point if you have your modified sound, you can take it in this input here and then just let the sampling rate be the same. So this G chord here, we are going to take the Fourier transform and we are going to use to real Fourier transform frequencies to get the domain of the Fourier transform or the x-values. Thereafter, we are going to plot the real and imaginary part of the Fourier transform. In exercise 5, we are going to do some smoothing, so we are going to cut off all the frequencies over 950 hertz. Finally, we are going to go back with the inverse Fourier transform and we are going to plot the new audio signal. And also if you use some iPython thing over here, then you can also play the audio signal. You get back. In Exercise 6, we are going to work with the Ito, which is imported at the top here. So here you have the Ito and the times in which we sample on the Ito. And again, we are going to plot the data. And if we run this cell, then you also can play the Ito in Jupiter notebook. And what we are going is to take the Fourier transform and plotting the Fourier transform. And then we're going to compress the signal. We are going to remove all values which has an absolute value less than ten. And after compression, we are going to plot it again and we are going to see how much we remove of the signal by counting the non-zero entries, both before and after the compression. Finally, we are going to go back by using the inverse Fourier transform, and then we are going to plot the compressed ITO. And finally, you can use iPython dot display to actually hear the file or the compressed eaten. So good luck for the exercise. And as always, you can find the solution of the exercise in the same folder as you find exercise. 60. Advanced Linear Algebra Intro: Hey, and welcome to this section on advanced linear algebra. Stevens previously shown you some basic linear algebra in this section, we're going to take that to the next level and show you some of the advanced features that NumPy can give you. I just want to let you notice is this is a bit of a difficult section. It is also optional. I definitely encourage you to try to watch it, but if there's something you don't understand and don't beat yourself up over it. So this section is all about the more advanced aspects of linear algebra, numpy, and more specifically, we'll learn how to find eigenvalues and eigenvectors of a matrix. We will learn how to recognize diagonal, orthogonal, and upper triangular matrices, special classes of matrices. We will perform a QR decomposition of a matrix. I'll also show you the numpy is built an exception called Lynne are finally, in some cases it's not really possible to solve linear systems exactly. In that case, you can still find the closest thing to a solution with what's called least squares. I'll try to explain you each of these topics as well as I can just be aware that a few of these topics, namely eigenvalues, eigenvectors, QR decomposition and least-squares are rather advanced. Specifically, QR decomposition is something you might not even see in a linear algebra course at the university. So it's definitely cool if you can learn this, but don't beat yourself up if it's too hard. As usual, we have an exercise set. We'll get a lot of practice with the topics here in the exercise set. We will, among other things, worked with what's called quadratic approximations. This means to take a complicated function and try to approximate it with a quadratic function, meaning a second degree polynomial that you probably learned about in school. When I'm talking about this, it might not seem like this has anything to do with linear algebra, but it turns out that it does. We can approximate a complicated function with a simple one by using techniques from linear algebra. So I really hope this sounds exciting and we'll get started on eigenvalues and eigenvectors in the next video. 61. Eigenvalues and Eigenvectors: Hi, welcome to this section on advanced linear algebra. I'm here in an empty Jupyter Notebook sheet. Let me just first of all, import NumPy as np. As usual, we'll also need a sub package that you have seen before, namely the linear algebra some package. So I can write from NumPy. I'll import the linear sub package. So for the first video, I'll be talking about eigenvalues and eigenvectors. This is about finding eigenvalues and eigenvectors. So before we start computing images, show your slide essentially explaining what eigenvalues and eigenvectors are. So before giving like a formal definition, Let's just explained the rough idea. So an eigenvector for a matrix a is a vector, sort of a only stretches the vector v when applied to it. If you take a matrix a and multiply it onto a vector v, the new, of course get a new vector. But an eigenvector is a bacterial only gets stretched and amount of stretching is done called the corresponding eigenvalue. Let's just see a brief example. So here I have a matrix. A is just a mutual two-by-two matrix. Entries are to 200 three, and I have a vector V which has entries 300. In this case, we have that if you apply a to V, the neural precisely get 2 times v. So to see briefly what will happen. The first row here will be multiplied by V and the sensory get two times three plus 2 times 0, that gives us just six. And then finally I get 3 times 0 and 0 times 3, that gives you 0. The result will be a vector with entries 60, and that is precisely two times the vector v. In this case, we will say that the V is an eigenvector for a and two is the corresponding eigenvalue. With this example in mind, we can give a bit more formal definition. So this is definition of eigenvalues and eigenvectors. So it's essentially just a repeat of the ID written a bit more formally. So if a is an n-by-n matrix and V is a non-zero vector, so it doesn't consist of all zeros. And we would say that v is an eigenvector for a if there exists a number lambda, so that a times v equal to lambda times v, there is no need to get frightened by the lambda. This is just a convention that we denote the eigenvalues by lambda. And of course, as I kind of already said, the value lambda is called a corresponding eigenvalue. So again, in this case, V is the eigenvector and a number two is the corresponding eigenvalue. So eigenvectors and eigenvalues are often very central topic in university courses on linear algebra. We'll go back now into jupyter Notebooks to see how we can find these by using NumPy. Now we're back and let's try to find eigenvalues and eigenvectors, certain matrix. First of all, we will need a matrix, so I'll just make one. What I will do is to make a random number generator, as we've seen previously. So this is np dot random, and then I'll go to the default R and G. Once I run this, I've now initiated a random number generator. So I can make myself a matrix by going to Orangi, calling the random function or get nine random numbers. So this gives me a vector and I'll just reshape it immediately to a three-by-three matrix. You can see that I have now a three-by-three matrix with random entries. So finding the eigenvalues and eigenvectors of the matrix is very, very simple in NumPy, what you can just do is to go to lean out a lot. Ache and then pass in my matrix. As you can see, the output is pretty confusing. Let me try to briefly explain what this means. First of all, we can see that I get a vector here having 1, 2, and 3 elements. This is really difficult to see in the output, so you'll just have to trust me. Secondly, you get a matrix here which is three by three, and the columns in this matrix will be the Eigen vectors. So here's the eigenvalues, Here's the eigenvectors. So what you do is you pick up these individually by first writing eigenvalues and eigenvectors and assign it to this in this way, the first thing here will be assigned to the eigenvalues variable, and the second thing here will be assigned to the eigenvectors variable. Once I've done this, I can print this out. So here I have the Eigen values first. And these are the three eigenvalues. So you can see that the eigenvalues are typically complex numbers, but not always. So here in the middle you have a pure complex number, but the first one here is just a real number. They're all outputted into complex form. So here we have the real part plus the imaginary part. And in this case the imaginary part is just 0. So this really just as number 1, point 2, 3, and so on. We can also print out the eigenvectors. Here. It can be nice to actually add new lines. Let me just do that here. Here you can see the eigenvectors and each of these columns here correspond to a single eigenvector. So this is the first eigenvector, this is the second and this is the third. That means that if I let my matrix act on the first column here, then I'll just get a constant times the same column. And thus constant will be precisely this one. Eigenvalues and eigenvectors have a lot of applications in mathematics and surrounding areas, especially in differential equations. This is not really a course about differential equations or higher level math. I don't want to go through this at all. Whoever let me just end by showing you a very small thing about eigenvalues. You've seen previously the determinant. We can always find the determinant of a matrix easily in NumPy. We just use little dots and pass in the matrix. So symmetry about this in a previous video, and here you can see that the determinant is some number. The most important thing about the determinant is whether it's 0 or non-zero. In this case it's non-zero. That means that the matrix is invertible. However, there is a different way of actually determining the determinant, which is essentially to just take all your eigenvalues, which are this, this, and this, and take their products. Let's see how this works. To take the product of something, I can go to NP, then I can use the function fraud, which is an abbreviation for product. And this can take the product of all the eigenvalues. Then I get this number and you might get the immediate feeling of, hey, this is not the same number. If you look closely at it, it actually is. In essence, this imaginary part is 0 and the real part that remains here is precisely the same as this one, up to some minor calculation errors in the last digits here. So if you already have the eigenvalues of a matrix and it can immediately just find the determinant by taking the product of them. Definitely computationally, if you already have the eigenvalues as we have here and taken their product is super quick. If you know the eigenvalues and you're concerned about the speed of your program. And this is definitely preferable over calling the determinant function is all I wanted to say about eigenvalues and eigenvectors in NumPy, really easy. You just use a dot eigenfunction, a new datum immediately. In the next video, we'll take a look at a few different types of matrices like diagonal matrices and something called orthogonal matrix is an upper triangular matrices is what gives us a better grasp of the different matrices that exists. Thanks, I'll see you soon. 62. Types of Matrices: Hi, In this video, I'll talk about three different types of matrices. The goal is to get ourselves more familiar with different types of matrices. Additionally, the last two types, namely orthogonal matrices and upper triangular matrices, will be used heavily in next video, the first type is what's called a diagonal matrix. And you've seen this previously. So matrix, let me just write it out in a comment. The matrix, let's call it D is diagonal. If the only non-zero entries are on the diagonal. So every element that is not under diagonal line should be 0. Let's just make a quick example. We make a matrix manually. So here we have our first row, which is 1 0. We also have a second row with 07. Let me just print it as well. Here we can see it. And diagonal is precisely the line starting at the upper left corner and going down to the lower right. So it starts here and it just goes down in this line here. So it includes 17. You can see in this example that all the elements that are not on the diagonal line, namely this one and this one are 0. So this is a pretty straightforward concept seen as previously shown you a very special matrix that is diagonal immediate identity matrix. So this you can make by np dot, let's say three-by-three, such as passing a three. So let me just print it out. So here you can see it. Again. It's probably better if I just make it like this. That has 1's on the diagonal and 0. Otherwise. If you want to make your own identity matrix where the entries on the diagonal or not all the same. And if you use a special command, so then you can use the command debug print statement. Let's call it my diagonal matrix, make a new line. And then I use the command NP DAG and then just pass in here a list containing the diagonal elements. Say I wanted to be a three by three matrix with first one, then a 79. So if I print this or get precisely this, the next type of matrices is a bit more involved. This is what's called an orthogonal matrix. The steam told you previously what it means for two vectors to be orthogonal, but a matrix is orthogonal. If the columns are orthogonal, each of the columns should be orthogonal to all the rest. And additionally, each column should have length one. So here let me just copy this because it's a bit boring to write. Here I have a matrix that I've written in manually. Telemetry is printed out. And here you can see that it's a pretty straightforward matrix, is a two-by-two matrix. Let us now check that is orthogonal. So how would you do this? We first need to check that the columns are orthogonal to each other. They checked the columns are orthogonal. We can use the function np dot, dot, dot. Anatolia about this gives us a dot-product of what we put in and we want the dot product to be 0. So in this case we want to take the first column. So that means I want all the rows and the first column, and I want to take the dot product between this and the second column. So again, this is all the rows and the second column, which of course is index one. And if I now run this, you can see that I get 0, so they are orthogonal. Let me just have this in a print statement. So this was the first thing we needed to check. The second we need to check that each column have length one. That's also pretty simple. Let's just do it for the first column. And to check the something has length 1, we use the lean out and then the pnorm function. So again, let's go into our matrix and select the first column. And here you can see that it has length one due to rounding errors again, we get almost one, but this should be precisely one. For the second column limiters copy this line, paste it here, change the first, second. And then of course do that second column, which is index one. And here you can also see that this is one. So indeed the matrix Q is orthogonal, okay? So we now know what an orthogonal matrix is. A big question is like so-what, what's really important about orthogonal matrices? And the answer is a orthogonal matrices. Awesome. So let me give you a few examples. One of the things still did was calculate the inverse even for a three-by-three matrix is hard to do by hand from numpy is really expensive to calculate inverses. But if you have an orthogonal matrix, It's really quick. And reason is that they satisfy something very peculiar. If you take an orthogonal matrix Q and then you take its inverse is actually precisely the just the transpose. Let me write it like this. Recall that the transpose is simply just flipping along the diagonal. When he talked about strides, when you talked about the areas we actually sorted, transposing is ridiculously cheap in NumPy. So finding the inverse of an orthogonal matrix is simply taking the transpose. So for the matrix Q we have here, the inverse is simply just these two numbers here, but oh, that two numbers are the same. So it is its own inverse. I don't need to call any inverse functions or deal with this at all. Secondly, as you can see, that means that orthogonal matrices always have inverses. Still told you that for a general matrix, you need to ensure that this determinant is not 0. But for orthogonal matrices, this is always the case. So they always have non-zero determinant. So this just really convenient. So let me just preface. This is for orthogonal matrices, everything I'm saying now for a general matrix it might be 0 or it might be a different number. So this is really convenient. And for a third thing, which essentially just build on the first one is that if we have a system of equations and we want to solve in the following form. So here q is the matrix and it is now orthogonal. And things are suddenly a lot easier. Because we know that the solution is simply given by multiplying by q inverse on both sides. We multiply by q inverse. I get a Q inverse over here. So this, you can do always. But the fun thing is that inverting is, again, very simple to this theory. Just becomes Q transpose times y, which again is very simple to compute. So once you know that you have an orthogonal matrix, U are really in good hands. Everything is just a lot more simple. So to illustrate the final point, say I have y being np.array. Let's just take the vector that has elements 34. Say now that I want to solve x equals y. To solve this, It's really simple to look here and just set x to be Q transposed times y. Let's set x to be q transpose. Remember that we can write transposed either as just T or dot transpose gives us the same thing. And then I just multiply this with y. So now if I print x and this will be the solution to the system. So the final type of matrix I want to talk about is something called upper triangular matrices. So upper triangular matrices are diagonal matrices, kind of almost pledge just first make one. I'll just do np.array. And here the first row is 1, 2, and the second row is 0 by three. Sludge just have our printed. So an upper triangular matrices is not one which is diagonal. That's too strict, but it shouldn't have any non-zero elements below the diagonal. So this matrix has non-zero entries here, here and here, all the entries below the diagonal are 0. The reason for the name is done. The upper part kind of looks like a triangle by combining all the elements here. And one really convenient thing about these determinants is really easy to calculate. So the determinant of R is simply the product of all the diagonal elements. So in this case I just take one and multiply it by 3. That gives me 3. Verify this, I can just do thin alg dot-dot-dot of our print this out and we see that we get three. So computing the determinant is really quick. Secondly, solving linear systems with upper triangular matrices is really quick. So these are two advantages of having an upper triangular matrix. Once you have a linear system, it's really good to take a few seconds and think it was my matrix. Have any special structure? Maybe it's upper triangular, maybe it's orthogonal, maybe it's even diagonal. In all of these cases, you can make a lot of simplifications in your work. Next video, we will look at something called a QR decomposition. This is a way to decompose a matrix into two simpler matrices. We will see that these two similar matrices are precisely the last two that we talked about in this video. So I really hope you like this and I'll see you again in the next video. 63. QR Decomposition: Hi and welcome back. In this video, we're going to do something really cool, which is talking about a QR decomposition for the other topics in linear algebra so far, I suspect that many of you have actually encountered these previously. However, very few have encountered QR decomposition, and I really like to talk about this. So the idea is that if a matrix is complicated, might be a good idea to decompose it into two simpler parts. So by decomposed, I mean write it as a matrix multiplication of two other matrices. And by simpler, I simply mean that they have some special stuff. And surprise, surprise. These are the matrices I talked about in the last video. So if you haven't watched that one, then please go back and watch it and then you can come back and see this one, any matrix, as long as it's n by n, so it has the same number of rows and columns can be written as a product of q by r. So this is the matrix product. So to specify the product, we usually write with this symbol here so that Q is orthogonal, is an orthogonal matrix and R is upper triangular. So this goes for any matrix. You can always decompose it into matrix which is orthogonal times a matrix. Operate triangular, since we typically denote orthogonal matrices by q and upper triangular matrices by r, This is the reason why it's called a QR decomposition. So before saying anything more or less, just do an example. So you have a matrix and I say that the first row should be 12 and the second row should be 3 and 4. To take a QR decomposition in NumPy is incredibly simple. So let's print this out. So here we have the QR decomposition. I'll just add a new line. What I do is to go into the lymph node package, then I simply use the command QR. It doesn't get much simpler than this. You can see here that the NP areas not defined, of course, it is np dot array. And here you can see what we get. Similarly to getting eigenvalues and eigenvectors we did a few videos ago. We don't just get one thing back, good. Two things back. Here is the first thing, and here is a second. And I think you can suspect that this is the first one will be the orthogonal matrix and the second one will be the upper triangular one. So instead of printing it out, we can assign this. So I'll call it the Q part and the rpart and set this to be linnaeus got QR of a. So now the Q part should have the orthogonal part of my matrix and our parts should have the upper triangular part of my matrix. So to see this, let me just print this out quickly, where we have the Q part and here we have the rpart. And you can see by inspection that the rpart is definitely upper triangular because the only thing below the diagonal is 0 and for the Q part, and when you can't directly see that it's orthogonal because that's a bit difficult if you try to do the same we did all the way up here when we talked about orthogonal matrices and check these conditions that will just work out perfectly. So if you're unsure about this, you can just go and check out these lines of code and replace Cu by Cu part and see what happens. I'll not do this. So I hope you can just take my faith that this will always be orthogonal. So what I can do is take Q part, multiply it with our part, and see what happens. And if you see here, we get precisely a back. Just a word of warning is very tempting to try to intertwine Python code and NumPy code in the following way. You might want to write an if sentence saying like, oh, if a is equal to Q part multiplied with rpart, well, in this case, okay, Then let's say we print out something. A is indeed equal to Q part times our parts. But if you run this, we'll get a value error saying that the truth value of any array with more than one element is unambiguous. This is not what you should do if you want to compare matrices. What you should do is to use the function and p dot all close, which takes in two arguments, the first one being the first matrix and the second one being the second. So what this does, and I think many of you can suspect it by just the name compares this matrix and this matrix. And it checks that all the elements and the corresponding matrices are close to each other. What does by default close mean? I think if I just take a look at a function, the default tolerance here is ten to the minus h. It's pretty close. If all the elements are close to each other, then this will return true. And of course in this case, the if sentence will be accepted and we get to print out this. And of course to just check that it works, if I suddenly plus one to all the entries by broadcasting. Of course the sentence doesn't run because they're not all close to each other. Let me just remove this again. I would like this. So QR decomposition is really neat way to decompose a matrix into two simpler parts. I want to end this video by showing you a slide explaining one of the applications of why this is really useful. One of the things which is very convenient by having a QR decomposition is that you can immediately see if a matrix is invertible or not, meaning if it has an inverse or not. So just to recall, a matrix is said to be invertible, or we also say that it has an inverse if and only if the determinant is non-zero. Calculating determinants is really expensive, but this is a lot easier to determine if you know the QR decomposition. So this is definitely the most theoretical slider have in all of this course to try to bear with me here. So here I have a small calculation. So I have a matrix a and it has a QR decomposition that we know just as we had in our Jupyter Notebooks. In that case, I want to calculate the determinant of a to see if it's 0 or not 0. Well, first of all, a is just equal to QR is I can just switch this in here. Secondly, the determinant of such a product is always equal to the product of each of the determinants. I don't think I mentioned this previously, but this is just a way to determine it behaves. I mentioned when I talked about orthogonal matrices, but they always have either determinant one or minus one. So these are just substitute in here. And I also mentioned for the determinant of an upper triangular matrix, and it's just the product of the elements on the diagonal. So I've written this as R11 to all the way up to R and M. So these are precisely the diagonal elements of R. And then we'll look at this expression where determinant of a, this is just this thing. And we wonder when is this 0? So multiplying by 1 reminders one doesn't change if something is true or not to just doesn't, then we're left with this thing here. One is a product of a lot of numbers 0, well, a product of a lot of numbers, say you take if your numbers, we start to multiply them, this will be 0 precisely if one of them is 0, say as an example, we have a few numbers like to 579. You multiply them, you're not sure what it is, but it definitely isn't 0. However, if just one of them is 0, so you have to 500 nine, you multiply all of them, you definitely get 0. So let me just summarize this in a theorem. So if you have a QR decomposition, then this is invertible precisely when none of the entries on the diagonal of R are 0. So that means in practice that if you have a QR decomposition, you don't need to call it a determinant function. We can just gauge on a diagonal of our weather the elements are 0 or not. So this is one of the many conveniences of having a QR decomposition. So again, this is definitely a theoretical aspect of this course. I hope you got something out of this. In the next video, we'll look at what happens if a linear system is not solvable, but we still want to obtain the next best thing. But thanks, and I'll see you then. 64. Partial Least Squares: Hi, So in this final lecture video on advanced linear algebra or to talk about when systems of equations are not soluble. What we can then do. So say that I have matrix a. And let's just make it sort of all the entries are one. And let's pick a y-value. So this is np dot array, and let's just pick this to be 3 five. Say now that I want to solve the system a x equals y, the problem is that this is not possible. You can't find any vector x such that if I multiply a by x or get why this is sometimes not possible. If you check the determinant of a, it will be 01. Big thing you should note is that although it's not soluble, NumPy might actually try to do this for you. Say that we now try to just do x equal to lean out dot solve, pass in a and y. Just as Dino told you previously, if I do this, then I'll actually get what's called a lynn arg error. This is special customized exception that NumPy has made. The sestet is a singular matrix which essentially is the same as saying that it has determinant 0. The scary thing about working in Numpy is as sometimes we will get this error saying, Hey, this doesn't work and this is the preferred thing. If something doesn't work, I want my program to tell me. On the other hand, in some cases you actually just get out something that's complete nonsense. Let me just comment this out. Is there any way for us to feel safe to code so that I don't have to manually inspect it and see if it makes sense. And the answer is, of course, yes, this is possible. It just requires a bit more work. So the question is now how to feel safe the code? So what you then can do is to first of all go to numpy.org and import this error message. What you can do is to do the same here, tried to solve the system, but inside what's called a try-except environments. So instead of writing this out or just copy it here, I'll just paste it in for you and you can see how it looks. So let's try to walk through this. So a lot of this is not new code, is just Python code. If you're familiar with this, great. If you're not, there is no better time to learn it. Now, heightened has what's called a try-except environment. This means that you write the keyword try with a colon and an insight here, this is what you try to do. If it works, then great, it works if it doesn't work. And Lynn org areas raced and this block here will run and this will print saying that the solution does not exist. So see what we do. We take the lintel that solve of a and y and we get x. Remember that two things can happen. What happens to us when we do this is that the limit of error was immediately raced implicitly by NumPy. And in our case here, this means that we immediately go into this case here. Namely that the solution does not exist. This is the good thing. If nobody doesn't raise an exception, I can still manually. I take a multiplied by x and compare it with this np dot o close to see is, is really close to y. And if it's not really close to white, and I manually erase this little Lindbergh error so that I get into this case here. If all of this kind of passes and I'll just write out the solution as x. So if I run this, I'll get out the solution does not exist. The reason is that once I do this, the numpy will implicitly in my case, raise an error which sends me immediately into this thing here. And you can see now that if I just modify a bit, Let's say a is equal to two here. Run this cell again, notice will be solvable. So if I go here, I get the solution is given by x equals this. So this is a way to fail safe my code. Let me just change this back to 11 and run both cells. So it says the solution does not exist. Finally, even though a system is not solvable, you might want to get the next best thing. If there is no x such that, take a multiply by x and precisely get why can we find x such that Ax is at least close to y. So we don't ask that a times x is precisely why it just close to y. And the answer is yes, this is always possible and this is what's called least squares or partially squares. To find this, let's call it X. We use the Lyn alg and then use the command LS T-SQL, which is short for and least squares, where we put in a and y like this. We can see here that I get something called a future warning, saying that I should specify something called our COND for future updates. So you can just do this. It should be specified to none. You don't need to think about this much. This is just a convenience for future updates. So if I run this, I get out x. Let's take a look at Mr. X. Here you can see something quite different. We get back four things, less things here, just some extra information. What I really want is just the first thing here. So I just pass in 0 to extract this. Let me print this out more properly. So this is the best solution. Mean that the closest I can actually get to y. And to see how close we can get, Let's try this out. The closest we can get this taking a, multiplying it with x. So this is the closest is four by four. If you look up on why it was three by five, this was not possible, but at least we can get to four by four, which is just one too much here and want to little in the second argument, we've seen that you can fail safe your code by using the linear algebra error and a bit of Python code here. And I really want to emphasize is that if you want to be really good at NumPy and you also need to be really good at Python is because NumPy is a Python library. So it's not something completely different is built on Python and really interact very well with a Python logic. Secondly, we sold least squares here, which is essentially asking the question, I can't find a precise answer or they want the closest one possible. So this is it for this section. I know that the advanced linear algebra section is a bit difficult from glad you got through it. In the next video, I'll go through the exercise set for this section. So I hope you will enjoy this and you can use the exercises, really reinforce what you've learned in this section. Thanks, and I'll see you then. 65. Exercise Set - Advanced LinAlg: Hi, and welcome to this exercise sat on advanced linear algebra. This would be a pretty straightforward exercise set where we will practice all of the things we've just learned about advanced linear algebra. So first of all, it's about important NumPy and also the linear algebra sub-module. The second exercise is about diagonal matrices and orthogonal matrices. The third exercise is about a specific family of orthogonal matrices. The fourth exercise is about QR decomposition, specifically, QR decomposition with images. So here we have a specific image, namely the camera man we saw previously. And ID is to QR decomposers and look at individual pieces. Again, it is Sally, you shouldn't modify, usually just run it. Finally, an exercise about least squares to approximate a function. So the idea here is that you have this complicated function and we can approximate it recently well by a second degree polynomial. So how can we actually do this? And this is described here in this exercise in fall. We will use such a second degree polynomial in t like this. So a pretty basic function, we just need to find a 0, A1, and a2, such as this polynomial is very close to this complicated function on the interval 0 to one. So read through this, have a look at an answer all the different parses. A really cool exercise, I think. So. I hope you like it and that's it. I hope we can give this exercise set honest shot. Of course, if you are stuck and take a look at the astrocytes solutions. 66. Saving and Loading Data Intro: Hi and welcome to this section which is all about how to save and load data in NumPy. So often, when working with rather large dataset, you do not want to write every entry into num pi by hand. So to prevent this, we will often read in data from an external source and also for other to use, we are going to write the data. So to start, we will learn how to read in data from a CSV file. So a CSV file is a really popular format for all kinds of data and stands for comma separated file. And also we are going to learn how to save the data in the same format. Numpy has also its own kind of files. So we are going to learn how to save a NumPy array as a NumPy objects for later. And we're also going to learn how to read in the same kind of files into NumPy. So the exercise set is going to contain a broader large data set known as the Boston datasets, which contains data for house prices in an area. So since this is the final section, we are going to try to repeat a lot of the other material in the course. But of course we also going to give exercises with reading in data and saving the data. So this was an introduction to this section. So let's get started. 67. Loading Data: Hi and welcome to this video which is all about saving and loading data. So often when you're working in Numpy, your arrays comes from some text file or comma separated file, which should then import into non pi to create a NumPy object. So let us do such an example. So here I have a text file called data.txt, which contains the following numbers, so 12, et cetera. What I want to do is to take this text file and create an array with the same numbers. So let us go back to the Jupiter notebook and see how this is done. So the function we are going to learn is the load TXT file. So we write np dot TXT. And the first variable is the name of the text file, in this case Beta, but TXT. And the next variable is called the delimiter. And it's how the numbers are separated. If you remember from the original files, the numbers were separated with commas. So the delimiter in this case, it's comma. So let's run this cell and we see what we get out is the array with the numbers 1, 2, and etc. This was exactly the numbers given in the text file. So now this will behave exactly as an empire object. So we can give it a name. Let's call it beta, run the cell. And then we can, for example, take the mean of the data. And now we get that the mean is five. If you have a text file with like thousands of entries, then we have a very quick and easy way to get the mean of the data, often when working with real-life data instead of this TXT. And then which sends for it text file, we have the CSV ending, which stands for comma separated file. This is just to indicate that our text file is a comma separated file. So let us look at another example. So in this example, we have the data, the CSV ending, and this is just a text file. We do not or ending. And what it contains is a comment on the top or a title which gives you some information about the datasets. And then you have a comma-separated line here, and then another comma separated line and so on. So in total, you have seven rows and four columns. And the comments said that this is the measurement of rain per day over a ve, taken on four different times of the day. Note that we also have the NAN values here and here denote thing missing values. So let's go back to our Jupiter notebook. If we want to import the data, we can again use the load TXT function. And then we write in data underscore csv dot c as V. And we need the delimiter. And for a comma separated file, the delimiter is usually a comma. And let's try to run this cell now. So what I want you to notice is two things. Here. We get a two-dimensional array, which is what we want. And second thing is that it ignores the comment. So now I can rename this here to be reign data. And now Rein data will behave like any other NumPy objects as we have seen. So for instance, we can ask if there are any non values in the dataset. So we write np dot is none brain data. And let's ask if there are any NAN values in the Rain data. And if we run this cell, we end up with true because there are missing data in our dataset. So this was everything I wanted to say in this video. In the next video, we are going to learn how to save the data. So see you again them. 68. Saving Data: Hi and welcome to this video, which is all about how to save data as a text file. So last video, we imported the brain data into our Jupyter Notebook. So let's do some modification to the data. So what I want to do with the rein data is to fill in the missing values with the mean. So let's take total meal. And if I try to use the mean function on the rein data, what I end up with is the total mean being the non-value and recent for this is that the sum of a non-value with an NAN value is none. So the way to fix this is to use the function nan mean instance. And if I run this cell and the next one, we end up with the mean being five. So let's fill in the value five on all the NAN values. To do this, we can use the function and P dot n two number. So let me write that in. And the first variable is our dataset, in this case, rain data. So the next value I want to specify is what I want to fill in the non values with. So I write equals total mean. And the final thing is that I do not want to make a copy, so I need to specify copy equals false. So the point is that if I do not give in this part here, it will set all the NAN values equal to 0. So I want to set it equal to total means. So then I specify that none equals total mean. So let me run this cell and here you see that now I have no missing values in this dataset. And this value here that to five, where it was an eigenvalue. Okay, so now I have made some change to the rain data. So if you just look again at the Rain data, we see that now all the missing values have been filled in. I want to save this new reign data, so I do not need to do the entire process again. So to do this, we will use the np dot save TXT. And it takes in the file name I want to save it to. In this case, I want to save it as new data that C, S, V. And then it takes in the data, I want to say, in this case I want to save brain data. And finally it takes in how I want to separate the values. In this case, I want to separate it with a comma. So let's run this and see what happens. And now I will go into my file directory and find the new file. So now when I look inside my file directory, I see that I have this new data, dot csv. So let's push it. And here you see that it has saved the data as a comma separated file, but you see that it has a lot of decimals here, even though they are all 0. So I want to fix that. So let me go back to my Jupyter Notebook and let me copy this line here below. So I want to change the format which the variable was saved. To do this, I can specify the format. So I want to save this data without anything off the decimal points. So the format I want to save it, it is that it can have whatever in front of the decimal point. And often the decimal point, I wanted to have Ciro digits. So let's run this here and look at the data in there. And now you see that it's saved the new data without any decimal points. So let's go back to your notebook. If I change this value to one, it will have one digit after the decimal point. If I change it to 10, it will have 10 digits after the decimal point and so on. But I don't want any digits after the decimal points, so I set it equal to 0. The final thing I want to do is to give this dataset header. So let me copy this line again, like this. And I want to write a header. And I want the header to be, for instance, rain Theta. This thing here will do is to give a comment symbolized with the hashtag symbol on the top of the CSV file. So let me run this cell and go back to the new data CSV. So you see now the CSV file contains this common tier with the rein data. So csv files are a great If you want to have other people using your data. But if you know that you will only use the data inside to Jupiter notebook or in NumPy. Then the easiest thing to do is to save it as a NumPy objects. So not save it as a CSV file, but saved the array itself. This will be the topic in the next video. So I hope you see you them. 69. Saving and Loading NumPy Arrays: Hi and welcome to this video where we are going to learn how to load and save NumPy objects. So the problems with saving things as CSV files or text files is that when you go back and forth from your notebook, your NumPy objects can change, for instance, into dtype can change every time you are saving and loading your data. So to prevent this, if you're only going to use the data inside Python, what you will do is to save the files as NPY or as native NumPy objects. So let's say that I take the daily mean of the rain data. So that means that I take mean with axis equal to one, run this cell, and then I can see that they limine. So for instance, the first day, the mean is five and then 3.25 and so on. And what I want to do is to save this. So what I can do then is to just save the array and let me call it daily meal. And taking the data daily mean and run the cell. And then I can go back into my phone directory and actually see what happens. So now I am in my file directory. What I want you to notice that we have the daily mean file here with the NPY extension. So this is a NumPy object, so it has saved the array with all the properties like the type and so on. So let's go back into Jupiter notebook and learn how to load this object. So if I want to get the daily mean back, I can use the load function. Inside this function, I can take in the name of the file, which is daily mean dot p y. And if I run this cell, we get the daily mean vector. So let's say that you want to save a lot of files. For instance, you want to save both the daily mean and the rain data. So what you can do is to compress these two vectors into one file which contains both. So this is done with np dot save C, which stands for saved sit. And then I can take in the name, which I want to say in with us. So let's say I want to save it as rainy days. And then I take in everything I want to save in this file here. So for instance, I want to save daily meal, and I also want to save the rain data. So now I can run this cell and look into my file directory. So here at the bottom, you see that now we have the rainy day dot MPC. So this again is a non py file and the C here stands for compressed. So let's go back and see how we can open this file again. So you open the NP is set files the same way as you would open an MPI file. So you write np dot load and then rainy days, that end piece set. So if I try to run this code here, you will see that what you get back is the NPC file objects. So if you want to see what is inside and peace see object, you can use the file attributes. And you see that it contains two things. One thing which is calls array one or r, one, and another thing which is calls or two. And essentially this thing here will work as a dictionary. So if I want to take out the array, one thing here, what I can do is let me just copy this line here. And what I can do is to take are 0, run this here. And what we get out is the first thing we into the rainy days file. The same thing I can do with array one. So let me just paste this line again and write array one. And here we see that we get the array containing all the rain data. But let's say that it has been some time since you are worked with it and you don't remember what the area 10 was. So you can also give in a specific name instead of error is 0 and everyone in today's save set function. So it makes it easier to remember what the data was. So let me copy this line here and just modify it. And I want to daily meal to be called daily mean. So I just set daily mean equal to daily mean. And I want to rain theta to be equal to rent data. So let me now run this cell and see what happens if I load this data back. So let's now ask what files it contains. So now you see that it has two files called daily mean and frame data. So if I want to take out to daily mean now I can do np.log10 and then the name of the file. And then I can take in the name of the file, for instance, daily mean from the cell and we get out the daily mean here. So the daily mean here is referring to this variable here. So for instance, if I change this one to be the mean from the cell, from the cell. Now you see that the name of the first one is me. And I can get it out with writing mean here. And taking not this was everything I wanted to say about loading and saving data. So see you again in the exercises. 70. Exercise Set - Boston Data: Hi and welcome to this final exercise video, which is exercise set a lemon. And in this exercise set we are going to work with broader big dataset, which is called the Boston datasets. The Boston dataset contains housing data from the Boston area. Here you can see that it has 506 houses which is sold. And it has 14 attributes which are numbered down here. So this is a rather famous dataset which is used a lot in machine learning. So here I have just copied it from scikit-learn and downloaded it and saved it as a text file. So the first exercise is just going to import the standard packages here. And then you are going to import the text file, which contains the Boston dataset. And then you're going to find the shape of the dataset and tried to print it out there after we are going to start answering some questions. So we are going to plot how many rooms in a histogram. And we're going to do the same with the prices, which is column 13. And finally, we are going to plot a scatter plot with the number of rooms and one axis and the host prices at one axis. And then you are going to look at the graph and just see if you can see a trend. For exercise 2, you are going to figure out how many houses were sold by the river, both the value of the house and how many houses were sold by the river in percent. So if a house is by the river or not, is contained in what's called dummy variable. And this is a way to represent categorical data, like being by the river and not being by the river is two categories. And a dummy variable is way too represented as numbers. So in this case, if a house is pi of the river, it has value one and it has value 0 if it is not by the river. Exercise 5 is just going to be finding the averages and the Min and max in each column. And exercise 6 is about comparing the crime rate in sheep housing areas compared to average housing areas. So what do you think is that areas with sheep houses has a lot more crime than average areas. So here we are just going to confirm that. And the final thing is that we are going to save the data. So good luck with exercise. And as always, you can find a solution in the same folder as you found the exercise. See you in the next video. 71. Neighboring Libraries Intro: Hi, welcome back. First of all, congratulations on more or less finishing the course. We now just have two videos left. In this video, I'm going to talk about neighboring libraries, meaning other Python libraries that's very close to NumPy. In the next video, I'll give you some further resources. And NumPy NAN both means in all say goodbye. A lot of Python libraries depend on NumPy or at least interact heavily with NumPy. In this video, I'm just going to showcase for libraries that heavily utilized NumPy. So we won't be needing any Jupyter Notebook sheets. I'll just show you their websites for the different packages and briefly talk about what they are doing. The first library I want to mention is here, this is matplotlib. This is a standard library for visualizations in Python. Describes itself as the comprehensive library for creating static animated, an interactive visualizations in Python. So just to give you a very simple example, I've gone here where it explains how to do a very simple plot. And you can see here that here is the code. You don't need to understand the code at all, but you can't sit at NumPy is definitely important to generate a data. One is typically reporting. One of the common ways of doing this is with NumPy here, consider to do np.array range to create some t-values, which I think represents time here afterwards to create some x values here by using np.zeros and piddle pi is you have seen previously with dinner and the rest of the code is matplotlib code here figures and accesses made and then he plotted T and S values. You can see here that if you already understand NumPy and quite a lot of business actually already understood. So matplotlib is a great library and a highly recommend looking a bit into it. The second library I want to mention is pandas. Pandas is a data structure library for managing data, handling data, wrangling data, and so on. This is one of the defacto libraries for working with data analysis in Python. And Pandas essentially provides two different data structures. One of them is called a series and the other is called a DataFrame. And the fact is that the series is essentially just a NumPy array with some extra functionality. Now I'm into their documentation page and I'm really just skip to a specific point. Series is mates. So here you can see that he used pandas, which is abbreviated PD, to make a series. And the fact is that when you make a series, one of the most common ways to do it. And so just specify a NumPy array. Here you can see that a go to random module to create five random numbers. And then secondly, you specify an index. So here we can see our output is essentially just a labeled NumPy array. So here we have the values that you've specified, but you also have a label for each of them. I say label, this is what pandas calls an index. If you're not used to dealing with NumPy arrays, then getting into series is no problem at all. It's almost the same functionality. You can see here that they have a datatype needs surely recognize the float 64. So once you know NumPy, getting you to Pandas Series object is really simple. The third library I wanted to show is scikit-learn. This is one of the most popular libraries for machine learning in Python. Can see here on frontpage lists a few bullet points that is simple and efficient tool for predictive data analysis. It is accessible to everybody and reusable in various contexts. And most importantly, it's built on numpy, scipy and matplotlib. Numpy specifically plays a very important role in scikit-learn. And here you can see all the different types of algorithm you can do like classification algorithms, regression algorithms, clustering, dimensionality reduction, model selection, preprocessing, and so on and so on. The fact is that if you know NumPy than learning, scikit-learn will be a lot easier. Just to show an example here I'm inside scikit-learn, and this is the classroom making linear regressions. I don't want to talk about all the stuff here, but if we scroll down, we can look at an example. And here you see the first thing you do is to import numpy as np. This is simply because NumPy is often used to generate mock data. Here you can see that you generate some x values, and this is just generated for np.array. And it can also recognize a few other functions we have done previously, like np dot, dot, dot, product, and the rest of the code here is really from scikit-learn to make some kind of linear regression and fits on values. And you can extract some information like scores and coefficients and intercepts. So again, you see that if you already know numpy and a lot of the code is already here really explained to you. You can then focus on important parts of scikit-learn. If you go into the documentation of scikit-learn, we'll just assume you already know numPy. You won't find any explanations of these functions here, insider documentation. So the fourth and final library is PyTorch. Pytorch is another machine learning framework, has really focused on deep learning. So it describes itself as an open source machine learning framework that accelerates the path from research prototyping to production deployments. If you go into the documentation for PyTorch, they have their own Tutorial page. If you really just go to the start, the tutorial here for tensors, you immediately find out that this is really related to NumPy. One of the first sentences here, answers are similar to NumPy. Arrays except at tensors can run on GPUs or other hardware accelerators. In fact, tensors a NumPy areas can often share the same underlying memory, eliminating need to copy data. First of all, you realize it if you didn't know numpy and reading this description wouldn't mean anything to you. This is another library that just assumes that we already know NumPy before you even start learning PyTorch. Secondly, the basic datatype of PyTorch tensors is incredibly similar to NumPy is ND arrays. You can see here that in the inputs you get to import numpy really quickly. And a lot of the documentation in the beginning here is how to convert between numpy arrays and PyTorch tensor type. All of these for libraries are heavily dependent on NumPy. And as you can see, many of them just assumes that the already know NumPy before starting to learn them. Since we have finished this course is puts you at a great advantage for learning new Python libraries that the pandas numpy. Finally, in the next video, I'll give you some further resources for learning NumPy. 72. Further Topics and Goodbye!: In this final video, I just want to give you a few further resources for your NumPy learning. Of course, first of all is a numpy homepage. This is a really great page and recomputation has excellent. So if you just go to the NumPy homepage, then you can see the documentation page and also the learning page. Of course, a lot of the things we've talked about you can find here in the documentation and learning page. Secondly, if you scroll down here on the homepage, you can see the ecosystem here. Here you can see more libraries that are heavily dependent on NumPy three. So for instance, Pandas in the last video draw our hear a lot more. So in signal processing, image processing, graphs and networks, numpy is really used in a lot of different libraries. A second thing I wanted to show you is the NumPy 100 GitHub repo. If you just search for num pi 100 exercises and you'll easily find this. This is a GitHub repo and here can find 100 NumPy exercises for it says this is a collection of NumPy exercises from NumPy Mamie list, stack overflow and the NumPy documentation and the author also created some problems himself to reach the 100 limit. So if you just go here to read them on GitHub, and you can find this page here, and here is 100 exercises. And in the beginning they're really simple. So it's like import NumPy or create a null vector of size 10 and so on. But as you progress towards the 100th, they get quite difficult. So here in 1809 you can see the question how to get the largest values in an array. So not just v largest, for instance, 33 largest elements in an array. Thirdly, if you'd like to teach instead, that means in a users and you can check out our YouTube page at TM quest. Here you can find some free content and tightened videos as well as content on late Tech and take some other related topics. If this sounds like something you're interested in, then check it out. This is it for the course. We hope you had a great time and hope you learned a lot. So finally, I want to congratulate you, add finishing this course and you bye, goodbye.