0 1 00:00:00,210 --> 00:00:08,160 Now, in the last lesson, we managed to parse all of the tweets that we got back from our results JSON 1 2 00:00:08,580 --> 00:00:10,290 into an array of tweets, 2 3 00:00:10,350 --> 00:00:12,340 that is an array of strings. 3 4 00:00:12,360 --> 00:00:20,180 Now, we want to be able to run our predictions on that array and get back an array of sentiment labels. 4 5 00:00:20,670 --> 00:00:27,510 So instead of using this particular method, which can only take a single piece of text, we need to use 5 6 00:00:27,510 --> 00:00:28,620 something else. 6 7 00:00:28,620 --> 00:00:36,900 So down here, let's tap into our sentimentClassifier again and let's hit ".pre" just to see all of 7 8 00:00:36,900 --> 00:00:38,820 the different prediction methods, 8 9 00:00:38,820 --> 00:00:45,980 and there's only five of them. The one that we've already used is this first one that's just making a 9 10 00:00:45,980 --> 00:00:53,540 prediction on a single piece of text. The next one is something that takes a TweetSentimentClassifier 10 11 00:00:53,690 --> 00:01:02,900 input data type to make a prediction, or you can take an array of TweetSentimentClassifier inputs and 11 12 00:01:02,900 --> 00:01:05,680 get an array of outputs back. 12 13 00:01:05,870 --> 00:01:12,740 And this is making a batch prediction using the structured interface of the CoreML Natural Language 13 14 00:01:12,740 --> 00:01:13,940 processes. 14 15 00:01:13,940 --> 00:01:20,450 Now, we can also specify some options and these options if you read the API docs include whether if you 15 16 00:01:20,450 --> 00:01:25,330 want to pick to use the CPU or the GPU to make this prediction 16 17 00:01:25,490 --> 00:01:31,640 depending on how resource-intensive this whole process is going to be. And you can also do that for batch 17 18 00:01:31,640 --> 00:01:33,500 processing as well. 18 19 00:01:33,770 --> 00:01:39,800 Now, in our case, we're interested in this method where we can batch process all of our tweets through 19 20 00:01:39,830 --> 00:01:43,630 our sentimentClassifier, so that's the one that I'm gonna put in here. 20 21 00:01:43,970 --> 00:01:51,680 Now, it would be nice to be able to simply put our tweets array in here and get our sentiments back as 21 22 00:01:51,740 --> 00:01:58,640 an array. But unfortunately, you can see we get a error here that says, cannot convert value of type String 22 23 00:01:58,640 --> 00:02:08,270 array, which is what tweets is, to the expected type which is a TweetSentimentClassifierInput array. 23 24 00:02:09,140 --> 00:02:15,920 In order for this to work, we have to change this tweet array from being an array of Strings to an array 24 25 00:02:16,010 --> 00:02:21,370 of TweetSentimentClassifierInput objects. 25 26 00:02:21,380 --> 00:02:27,590 So that's very easy to change. But then, we have a problem down here because we're trying to convert a 26 27 00:02:27,590 --> 00:02:35,570 string that's a single tweet to an array that can only take TweetSentimentClassifierInput objects. 27 28 00:02:36,020 --> 00:02:40,580 So in that case, we have to convert our tweet. 28 29 00:02:40,580 --> 00:02:53,380 So let's say let tweetForClassification = tweetSentimentClassifierInput, we initialize it with 29 30 00:02:53,500 --> 00:03:03,290 tweet which is a string. And then we append, instead of the tweet which is the string, we append our 30 31 00:03:03,290 --> 00:03:11,270 tweetForClassification which is now in the right data type. And now, we fixed that problem. But we, of 31 32 00:03:11,270 --> 00:03:17,900 course, get another problem. Always remember that Churchill once said that "Success is going from failure 32 33 00:03:17,900 --> 00:03:21,570 to failure without loss of enthusiasm." 33 34 00:03:21,620 --> 00:03:27,320 So that's exactly what we need to do when we're programming. In most cases, you're going from bug to bug 34 35 00:03:27,410 --> 00:03:28,440 and error to error, 35 36 00:03:28,670 --> 00:03:36,530 but let's try to not lose our enthusiasm. In this case, the reason is because the sentimentClassifier 36 37 00:03:36,590 --> 00:03:42,500 can throw, but it's not marked with a "try" and the error is not handled. 37 38 00:03:42,500 --> 00:03:49,760 Now, previously, we simply marked it with a forced "try" to just force this prediction to go through, but 38 39 00:03:49,760 --> 00:03:54,450 that was because we were testing our code and we weren't expecting to keep that. 39 40 00:03:54,470 --> 00:03:56,220 In fact, I'm going to delete it now. 40 41 00:03:56,360 --> 00:04:01,730 But in this case, this is gonna be our working code, so I don't want to force the "try," I just want to use 41 42 00:04:01,760 --> 00:04:10,240 a normal "try," but that means I have to hold it inside a "do" and "catch" block. Inside my "do" block, 42 43 00:04:10,250 --> 00:04:15,730 I, of course, have my "try." And inside my "catch" block, I'm simply going to print 43 44 00:04:21,820 --> 00:04:23,010 my error. 44 45 00:04:23,290 --> 00:04:23,630 All right. 45 46 00:04:23,650 --> 00:04:33,820 So, now we have one more error and that's because using this sentimentClassifier which, remember, is something 46 47 00:04:33,820 --> 00:04:40,120 that has global scope inside the class, inside a closure or a callback. 47 48 00:04:40,120 --> 00:04:45,120 Remember, you can tell when we're inside a closure or a callback with that in keyword. 48 49 00:04:45,310 --> 00:04:53,140 And this entire part is the closure, then we have to mark this with a self. 49 50 00:04:53,170 --> 00:04:54,990 So let's just click fix. 50 51 00:04:55,210 --> 00:05:01,750 Now, the final warning we're getting is that we've gotten this thing, but we haven't really done anything 51 52 00:05:01,840 --> 00:05:02,290 with it. 52 53 00:05:03,220 --> 00:05:11,640 So let's do something with it. Let's store it inside a constant. Let's call it predictions. And let's go 53 54 00:05:11,640 --> 00:05:24,440 ahead and print predictions at index zero .label, so just as what we did previously. We're tapping into 54 55 00:05:24,740 --> 00:05:31,640 that label property of the prediction which, remember, is that positive, negative, or neutral. 55 56 00:05:32,090 --> 00:05:35,120 So let's hit run and see what we get. 56 57 00:05:37,480 --> 00:05:37,770 All right. 57 58 00:05:37,780 --> 00:05:46,750 So the first tweet had a label of neutral. If we wanted to see the label for all of the predictions inside 58 59 00:05:46,750 --> 00:05:49,230 this array of prediction, 59 60 00:05:49,240 --> 00:05:52,710 then we, again, need to use a loop. 60 61 00:05:53,140 --> 00:05:56,200 Let's delete this print statement, and instead, 61 62 00:05:56,200 --> 00:05:57,070 let's write 62 63 00:05:57,070 --> 00:06:04,060 a for prediction in predictions. 63 64 00:06:04,670 --> 00:06:11,650 Print prediction, singular, .label. 64 65 00:06:12,020 --> 00:06:18,650 Now, if you find that too similar, you can also just call this "pred," for "pred" in predictions. 65 66 00:06:18,650 --> 00:06:26,920 Just make sure that you understand that this is the singular one and this is the array. 66 67 00:06:26,950 --> 00:06:34,870 So, now we have all of our positive, neutral, or negative predictions for all hundred tweets that we have 67 68 00:06:34,870 --> 00:06:35,880 processed. 68 69 00:06:35,890 --> 00:06:38,110 So pretty neat, right? 69 70 00:06:38,110 --> 00:06:43,310 Now, wouldn't it be nice to be able to tally this up as almost like a score? 70 71 00:06:43,390 --> 00:06:50,590 So, say, if one of the tweets was marked as negative, then we subtract one from the score, but if it was 71 72 00:06:50,590 --> 00:06:57,340 marked as positive, then we add one to the score. And if it's neutral, it doesn't affect the score, 72 73 00:06:57,340 --> 00:07:05,080 and we see depending on what it is that we search for, say, @Apple or @CocaCola, we see what is the overall 73 74 00:07:05,080 --> 00:07:10,740 sentiment over a hundred tweets. And we can do that by keeping score. 74 75 00:07:10,990 --> 00:07:18,270 So let's create a local variable called sentimentScore and let's start it off at zero. 75 76 00:07:18,430 --> 00:07:25,090 Now, instead of printing all of these prediction labels, we're going to say, let sentiment = 76 77 00:07:27,820 --> 00:07:47,350 pred.label. And if the sentiment is equal to positive, then sentimentScore is plus equal 1. 77 78 00:07:47,530 --> 00:07:52,480 So sentimentScore gets increased by 1. 78 79 00:07:52,480 --> 00:08:06,010 Now else if the sentiment is equal to negative, then the sentimentScore gets minus equal 1. 79 80 00:08:06,060 --> 00:08:14,100 So we subtract 1 from the score. And we can ignore the "else" case which is basically neutral. 80 81 00:08:14,900 --> 00:08:21,740 We're not going to affect the score in that case. After this, all of this loop has gone through, 81 82 00:08:21,740 --> 00:08:25,660 let's now print our sentimentScore. 82 83 00:08:26,150 --> 00:08:36,800 Let's run this based off tweets that contain or mention @Apple that are English for 100 of them. 83 84 00:08:36,800 --> 00:08:40,100 Let's see what we get. We get minus 15. 84 85 00:08:40,100 --> 00:08:46,000 So overall, the sentiment over 100 tweets is a bit negative. 85 86 00:08:46,010 --> 00:08:47,360 Now, let's try something else. 86 87 00:08:47,360 --> 00:08:51,290 Let's try something like @Facebook. 87 88 00:08:51,290 --> 00:08:54,830 How do people feel about Facebook given all of the controversy? 88 89 00:08:58,220 --> 00:09:00,080 Interesting, minus 3. 89 90 00:09:00,140 --> 00:09:02,750 So people dislike it less than Apple even. 90 91 00:09:02,750 --> 00:09:06,260 Now, let's try this with a hashtag instead 91 92 00:09:06,290 --> 00:09:13,640 maybe, something that we know people always write positive things about when they have a particular hashtag. 92 93 00:09:13,640 --> 00:09:16,570 One of them is #blessed, right? 93 94 00:09:16,580 --> 00:09:20,270 People say, "Oh, I have the best life. #blessed." 94 95 00:09:20,270 --> 00:09:21,020 Something like that. 95 96 00:09:21,560 --> 00:09:26,360 Let's see what the score is for that, just to make sure that our scoring and our sentiment analyze it 96 97 00:09:26,360 --> 00:09:29,590 everything is actually working properly. 97 98 00:09:29,660 --> 00:09:30,240 All right, great. 98 99 00:09:30,340 --> 00:09:35,180 So that's great. For the tweets that have the #blessed, 99 100 00:09:35,180 --> 00:09:37,740 we're getting a score of 36. 100 101 00:09:37,910 --> 00:09:40,090 That's really, really positive. 101 102 00:09:40,130 --> 00:09:45,240 And you can actually have fun here and try and play around with all sorts of different things. 102 103 00:09:45,410 --> 00:09:52,720 Say, what happens when you try @Trump or @Obama or hashtag a particular stock symbol. 103 104 00:09:52,790 --> 00:09:53,530 See what happens. 104 105 00:09:53,530 --> 00:09:59,240 What is the overall sentiment? Instead of having to read through all of the tweets, try to gather the 105 106 00:09:59,240 --> 00:09:59,950 sentiment. 106 107 00:09:59,990 --> 00:10:06,620 You can actually do this automatically now using all of this code that we have written. Now in the next 107 108 00:10:06,620 --> 00:10:13,460 lesson, we're going to be making some UI updates so that our app isn't just sitting there and we're doing 108 109 00:10:13,460 --> 00:10:16,450 everything inside the debug console. 109 110 00:10:16,550 --> 00:10:19,670 So for all of that and more, I'll see you on the next lesson.