C1W2.Assignment: Naive Bayes

时间:2024-07-17 07:16:56

理论课:C1W2.Sentiment Analysis with Naïve Bayes

文章目录

  • 加载包与数据
  • Part 1: Process the Data
    • Part 1.1 Implementing your helper functions
      • Instructions
  • Part 2: Train your model using Naive Bayes
    • 步骤
    • Prior and Logprior
    • Positive and Negative Probability of a Word
    • Log likelihood
  • Part 3: Test your naive bayes
    • 实现test_naive_bayes
  • Part 4: Filter words by Ratio of positive to negative counts
    • 实现get_ratio
    • 实现get_words_by_threshold(freqs,label,threshold)
  • Part 5: Error Analysis
  • Part 6: Predict with your own tweet

理论课: C1W2.Sentiment Analysis with Naïve Bayes

加载包与数据

from utils import process_tweet, lookup
import pdb
from nltk.corpus import stopwords, twitter_samples
import numpy as np
import pandas as pd
import nltk
import string
from nltk.tokenize import TweetTokenizer
from os import getcwd
import w2_unittest

注意,需要提前下载NLTK推特数据集和停用词表
加载数据并切分训练和测试集

# get the sets of positive and negative tweets
all_positive_tweets = twitter_samples.strings('positive_tweets.json')
all_negative_tweets = twitter_samples.strings('negative_tweets.json')

# split the data into two pieces, one for training and one for testing (validation set)
test_pos = all_positive_tweets[4000:]
train_pos = all_positive_tweets[:4000]
test_neg = all_negative_tweets[4000:]
train_neg = all_negative_tweets[:4000]

train_x = train_pos + train_neg
test_x = test_pos + test_neg

# avoid assumptions about the length of all_positive_tweets
train_y = np.append(np.ones(len(train_pos)), np.zeros(len(train_neg)))
test_y = np.append(np.ones(len(test_pos)), np.zeros(len(test_neg)))

Part 1: Process the Data

对于任何机器学习项目来说,一旦收集到数据,第一步就是对其进行处理,为模型提供有用的输入。

  • 去除噪音: 首先,要去除数据中的噪音,也就是去除那些不能说明太多内容的词语(停用词)。其中包括 "I, you, are, is,… "等所有常见词语,这些词语无法提供足够的情感信息。
  • 删除股市行情、转发符号、超链接和标签,因为它们无法提供大量的情感信息。
  • 删除推文中的所有标点符号。这样做的原因是,我们希望将带标点符号或不带标点符号的词视为同一个词,而不是将 “happy”、“happy?”、“happy!”、"happy "和 "happy. "视为不同的词。
  • 使用词干法,只跟踪每个词的词干。换句话说,我们将把 “motivation”、"motivated "和 "motivate "归入同一个词干 “motiv-”,从而对它们进行类似的处理。

之前的C1W1中的函数 process_tweet,可以完成以上功能。

custom_tweet = "RT @Twitter @chapagain Hello There! Have a great day. :) #good #morning http://chapagain.com.np"

# print cleaned tweet
print(process_tweet(custom_tweet))

答案:[‘hello’, ‘great’, ‘day’, ‘????’, ‘good’, ‘morn’]

Part 1.1 Implementing your helper functions

这里要完成情感词频字典(freqs)的构建,字典的键是一个元组(单词、标签),值是相应的频率。
在utils.py中,还实现了一个查询辅助函数(lookup),该函数接收 freqs 词典、一个单词和一个标签(1 或 0),并返回该单词和标签元组在推文集合中出现的次数。
例如,给定以下推文:
[“i am rather excited”, “you are rather happy”]
标签都是为1,函数将返回一个包含以下键值对的字典:
{
(“rather”, 1): 2,
(“happi”, 1) : 1,
(“excit”, 1) : 1
}

  • 请注意,对于给定字符串中的每个单词,都会为其分配相同的标签 1。
  • 请注意,"i "和 "am "这两个词没有被保存,因为它是一个停用词,已被 process_tweet 删除。
  • 请注意 "ather "这个词在推文列表中出现了两次,因此它的计数值是 2。

Instructions

创建一个函数 count_tweets,将推文列表作为输入,对所有推文进行数据预处理,然后返回一个字典。

  • 字典中的键是一个元组,包含词干及其类别标签,例如(“happi”,1)。
  • 值是该词在给定推文中出现的次数(整数)。
# UNQ_C1 GRADED FUNCTION: count_tweets

def count_tweets(result, tweets, ys):
    '''
    Input:
        result: a dictionary that will be used to map each pair to its frequency
        tweets: a list of tweets
        ys: a list corresponding to the sentiment of each tweet (either 0 or 1)
    Output:
        result: a dictionary mapping each pair to its frequency
    '''
    ### START CODE HERE ###
    for y, tweet in zip(ys, tweets):
        for word in process_tweet(tweet):
            # define the key, which is the word and label tuple
            pair = (word,y)
            
            # if the key exists in the dictionary, increment the count
            if pair in result:
                result[pair] += 1

            # else, if the key is new, add it to the dictionary and set the count to 1
            else:
                result[pair] = 1
    ### END CODE HERE ###

    return result
# Testing your function

result = {}
tweets = ['i am happy', 'i am tricked', 'i am sad', 'i am tired', 'i am tired']
ys = [1, 0, 0, 0, 0]
count_tweets(result, tweets, ys)

结果:
{(‘happi’, 1): 1, (‘trick’, 0): 1, (‘sad’, 0): 1, (‘tire’, 0): 2}

Part 2: Train your model using Naive Bayes

步骤

  • 训练朴素贝叶斯分类器的第一个步骤是确定类别的数量。
  • 然后为每个类别创建一个概率。
    P ( D p o s ) P(D_{pos}) P(Dpos)是文档为正类的概率。
    P ( D n e g ) P(D_{neg}) P(Dneg)是文档为负类的概率。
    使用以下公式,并将值存储在字典中:
    P ( D p o s ) = D p o s D (1) P(D_{pos}) = \frac{D_{pos}}{D}\tag{1} P(Dpos)=DDpos(1)

P ( D n e g ) = D n e g D (2) P(D_{neg}) = \frac{D_{neg}}{D}\tag{2} P(Dneg)=DDneg(2)

其中, D D D 是推文的总数, D p o s D_{pos} Dpos 是正面推文的总数, D n e g D_{neg} Dneg 是负面推文的总数。

Prior and Logprior

先验概率表示目标人群中某条推文是正面还是负面的潜在概率。换句话说,如果我们没有任何具体信息,盲目地从人群集合中挑选一条推文,那么这条推文是正面还是负面的概率是多少?具体公式为:
P ( D p o s ) P ( D n e g ) \cfrac{P(D_{pos})}{P(D_{neg})} P(Dneg)P(Dpos)
我们可以取先验值的对数来调整它的大小,我们称之为 logprior:
logprior = log ⁡ ( P ( D p o s ) P ( D n e g ) ) = log ⁡ ( D p o s D n e g ) \text{logprior} = \log \left( \frac{P(D_{pos})}{P(D_{neg})} \right) = \log \left( \frac{D_{pos}}{D_{neg}} \right) logprior=log(P(Dneg)P(Dpos))=log(DnegDpos)
注意, l o g ( A B ) log(\frac{A}{B}) log(BA) 等于 l o g ( A ) − l o g ( B ) log(A)-log(B) log(A)log(B)。 因此,logprior 也可以计算为两个对数之差:
logprior = log ⁡ ( P ( D p o s ) ) − log ⁡ ( P ( D n e g ) ) = log ⁡ ( D p o s ) − log ⁡ ( D n e g ) (3) \text{logprior} = \log (P(D_{pos})) - \log (P(D_{neg})) = \log (D_{pos}) - \log (D_{neg})\tag{3} logprior=log(P(Dpos))log(P(Dneg))=log(Dpos)log(Dneg)(3)

Positive and Negative Probability of a Word

要计算词汇表中某个特定单词的正向概率和负向概率,可使用以下输入:

  • f r e q p o s freq_{pos} freqpos f r e q n e g freq_{neg} freqneg是该词在正分类或负分类中的频率。换句话说,一个词的正向频率是该词被标为 1 的次数。
  • N p o s N_{pos} Npos N n e g N_{neg} Nneg 分别是所有文档(所有推文)中正词和负词的总数。
  • V V V 是整个文档集合中所有类别(无论是正面还是负面)的唯一单词数。

可使用以下公式计算特定单词的正负概率:
P ( W p o s ) = f r e q p o s + 1 N p o s + V (4) P(W_{pos}) = \frac{freq_{pos} + 1}{N_{pos} + V}\tag{4} P(Wpos)=Npos+Vfreqpos+1(4)
P ( W n e g ) = f r e q n e g + 1 N n e g + V (5) P(W