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.
