0 1 00:00:00,550 --> 00:00:01,110 All right. 1 2 00:00:01,110 --> 00:00:04,940 So in this lesson we're gonna do a couple of things. 2 3 00:00:05,130 --> 00:00:12,210 We're gonna be plotting our gradient descent path on our 3D surface so we can see our algorithm slowly 3 4 00:00:12,210 --> 00:00:15,420 working its way down to the bottom of the bowl. 4 5 00:00:15,540 --> 00:00:23,310 But this is also a really good opportunity to learn a little bit more about numpy's n-dimensional 5 6 00:00:23,400 --> 00:00:30,000 arrays because these things are incredibly powerful and we're gonna be taking a look at how we can append 6 7 00:00:30,000 --> 00:00:36,330 values to arrays, how we can concatenate arrays, how we can slice arrays and how we can select particular 7 8 00:00:36,330 --> 00:00:43,680 columns of an array. Let's commemorate the upcoming topics with a new section heading. 8 9 00:00:44,690 --> 00:00:51,620 So I'm going to change this cell to Markdown and then I'm going to put two pound symbols here and then I'll 9 10 00:00:51,620 --> 00:01:07,240 write "Graphing 3D Gradient Descent & Advanced Numpy Arrays". And I'll hit Shift+Enter. 10 11 00:01:07,240 --> 00:01:12,710 I'm also going to add a few more cells to the bottom so that way I'm working more in the center of the 11 12 00:01:12,710 --> 00:01:19,640 screen. Now to do our plotting what we're going to do is we're gonna scroll a little bit up and we're 12 13 00:01:19,640 --> 00:01:28,290 going to copy this cell here, I'm going to copy the cell and I'm going to paste this cell here. 13 14 00:01:28,740 --> 00:01:32,100 And the reason I'm doing this is so that I can add some code to it. 14 15 00:01:32,250 --> 00:01:38,310 I want to modify the cells so we have a record of what we've been doing but this is also the cell which 15 16 00:01:38,370 --> 00:01:42,880 is gonna contain the code that tracks the progress of our gradient descent. 16 17 00:01:42,900 --> 00:01:49,840 So I'm going to add some code to this. Now, as before the values that we're gonna be tracking are how 17 18 00:01:49,840 --> 00:01:56,550 are our parameters change as the loop runs and the place where I'm going to store all these values that we're 18 19 00:01:56,550 --> 00:02:04,650 gonna be tracking is going to be a variable that I'm going to call values_array and 19 20 00:02:04,650 --> 00:02:11,090 the very first value this values array is going to have is going to consist of our initial guess, our 20 21 00:02:11,670 --> 00:02:13,510 params. 21 22 00:02:13,650 --> 00:02:15,450 So leaving the code like this, 22 23 00:02:15,540 --> 00:02:20,490 let's take a really quick look at the shape of our values array. 23 24 00:02:20,760 --> 00:02:29,730 So I'm going to print the "values_array.shape" and see what I get. 24 25 00:02:29,850 --> 00:02:35,340 The result is gonna be the very first line that's printed below the cell so I can see that this is a 25 26 00:02:35,340 --> 00:02:42,870 tuple and my array just consists of two elements and that's no surprise, those elements are gonna be 26 27 00:02:42,990 --> 00:02:46,630 1.8 and 1.0. 27 28 00:02:46,920 --> 00:02:53,190 And that's all this shape attribute is showing us. Now the thing is, I can transform this array if I want 28 29 00:02:53,190 --> 00:03:02,100 to. Instead of having a one dimensional array with two elements, I can have a two dimensional array with 29 30 00:03:02,130 --> 00:03:05,350 one element each instead. 30 31 00:03:05,490 --> 00:03:08,380 But why would I want two dimensions? 31 32 00:03:08,400 --> 00:03:16,230 Well what I want to do is I want to keep all the x values in one dimension and then I want to keep all 32 33 00:03:16,230 --> 00:03:20,520 the y values in the second dimension. 33 34 00:03:20,520 --> 00:03:28,290 So what I'm going to do is I want to transform my array into a new shape so handily there is something 34 35 00:03:28,290 --> 00:03:33,240 called a reshape method which takes two inputs - 35 36 00:03:33,240 --> 00:03:39,080 one is the number of rows and the other is the number of columns. 36 37 00:03:39,090 --> 00:03:44,250 So rows are first so it's gonna be 1,2 - 37 38 00:03:44,460 --> 00:03:48,190 those are gonna be the arguments to the reshape method. 38 39 00:03:48,190 --> 00:03:55,530 Now if I rerun the cell have a look at the output below the cell to see how many rows and how many columns 39 40 00:03:55,830 --> 00:03:57,460 my array has now. 40 41 00:03:58,380 --> 00:04:06,570 So you should see this updated to 1,2 - one row, two columns. I now have a two dimensional array. 41 42 00:04:07,110 --> 00:04:13,560 My x value is gonna be in my first dimension and my y value is going to be in my second dimension. 42 43 00:04:14,700 --> 00:04:15,270 Okay yeah, 43 44 00:04:15,300 --> 00:04:20,740 so you might say "Yeah Phillip great preamble, but where are you going with this?". 44 45 00:04:20,740 --> 00:04:27,750 And what I would say to that is I'm setting the scene for the code I'm going to add to my for loop right 45 46 00:04:27,750 --> 00:04:28,040 here. 46 47 00:04:28,710 --> 00:04:36,540 But before I do that and move on to the code inside the gradient descent, let me add a new cell below 47 48 00:04:36,540 --> 00:04:44,680 this one and just go through a few methods and a few techniques for working with multi-dimensional arrays. 48 49 00:04:44,790 --> 00:04:54,940 So I'm going to add a little comment here and I'm going to call this "Advanced Numpy Array Practice". 49 50 00:04:55,650 --> 00:05:00,000 And the first thing I'm going to do of course is create a dummy array. 50 51 00:05:00,000 --> 00:05:01,190 This array is going to have a name, 51 52 00:05:01,220 --> 00:05:08,850 it's going to be called kirk, and it's going to be equal to np.array, so we're creating an array, parentheses, 52 53 00:05:08,850 --> 00:05:13,440 and then I want this array to have one row and two columns. 53 54 00:05:13,440 --> 00:05:21,510 So I'm going to have one square bracket and then a second square bracket and inside I'm going to put 54 55 00:05:21,600 --> 00:05:22,230 a string. 55 56 00:05:22,230 --> 00:05:32,020 I'm going to say "Captain" and then comma and then I'm going to have another string and that's gonna read "Guitar". 56 57 00:05:32,130 --> 00:05:37,230 So two strings surrounded by two square brackets. 57 58 00:05:37,230 --> 00:05:41,140 So just to verify that we indeed have a two dimensional array, 58 59 00:05:41,280 --> 00:05:51,180 let's print out "kirk.shape" below the cell and hit Shift+Enter. There we see that indeed we have 59 60 00:05:51,240 --> 00:05:56,830 one row and two columns by using this notation here. 60 61 00:05:56,880 --> 00:05:57,380 All right. 61 62 00:05:57,390 --> 00:06:04,230 So upwards and onwards. This time we're gonna create a two by two array. 62 63 00:06:04,230 --> 00:06:07,640 So this is gonna be two rows, two columns. 63 64 00:06:07,830 --> 00:06:18,640 And I'm going to call this array "hs_band" and we've said it's equal to "np.array()", 64 65 00:06:19,140 --> 00:06:24,060 and then I'm going to add two square brackets again and inside the second square bracket I'm going to 65 66 00:06:24,060 --> 00:06:29,760 add a string and call it "Black Thought". 66 67 00:06:29,880 --> 00:06:36,740 And then after the string and I'm going to add a comma and then another string "MC" and then after that first 67 68 00:06:36,750 --> 00:06:44,040 closing square bracket I'm going to add another comma and then I'm going to open another square bracket, 68 69 00:06:44,040 --> 00:06:53,600 and add the string "Questlove", comma and then the string "Drums" and then you'll have two square brackets at 69 70 00:06:53,600 --> 00:06:56,250 the end and the parentheses. 70 71 00:06:56,300 --> 00:07:07,420 So this is our second array and let's print out the shape. So "print(hs_band.shape)" and 71 72 00:07:07,470 --> 00:07:14,110 here we can see that indeed this array is two by two - two rows two columns. 72 73 00:07:14,130 --> 00:07:20,530 Now when working with multi-dimensional arrays like this let me ask you a question. 73 74 00:07:20,880 --> 00:07:30,020 How do you think we would go about selecting a particular item in the array? So previously we just used 74 75 00:07:30,110 --> 00:07:34,870 the square bracket notation and then we supplied an index. 75 76 00:07:34,880 --> 00:07:38,270 Let's see what happens when we do that on a two dimensional array. 76 77 00:07:38,300 --> 00:07:46,040 So I'll print and I'll just put down in the string the code I'm going to add after the string. 77 78 00:07:46,050 --> 00:07:52,230 So I'm going to say "hs_band[0]", 78 79 00:07:52,510 --> 00:08:00,540 and then after the string I'm going to add a comma and then put the actual Python code here "hs_band[0]". 79 80 00:08:00,780 --> 00:08:09,300 I'm going to hit Shift+Enter here. So we can see here that if I use the very, very same approach with a two dimensional 80 81 00:08:09,300 --> 00:08:15,840 array for selecting a particular item as with a one dimensional array I don't get back one item, 81 82 00:08:15,960 --> 00:08:26,160 instead I'm getting back an entire row. I'm getting back all the elements in that first row. But the thing 82 83 00:08:26,160 --> 00:08:27,810 is that kind of makes sense, right? 83 84 00:08:27,810 --> 00:08:31,760 We have two dimensions so we shouldn't be supplying one index, 84 85 00:08:31,800 --> 00:08:35,680 we should be supplying two indices. 85 86 00:08:35,760 --> 00:08:36,900 How do we do that? 86 87 00:08:36,930 --> 00:08:38,820 Let me just copy this line of Python code here. 87 88 00:08:40,790 --> 00:08:42,220 And add a print statement. 88 89 00:08:42,230 --> 00:08:44,060 Paste the print statement below. 89 90 00:08:44,510 --> 00:08:51,010 And then instead of having just "hs_band[0]", 90 91 00:08:51,230 --> 00:08:57,540 I'm going to add another pair of square brackets here and between those I'm going to put the value 1. 91 92 00:08:58,780 --> 00:09:06,140 I'm going to add that to my string as well so that we're consistent and I'm going to hit Shift+Enter and what 92 93 00:09:06,140 --> 00:09:14,150 you should see is that in this case we're selecting one particular element, we're selecting the first 93 94 00:09:14,150 --> 00:09:18,500 row and then the first column in that row. 94 95 00:09:18,500 --> 00:09:25,790 So we're honing in on the string "MC". If you have trouble seeing this in your print statements then 95 96 00:09:26,150 --> 00:09:33,620 you can put a few spaces here and a semicolon, might make it a little easier and then you'll have a nice 96 97 00:09:33,620 --> 00:09:41,000 separation between the the string and the value that you're getting back with your Python code. 97 98 00:09:41,010 --> 00:09:41,290 All right. 98 99 00:09:41,290 --> 00:09:46,460 So this was a really one difference between working with a one dimensional array and a two dimensional 99 100 00:09:46,460 --> 00:09:47,110 array. 100 101 00:09:47,420 --> 00:09:48,500 Now, as a challenge, 101 102 00:09:48,500 --> 00:09:55,460 can you modify this print statement to select the word "Questlove" and have that printed out right here 102 103 00:09:55,460 --> 00:09:57,740 where it says "MC" currently? 103 104 00:09:57,740 --> 00:10:04,490 I'll give you a few seconds to pause the video and give this a shot. So I hope you had a chance to solve 104 105 00:10:04,490 --> 00:10:05,580 this. 105 106 00:10:05,590 --> 00:10:08,060 Questlove is in the second row. 106 107 00:10:08,060 --> 00:10:09,260 So we start counting at zero. 107 108 00:10:09,260 --> 00:10:16,120 Second row is at index 1 and it is the first item in the second row, 108 109 00:10:16,130 --> 00:10:17,240 so first column. 109 110 00:10:17,240 --> 00:10:20,680 So this would be column zero. 110 111 00:10:20,720 --> 00:10:24,510 Let me Shift+Enter to prove to you that this is indeed the case. 111 112 00:10:24,620 --> 00:10:25,260 And there we go. 112 113 00:10:25,310 --> 00:10:28,370 We see Questlove printed out below. 113 114 00:10:28,370 --> 00:10:32,010 Now let's create another array but through a different way. 114 115 00:10:32,060 --> 00:10:33,800 I'm going to call this array 115 116 00:10:33,800 --> 00:10:42,750 "the_roots". I'm going to set it equal to "np.append", 116 117 00:10:42,920 --> 00:10:46,930 so I'm not going to write "np.array", I'm going to write "np.append". 117 118 00:10:47,120 --> 00:10:53,690 I'm gonna open the parentheses and inside these parentheses I'm going to supply three arguments, three inputs - 118 119 00:10:54,170 --> 00:11:02,360 the first argument is gonna be the array I want to append items to, this is gonna be "arr = hs_ 119 120 00:11:02,480 --> 00:11:10,180 band", I'm going to put comma and supply my second argument and these are gonna be the values so I'm going to write 120 121 00:11:10,640 --> 00:11:19,030 "values = kirk" and then I'm going to supply the third argument and this is going to be the axis. Axis is gonna 121 122 00:11:19,040 --> 00:11:28,420 be equal to zero. And below all this I'm going add a print statements, so I'm going to say "print(the_roots)". 122 123 00:11:28,580 --> 00:11:33,710 Now before I hit Shift+Enter, I'm going to make sure my variable names are the same. 123 124 00:11:33,710 --> 00:11:34,250 So, 124 125 00:11:34,340 --> 00:11:44,570 so this is gonna be "the_roots = np.append(arr=hs_band, values= 125 126 00:11:44,600 --> 00:11:52,550 kirk, axis=0)" and then I am indeed printing this variable here, printing the_roots. 126 127 00:11:52,570 --> 00:11:59,390 Now let me Shift+Enter so you can see what this looks like. Now what we've got is that below the cell, there 127 128 00:11:59,390 --> 00:12:02,480 are six elements being printed out. 128 129 00:12:02,560 --> 00:12:11,170 We've got the four elements from hs_band and we've appended two extra elements, namely "Captain" and "Guitar" 129 130 00:12:11,590 --> 00:12:13,330 to these four elements. 130 131 00:12:13,450 --> 00:12:18,220 So our array called the_roots is actually three by two, 131 132 00:12:18,220 --> 00:12:20,370 it's a three by two array. 132 133 00:12:20,440 --> 00:12:25,000 Now let's take a look at this append method. The append method takes three arguments - 133 134 00:12:25,000 --> 00:12:30,510 the first one is, well, the element where the items are going to be appended to 134 135 00:12:30,800 --> 00:12:38,310 and the second argument here is our array which was appended to hs_band and then we've got 135 136 00:12:38,320 --> 00:12:39,590 this third argument here - 136 137 00:12:39,630 --> 00:12:47,940 axis; axis=0 and the first time I saw this I thought "Man, this is a really confusing word" but 137 138 00:12:47,960 --> 00:12:56,490 it's actually pretty simple. Axis basically means should we add our values as a row 138 139 00:12:56,810 --> 00:13:00,360 or should we add them as a column. 139 140 00:13:00,390 --> 00:13:03,270 So what we've done is we said "axis=0", 140 141 00:13:03,510 --> 00:13:10,980 and that means that our values inside kirk are added as a row on to our two by two array. So our two by 141 142 00:13:10,980 --> 00:13:14,680 two array became a three by two array. 142 143 00:13:14,880 --> 00:13:23,170 If axis instead was equal to one, then we would be trying to add our new values as a column. 143 144 00:13:23,170 --> 00:13:30,270 But you have to be careful with these axes. If you try to change this to one and press Shift+Enter it 144 145 00:13:30,320 --> 00:13:36,960 actually won't work, because Kirk is actually a one by two array and not a two by one array. 145 146 00:13:37,140 --> 00:13:44,220 So you have to be careful because your axes have to match you can't add up or append items to arrays 146 147 00:13:44,550 --> 00:13:47,700 where the dimensions don't match. 147 148 00:13:47,700 --> 00:13:56,780 Kirk has one row, two columns and you can't add a one row two columns as columns to a two by two. 148 149 00:13:57,030 --> 00:14:04,690 If you actually wanted to do that you'd have to reshape the Kirk array to be two by one. 149 150 00:14:04,710 --> 00:14:06,530 This is the only way it would work. 150 151 00:14:06,750 --> 00:14:14,790 In this case you would indeed get a two by three matrix, a two by three array. 151 152 00:14:14,970 --> 00:14:22,620 So I hope this makes sense - if you're appending stuff to an existing array then the shapes of the array 152 153 00:14:22,650 --> 00:14:25,310 have to be compatible. 153 154 00:14:25,380 --> 00:14:30,280 So in this case what I actually want to do is I want to add rows on to my existing array so I'm going to say 154 155 00:14:30,300 --> 00:14:31,990 axis=0 155 156 00:14:32,100 --> 00:14:35,390 and the way I've made these arrays the rows already match. 156 157 00:14:35,490 --> 00:14:36,810 So I'm going to hit Shift+Enter again. 157 158 00:14:36,890 --> 00:14:39,500 So you refresh this and you can see, indeed, 158 159 00:14:39,520 --> 00:14:45,090 okay I've got an artist and I've got a role in the band and here's another artist and here's another 159 160 00:14:45,090 --> 00:14:45,960 role in the band, 160 161 00:14:46,590 --> 00:14:54,010 and so on. Now I'm not gonna make you add all the band members of the roots individually that would be 161 162 00:14:54,460 --> 00:15:02,260 very, very time consuming but um let's just pretend this band has three members for now. 162 163 00:15:02,260 --> 00:15:09,960 And suppose that we want to select all the band members just by their nicknames. 163 164 00:15:09,970 --> 00:15:16,680 So we want to just take an entire column from this array. 164 165 00:15:16,730 --> 00:15:18,390 How would we do that? 165 166 00:15:18,440 --> 00:15:26,180 And the answer is that this is actually really, really, really easy to do with some special Python notation 166 167 00:15:26,330 --> 00:15:29,170 for slicing arrays. 167 168 00:15:29,180 --> 00:15:29,950 Let me show you. 168 169 00:15:30,080 --> 00:15:40,990 If I print out, uh, add a string here "Printing nicknames...", comma and here's how we slice our 169 170 00:15:40,990 --> 00:15:41,700 array. 170 171 00:15:41,710 --> 00:15:44,680 Here's how we only print out the first column. 171 172 00:15:45,090 --> 00:15:52,470 We're gonna say "the_roots[]", and I'm going to supply two values - 172 173 00:15:52,470 --> 00:16:02,460 the first one is gonna be a column and I'm going to have a comma and then we're to have a zero. 173 174 00:16:02,730 --> 00:16:09,030 So what we're saying here is - take all the rows, so a colon is the shorthand notation here for selecting 174 175 00:16:09,210 --> 00:16:10,260 all the rows, 175 176 00:16:10,260 --> 00:16:17,670 all the values in the rows and that second argument here, that zero refers to the first column. 176 177 00:16:17,730 --> 00:16:20,870 Let me hit Shift+Enter to show you what I mean. 177 178 00:16:21,090 --> 00:16:28,620 I'm going to scroll down and there you should see "Printing nicknames... ['Blackthorn', 'Questlove', 'Captain']". 178 179 00:16:29,740 --> 00:16:30,310 All right. 179 180 00:16:30,310 --> 00:16:33,640 So let's practice this one more time. 180 181 00:16:33,640 --> 00:16:40,070 I'm going to add another band member though, so I'm going to say the_roots and I'm going 181 182 00:16:40,090 --> 00:16:50,080 to update our roots array with "np.append" and for the array I'm going to choose the_roots 182 183 00:16:51,010 --> 00:16:54,550 and for the values I'm gonna say 183 184 00:16:54,820 --> 00:16:58,470 "values = [[]]", 184 185 00:16:58,540 --> 00:17:04,180 So I'm going to add the values here directly and then between those square brackets I'm going to provide 185 186 00:17:04,540 --> 00:17:05,590 two strings - 186 187 00:17:05,590 --> 00:17:08,320 the first one is gonna say "Malik 187 188 00:17:08,560 --> 00:17:23,400 B", and then comma, single quotes MC, closing square brackets comma, axis again is equal to zero. 188 189 00:17:23,460 --> 00:17:30,930 Having added another band member here let's print out the roles. I'm going to say "Printing 189 190 00:17:31,050 --> 00:17:35,180 band roles..." 190 191 00:17:35,590 --> 00:17:39,100 and then after the string, put a comma, 191 192 00:17:39,330 --> 00:17:42,580 and now I'm going to throw the ball over into your court. 192 193 00:17:42,650 --> 00:17:48,440 I'm going to challenge you to print out all the band roles in the roots. 193 194 00:17:48,440 --> 00:17:53,370 So I'm going to give you a few seconds to pause the video and write the Python code that will print 194 195 00:17:53,370 --> 00:17:58,600 out all the band members roles below the cell. 195 196 00:17:58,850 --> 00:18:00,830 And here's the solution. 196 197 00:18:01,400 --> 00:18:08,990 Again we're gonna use our array slicing notation so I'm going to say "the_roots[ 197 198 00:18:09,140 --> 00:18:13,870 :,1]", I'm going to hit Shift+Enter. 198 199 00:18:13,910 --> 00:18:21,280 I can see now that we've got two MCs, one set of drums and one guitar. All right, 199 200 00:18:21,310 --> 00:18:28,590 so with these array techniques covered we're ready to move on to graphing our gradient descent. And 200 201 00:18:29,020 --> 00:18:35,340 if you haven't heard of the roots then check out our song of theirs called "The Next Movement". 201 202 00:18:35,350 --> 00:18:38,220 That's one of my personal favorites. A long time ago, 202 203 00:18:38,230 --> 00:18:39,880 I actually went to see these guys live. 203 204 00:18:39,910 --> 00:18:46,660 They came down to London and I think one of the things that impressed me most was that during the performance 204 205 00:18:47,260 --> 00:18:49,520 the band members traded the instruments, 205 206 00:18:49,690 --> 00:18:55,030 so like the drummer took the guitar and the guitarist took the vocals and the vocalist took the bass 206 207 00:18:55,120 --> 00:18:56,020 and so on. 207 208 00:18:56,350 --> 00:19:02,020 And having done that they proceeded to play their next song just showing everyone in the audience that 208 209 00:19:02,020 --> 00:19:07,710 they weren't one trick ponies but actual musicians who could do more than than one thing. 209 210 00:19:07,720 --> 00:19:11,250 I mean I haven't gone to that many concerts but I've never seen that before. 210 211 00:19:11,290 --> 00:19:12,510 So yeah check out these guys. 211 212 00:19:12,520 --> 00:19:13,060 They're pretty cool.