如何使用自然语言工具包(NLTK)在Python3中执行情感分析

来自菜鸟教程
跳转至:导航、​搜索

作者选择了 Open Internet/Free Speech 基金来接收捐赠,作为 Write for DOnations 计划的一部分。

介绍

今天生成的大量数据是 非结构化 ,需要进行处理才能产生洞察力。 非结构化数据的一些示例包括新闻文章、社交媒体上的帖子和搜索历史。 分析自然语言并从中理解的过程属于自然语言处理(NLP)领域。 情感分析是一项常见的 NLP 任务,它涉及将文本或部分文本分类为预定义的情感。 您将使用 自然语言工具包 (NLTK) (Python 中常用的 NLP 库)来分析文本数据。

在本教程中,您将从 NLTK 包中为具有不同数据清理方法的 NLP 准备一个示例推文数据集。 一旦数据集准备好进行处理,您将在预先分类的推文上训练一个模型,并使用该模型将样本推文分类为负面和正面情绪。

本文假设您熟悉 Python 的基础知识(请参阅我们的 如何在 Python 3 系列中编码 ),主要是数据结构、类和方法的使用。 本教程假定您没有 NLP 和 nltk 方面的背景,尽管对此有所了解是一个额外的优势。

先决条件

  • 本教程基于 Python 3.6.5 版本。 如果您没有安装 Python 3,这里是 为 Python 3 安装和设置本地编程环境的指南。
  • 建议熟悉使用语言数据。 如果您不熟悉使用 NLTK,请查看 如何使用自然语言工具包 (NLTK) 在 Python 3 中使用语言数据指南。

第 1 步 — 安装 NLTK 并下载数据

您将使用 Python 中的 NLTK 包来完成本教程中的所有 NLP 任务。 在此步骤中,您将安装 NLTK 并下载用于训练和测试模型的示例推文。

首先,使用pip包管理器安装NLTK包

pip install nltk==3.3

本教程将使用 NLTK 包中的示例推文。 首先,通过运行以下命令启动 Python 交互式会话:

python3

然后,在 python 解释器中导入 nltk 模块。

import nltk

从 NLTK 包下载示例推文:

nltk.download('twitter_samples')

从 Python 解释器运行此命令会在本地下载并存储推文。 下载样本后,您就可以使用它们了。

您将在本教程后面使用负面和正面推文来训练您的模型进行情绪分析。 没有情绪的推文将用于测试您的模型。

如果您想使用自己的数据集,您可以使用 Twitter API 收集来自特定时间段、用户或主题标签的推文。

现在您已经导入了 NLTK 并下载了示例推文,通过输入 exit() 退出交互式会话。 您已准备好导入推文并开始处理数据。

第 2 步 - 标记数据

机器无法准确处理原始形式的语言,因此您需要对语言进行处理以使机器更易于理解。 理解数据的第一部分是通过称为 tokenization 的过程,或将字符串拆分为称为 tokens 的较小部分。

记号是文本中用作一个单元的字符序列。 根据您创建令牌的方式,它们可能由单词、表情符号、主题标签、链接甚至单个字符组成。 将语言分解为标记的一种基本方法是根据空格和标点符号拆分文本。

首先,创建一个新的 .py 文件来保存您的脚本。 本教程将使用 nlp_test.py

nano nlp_test.py

在此文件中,您将首先导入 twitter_samples,以便您可以使用该数据:

nlp_test.py

from nltk.corpus import twitter_samples

这将从 NLTK 导入三个数据集,其中包含各种推文来训练和测试模型:

  • negative_tweets.json:5000 条带有负面情绪的推文
  • positive_tweets.json:5000 条带有正面情绪的推文
  • tweets.20150430-223406.json:20000 条没有情绪的推文

接下来,为 positive_tweetsnegative_tweetstext 创建变量:

nlp_test.py

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')

twitter_samplesstrings() 方法会将数据集中的所有推文打印为字符串。 将不同的推文集合设置为变量将使处理和测试更容易。

在 NLTK 中使用分词器之前,您需要下载一个额外的资源,punktpunkt 模块是一个预训练模型,可帮助您对单词和句子进行标记。 例如,此模型知道名称可能包含句点(如“S. Daityari”),并且这个句点在句子中的存在并不一定会结束它。 首先,启动一个 Python 交互式会话:

python3

在会话中运行以下命令以下载 punkt 资源:

import nltk
nltk.download('punkt')

下载完成后,您就可以使用 NLTK 的分词器了。 NLTK 使用 .tokenized() 方法为推文提供默认标记器。 添加一行来创建一个对 positive_tweets.json 数据集进行标记的对象:

nlp_test.py

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')
tweet_tokens = twitter_samples.tokenized('positive_tweets.json')

如果您想测试脚本以查看 .tokenized 方法的运行情况,请将突出显示的内容添加到您的 nlp_test.py 脚本中。 这将标记来自 positive_tweets.json 数据集的单个推文:

nlp_test.py

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')
tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0]

print(tweet_tokens[0])

保存并关闭文件,然后运行脚本:

python3 nlp_test.py

标记化过程需要一些时间,因为它不是简单的空白分割。 处理片刻后,您将看到以下内容:

Output['#FollowFriday',
 '@France_Inte',
 '@PKuchly57',
 '@Milipol_Paris',
 'for',
 'being',
 'top',
 'engaged',
 'members',
 'in',
 'my',
 'community',
 'this',
 'week',
 ':)']

这里,.tokenized() 方法返回特殊字符,例如 @_。 这些字符将在本教程后面通过正则表达式删除。

现在您已经了解了 .tokenized() 方法的工作原理,请确保注释掉或删除最后一行,以便通过在行首添加 # 从脚本中打印标记化推文:

nlp_test.py

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')
tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0]

#print(tweet_tokens[0])

您的脚本现在已配置为标记数据。 在下一步中,您将更新脚本以规范化数据。

第 3 步 — 规范化数据

单词有不同的形式——例如,“ran”、“runs”和“running”是同一个动词“run”的不同形式。 根据您的分析要求,所有这些版本可能都需要转换为相同的形式,“运行”。 NLP 中的 Normalization 是将单词转换为其规范形式的过程。

规范化有助于将具有相同含义但形式不同的单词组合在一起。 如果没有规范化,“ran”、“runs”和“running”将被视为不同的词,即使您可能希望它们被视为同一个词。 在本节中,您将探索 stemminglemmatization,这是两种流行的归一化技术。

词干提取是从单词中删除词缀的过程。 词干提取,仅使用简单的动词形式,是一个删除词尾的启发式过程。

在本教程中,您将使用词形还原过程,该过程使用词汇的上下文和文本中单词的 形态分析 对单词进行规范化。 词形还原算法分析单词的结构及其上下文,以将其转换为规范化形式。 因此,它是以速度为代价的。 词干提取和词形还原的比较最终归结为速度和准确性之间的权衡。

在继续使用词形还原之前,通过在 Python 交互式会话中输入以下内容来下载必要的资源:

python3

在会话中运行以下命令以下载资源:

import nltk
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')

wordnet 是一个英语词汇数据库,可帮助脚本确定基本词。 您需要 averaged_perceptron_tagger 资源来确定句子中单词的上下文。

下载后,您几乎可以使用词形还原器了。 在运行 lemmatizer 之前,您需要确定文本中每个单词的上下文。 这是通过标记算法实现的,该算法评估单词在句子中的相对位置。 在 Python 会话中,导入 pos_tag 函数,并提供一个标记列表作为获取标记的参数。 让我们在 Python 中尝试一下:

from nltk.tag import pos_tag
from nltk.corpus import twitter_samples

tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
print(pos_tag(tweet_tokens[0]))

这是 pos_tag 函数的输出。

Output[('#FollowFriday', 'JJ'),
 ('@France_Inte', 'NNP'),
 ('@PKuchly57', 'NNP'),
 ('@Milipol_Paris', 'NNP'),
 ('for', 'IN'),
 ('being', 'VBG'),
 ('top', 'JJ'),
 ('engaged', 'VBN'),
 ('members', 'NNS'),
 ('in', 'IN'),
 ('my', 'PRP$'),
 ('community', 'NN'),
 ('this', 'DT'),
 ('week', 'NN'),
 (':)', 'NN')]

从标签列表中,这是最常见的项目及其含义的列表:

  • NNP:名词,专有名词,单数
  • NN:名词、普通、单数或质量
  • IN:介词或连词,从属
  • VBG:动词、动名词或现在分词
  • VBN:动词,过去分词

这是数据集 完整列表。

通常,如果标签以 NN 开头,则该词是名词,如果以 VB 开头,则该词是动词。 查看标签后,输入 exit() 退出 Python 会话。

要将其合并到一个标准化句子的函数中,您应该首先为文本中的每个标记生成标签,然后使用标签对每个单词进行词形还原。

使用以下对句子进行词形还原的函数更新 nlp_test.py 文件:

nlp_test.py

...

from nltk.tag import pos_tag
from nltk.stem.wordnet import WordNetLemmatizer

def lemmatize_sentence(tokens):
    lemmatizer = WordNetLemmatizer()
    lemmatized_sentence = []
    for word, tag in pos_tag(tokens):
        if tag.startswith('NN'):
            pos = 'n'
        elif tag.startswith('VB'):
            pos = 'v'
        else:
            pos = 'a'
        lemmatized_sentence.append(lemmatizer.lemmatize(word, pos))
    return lemmatized_sentence

print(lemmatize_sentence(tweet_tokens[0]))

此代码导入 WordNetLemmatizer 类并将其初始化为变量 lemmatizer

函数 lemmatize_sentence 首先获取推文每个标记的位置标签。 在 if 语句中,如果标记以 NN 开头,则将标记分配为名词。 类似地,如果标记以 VB 开头,则标记被分配为动词。

保存并关闭文件,然后运行脚本:

python3 nlp_test.py

这是输出:

Output['#FollowFriday',
 '@France_Inte',
 '@PKuchly57',
 '@Milipol_Paris',
 'for',
 'be',
 'top',
 'engage',
 'member',
 'in',
 'my',
 'community',
 'this',
 'week',
 ':)']

你会注意到动词 being 变成了它的词根 be,而名词 members 变成了 member。 在继续之前,请注释掉从脚本中打印示例推文的最后一行。

既然您已经成功创建了一个标准化单词的函数,那么您就可以继续移除噪音了。

第 4 步 — 从数据中去除噪音

在此步骤中,您将从数据集中去除噪声。 Noise 是文本中不向数据添加含义或信息的任何部分。

噪音因每个项目而异,因此在一个项目中构成噪音的因素可能不在不同的项目中。 例如,一种语言中最常见的词称为停用词。 停用词的一些示例是“is”、“the”和“a”。 在处理语言时,它们通常无关紧要,除非特定用例需要包含它们。

在本教程中,您将 使用 Python 中的正则表达式来搜索和删除这些项目:

  • Hyperlinks - Twitter 中的所有超链接都转换为 URL 缩短器 t.co。 因此,将它们保留在文本处理中不会为分析增加任何价值。
  • Twitter 回复中的句柄 - 这些 Twitter 用户名前面有一个 @ 符号,它不传达任何含义。
  • 标点符号和特殊字符 - 虽然这些通常为文本数据提供上下文,但这种上下文通常难以处理。 为简单起见,您将从推文中删除所有标点符号和特殊字符。

要删除超链接,您需要首先搜索与以 http://https:// 开头,后跟字母、数字或特殊字符的 URL 匹配的子字符串。 一旦模式匹配,.sub() 方法将其替换为空字符串。

由于我们将在 remove_noise() 函数中规范化单词形式,因此您可以从脚本中注释掉 lemmatize_sentence() 函数。

将以下代码添加到您的 nlp_test.py 文件中以消除数据集中的噪声:

nlp_test.py

...

import re, string

def remove_noise(tweet_tokens, stop_words = ()):

    cleaned_tokens = []

    for token, tag in pos_tag(tweet_tokens):
        token = re.sub('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|'\
                       '(?:%[0-9a-fA-F][0-9a-fA-F]))+','', token)
        token = re.sub("(@[A-Za-z0-9_]+)","", token)

        if tag.startswith("NN"):
            pos = 'n'
        elif tag.startswith('VB'):
            pos = 'v'
        else:
            pos = 'a'

        lemmatizer = WordNetLemmatizer()
        token = lemmatizer.lemmatize(token, pos)

        if len(token) > 0 and token not in string.punctuation and token.lower() not in stop_words:
            cleaned_tokens.append(token.lower())
    return cleaned_tokens

这段代码创建了一个 remove_noise() 函数,它可以去除噪声并结合上一节中提到的归一化和词形还原。 该代码有两个参数:推文标记和停用词元组。

然后代码使用循环从数据集中去除噪声。 要删除超链接,代码首先搜索与以 http://https:// 开头的 URL 匹配的子字符串,后跟字母、数字或特殊字符。 一旦模式匹配,.sub() 方法将其替换为空字符串,或

同样,要删除 @ 提及,代码使用正则表达式替换文本的相关部分。 代码使用 re 库搜索 @ 符号,后跟数字、字母或 _,并将它们替换为空字符串。

最后,您可以使用库 string 删除标点符号。

除此之外,您还将使用 NLTK 中的一组内置停用词删除停用词,需要单独下载。

从 Python 交互式会话中执行以下命令以下载此资源:

nltk.download('stopwords')

下载资源后,退出交互式会话。

您可以使用 .words() 方法获取英文停用词列表。 为了测试该功能,让我们在示例推文上运行它。 将以下行添加到 nlp_test.py 文件的末尾:

nlp_test.py

...
from nltk.corpus import stopwords
stop_words = stopwords.words('english')

print(remove_noise(tweet_tokens[0], stop_words))

保存并关闭文件后,再次运行脚本以接收类似于以下内容的输出:

Output['#followfriday', 'top', 'engage', 'member', 'community', 'week', ':)']

请注意,该函数会删除所有 @ 提及、停用词,并将这些词转换为小写。

在进行下一步的建模练习之前,使用 remove_noise() 函数清理正面和负面推文。 注释掉在示例推文上打印 remove_noise() 输出的行,并将以下内容添加到 nlp_test.py 脚本中:

nlp_test.py

...
from nltk.corpus import stopwords
stop_words = stopwords.words('english')

#print(remove_noise(tweet_tokens[0], stop_words))

positive_tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
negative_tweet_tokens = twitter_samples.tokenized('negative_tweets.json')

positive_cleaned_tokens_list = []
negative_cleaned_tokens_list = []

for tokens in positive_tweet_tokens:
    positive_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

for tokens in negative_tweet_tokens:
    negative_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

现在您已经添加了清理示例推文的代码,您可能希望将原始令牌与清理后的令牌进行比较以获取示例推文。 如果您想对此进行测试,请将以下代码添加到文件中以比较列表中第 500 条推文的两个版本:

nlp_test.py

...
print(positive_tweet_tokens[500])
print(positive_cleaned_tokens_list[500])

保存并关闭文件并运行脚本。 从输出中您将看到标点符号和链接已被删除,并且单词已被转换为小写。

Output['Dang', 'that', 'is', 'some', 'rad', '@AbzuGame', '#fanart', '!', ':D', 'https://t.co/bI8k8tb9ht']
['dang', 'rad', '#fanart', ':d']

在文本的预处理过程中可能会出现某些问题。 例如,没有空格的单词(“iLoveYou”)将被视为一个单词,并且很难将这些单词分开。 此外,除非您编写特定内容来解决该问题,否则脚本将对“Hi”、“Hii”和“Hiiii”进行不同的处理。 为您的特定数据微调噪声消除过程是很常见的。

现在您已经看到了 remove_noise() 函数的运行情况,请务必注释掉或删除脚本的最后两行,以便您可以添加更多内容:

nlp_test.py

...
#print(positive_tweet_tokens[500])
#print(positive_cleaned_tokens_list[500])

在此步骤中,您从数据中去除了噪音,以使分析更有效。 在下一步中,您将分析数据以查找示例数据集中最常见的单词。

第 5 步 — 确定字密度

对文本数据最基本的分析形式就是取出词频。 单个推文太小,无法找出单词的分布,因此,将对所有正面推文进行单词频率分析。

以下代码段定义了 一个名为 get_all_words 的生成器函数 ,它将推文列表作为参数提供所有加入的推文标记中的单词列表。 将以下代码添加到您的 nlp_test.py 文件中:

nlp_test.py

...

def get_all_words(cleaned_tokens_list):
    for tokens in cleaned_tokens_list:
        for token in tokens:
            yield token

all_pos_words = get_all_words(positive_cleaned_tokens_list)

现在您已经编译了推文样本中的所有单词,您可以使用 NLTK 的 FreqDist 类找出最常见的单词。 将以下代码添加到 nlp_test.py 文件中:

nlp_test.py

from nltk import FreqDist

freq_dist_pos = FreqDist(all_pos_words)
print(freq_dist_pos.most_common(10))

.most_common() 方法列出了数据中出现频率最高的单词。 进行这些更改后保存并关闭文件。

现在运行文件时,您会发现数据中最常用的术语:

Output[(':)', 3691),
 (':-)', 701),
 (':d', 658),
 ('thanks', 388),
 ('follow', 357),
 ('love', 333),
 ('...', 290),
 ('good', 283),
 ('get', 263),
 ('thank', 253)]

从这些数据中,您可以看到表情符号实体构成了正面推文的一些最常见部分。 在继续下一步之前,请确保注释掉打印前十个标记的脚本的最后一行。

总而言之,您从 nltk 中提取了推文,进行了标记化、规范化并清理了推文以在模型中使用。 最后,您还查看了数据中标记的频率,并检查了前十个标记的频率。

在下一步中,您将为情绪分析准备数据。

第 6 步 — 为模型准备数据

情感分析是确定作者对所写主题的态度的过程。 您将创建一个训练数据集来训练模型。 这是一个有监督的机器学习过程,需要你将每个数据集与一个“情绪”关联起来进行训练。 在本教程中,您的模型将使用“正面”和“负面”情绪。

情感分析可用于将文本分类为各种情感。 为了训练数据集的简单性和可用性,本教程仅帮助您在正面和负面两个类别中训练模型。

模型是使用规则和方程对系统的描述。 它可能就像一个等式一样简单,根据一个人的身高预测一个人的体重。 您将构建的情绪分析模型会将推文与正面或负面情绪相关联。 您需要将数据集分成两部分。 第一部分的目的是建立模型,而下一部分的目的是测试模型的性能。

在数据准备步骤中,您将通过将标记转换为字典形式来准备用于情感分析的数据,然后将数据拆分以用于训练和测试目的。

将标记转换为字典

首先,您将准备要输入模型的数据。 您将使用 NLTK 中的 朴素贝叶斯分类器 来执行建模练习。 请注意,该模型不仅需要推文中的单词列表,还需要一个 Python 字典,其中单词作为键,True 作为值。 以下函数创建了一个生成器函数来更改已清理数据的格式。

添加以下代码以将推文从已清理的令牌列表转换为以键为令牌和 True 作为值的字典。 对应的字典存储在positive_tokens_for_modelnegative_tokens_for_model中。

nlp_test.py

...
def get_tweets_for_model(cleaned_tokens_list):
    for tweet_tokens in cleaned_tokens_list:
        yield dict([token, True] for token in tweet_tokens)

positive_tokens_for_model = get_tweets_for_model(positive_cleaned_tokens_list)
negative_tokens_for_model = get_tweets_for_model(negative_cleaned_tokens_list)

拆分数据集以训练和测试模型

接下来,您需要准备用于训练 NaiveBayesClassifier 类的数据。 将以下代码添加到文件中以准备数据:

nlp_test.py

...
import random

positive_dataset = [(tweet_dict, "Positive")
                     for tweet_dict in positive_tokens_for_model]

negative_dataset = [(tweet_dict, "Negative")
                     for tweet_dict in negative_tokens_for_model]

dataset = positive_dataset + negative_dataset

random.shuffle(dataset)

train_data = dataset[:7000]
test_data = dataset[7000:]

此代码将 PositiveNegative 标签附加到每条推文。 然后它通过加入正面和负面的推文来创建一个 dataset

默认情况下,数据包含所有正面推文,然后依次包含所有负面推文。 在训练模型时,您应该提供不包含任何偏差的数据样本。 为避免偏差,您添加了代码以使用 random.shuffle() 方法随机排列数据。

最后,代码将打乱后的数据分成 70:30 的比例分别用于训练和测试。 由于推文的数量为 10000,因此您可以使用洗牌数据集中的前 7000 条推文来训练模型,最后的 3000 条推文用于测试模型。

在此步骤中,您将清理后的标记转换为字典形式,随机打乱数据集,并将其拆分为训练和测试数据。

第 7 步 - 构建和测试模型

最后,您可以使用 NaiveBayesClassifier 类来构建模型。 使用 .train() 方法训练模型,使用 .accuracy() 方法在测试数据上测试模型。

nlp_test.py

...
from nltk import classify
from nltk import NaiveBayesClassifier
classifier = NaiveBayesClassifier.train(train_data)

print("Accuracy is:", classify.accuracy(classifier, test_data))

print(classifier.show_most_informative_features(10))

添加代码后保存、关闭并执行文件。 代码的输出将如下所示:

OutputAccuracy is: 0.9956666666666667

Most Informative Features
                      :( = True           Negati : Positi =   2085.6 : 1.0
                      :) = True           Positi : Negati =    986.0 : 1.0
                 welcome = True           Positi : Negati =     37.2 : 1.0
                  arrive = True           Positi : Negati =     31.3 : 1.0
                     sad = True           Negati : Positi =     25.9 : 1.0
                follower = True           Positi : Negati =     21.1 : 1.0
                     bam = True           Positi : Negati =     20.7 : 1.0
                    glad = True           Positi : Negati =     18.1 : 1.0
                     x15 = True           Negati : Positi =     15.9 : 1.0
               community = True           Positi : Negati =     14.1 : 1.0

准确性定义为模型能够正确预测情绪的测试数据集中推文的百分比。 测试集上 99.5% 的准确率相当不错。

在显示信息最丰富的特征的表中,输出中的每一行都显示了训练数据集中正标记推文和负标记推文中标记的出现率。 数据中的第一行表示在所有包含标记 :( 的推文中,负面推文与正面推文的比率为 2085.61。 有趣的是,在正数据集中似乎有一个带有 :( 的标记。 您可以看到,文本中最有区别的两个项目是表情符号。 此外,诸如 sad 之类的词会导致负面情绪,而 welcomeglad 与正面情绪相关联。

接下来,您可以检查模型对来自 Twitter 的随机推文的执行情况。 将此代码添加到文件中:

nlp_test.py

...
from nltk.tokenize import word_tokenize

custom_tweet = "I ordered just once from TerribleCo, they screwed up, never used the app again."

custom_tokens = remove_noise(word_tokenize(custom_tweet))

print(classifier.classify(dict([token, True] for token in custom_tokens)))

此代码将允许您通过更新与 custom_tweet 变量关联的字符串来测试自定义推文。 进行这些更改后保存并关闭文件。

运行脚本以分析自定义文本。 以下是示例中自定义文本的输出:

Output'Negative'

您还可以检查它是否正确地描述了正面推文:

nlp_test.py

...
custom_tweet = 'Congrats #SportStar on your 7th best goal from last season winning goal of the year :) #Baller #Topbin #oneofmanyworldies'

这是输出:

Output'Positive'

既然您已经测试了正面和负面情绪,请更新变量以测试更复杂的情绪,例如讽刺。

nlp_test.py

...
custom_tweet = 'Thank you for sending my baggage to CityX and flying me to CityY at the same time. Brilliant service. #thanksGenericAirline'

这是输出:

Output'Positive'

该模型将此示例分类为正例。 这是因为训练数据不够全面,无法将讽刺推文分类为负面。 如果您希望您的模型预测讽刺,您需要提供足够数量的训练数据来相应地训练它。

在此步骤中,您构建并测试了模型。 您还探索了它的一些限制,例如在特定示例中未检测到讽刺。 您完成的代码仍然有遵循教程留下的工件,因此下一步将指导您将代码与 Python 的最佳实践保持一致。

第 8 步 — 清理代码(可选)

尽管您已完成本教程,但建议重新组织 nlp_test.py 文件中的代码以遵循最佳编程实践。 根据最佳实践,您的代码应符合以下标准:

  • 所有导入都应该在文件的顶部。 来自同一个库的导入应该在一个语句中组合在一起。
  • 所有函数都应该在导入之后定义。
  • 文件中的所有语句都应置于 if __name__ == "__main__": 条件下。 如果您将文件的功能导入另一个文件,这可确保不会执行语句。

我们还将删除按照教程注释掉的代码,以及 lemmatize_sentence 函数,因为词形还原由新的 remove_noise 函数完成。

这是 nlp_test.py 的清理版本:

from nltk.stem.wordnet import WordNetLemmatizer
from nltk.corpus import twitter_samples, stopwords
from nltk.tag import pos_tag
from nltk.tokenize import word_tokenize
from nltk import FreqDist, classify, NaiveBayesClassifier

import re, string, random

def remove_noise(tweet_tokens, stop_words = ()):

    cleaned_tokens = []

    for token, tag in pos_tag(tweet_tokens):
        token = re.sub('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|'\
                       '(?:%[0-9a-fA-F][0-9a-fA-F]))+','', token)
        token = re.sub("(@[A-Za-z0-9_]+)","", token)

        if tag.startswith("NN"):
            pos = 'n'
        elif tag.startswith('VB'):
            pos = 'v'
        else:
            pos = 'a'

        lemmatizer = WordNetLemmatizer()
        token = lemmatizer.lemmatize(token, pos)

        if len(token) > 0 and token not in string.punctuation and token.lower() not in stop_words:
            cleaned_tokens.append(token.lower())
    return cleaned_tokens

def get_all_words(cleaned_tokens_list):
    for tokens in cleaned_tokens_list:
        for token in tokens:
            yield token

def get_tweets_for_model(cleaned_tokens_list):
    for tweet_tokens in cleaned_tokens_list:
        yield dict([token, True] for token in tweet_tokens)

if __name__ == "__main__":

    positive_tweets = twitter_samples.strings('positive_tweets.json')
    negative_tweets = twitter_samples.strings('negative_tweets.json')
    text = twitter_samples.strings('tweets.20150430-223406.json')
    tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0]

    stop_words = stopwords.words('english')

    positive_tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
    negative_tweet_tokens = twitter_samples.tokenized('negative_tweets.json')

    positive_cleaned_tokens_list = []
    negative_cleaned_tokens_list = []

    for tokens in positive_tweet_tokens:
        positive_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

    for tokens in negative_tweet_tokens:
        negative_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

    all_pos_words = get_all_words(positive_cleaned_tokens_list)

    freq_dist_pos = FreqDist(all_pos_words)
    print(freq_dist_pos.most_common(10))

    positive_tokens_for_model = get_tweets_for_model(positive_cleaned_tokens_list)
    negative_tokens_for_model = get_tweets_for_model(negative_cleaned_tokens_list)

    positive_dataset = [(tweet_dict, "Positive")
                         for tweet_dict in positive_tokens_for_model]

    negative_dataset = [(tweet_dict, "Negative")
                         for tweet_dict in negative_tokens_for_model]

    dataset = positive_dataset + negative_dataset

    random.shuffle(dataset)

    train_data = dataset[:7000]
    test_data = dataset[7000:]

    classifier = NaiveBayesClassifier.train(train_data)

    print("Accuracy is:", classify.accuracy(classifier, test_data))

    print(classifier.show_most_informative_features(10))

    custom_tweet = "I ordered just once from TerribleCo, they screwed up, never used the app again."

    custom_tokens = remove_noise(word_tokenize(custom_tweet))

    print(custom_tweet, classifier.classify(dict([token, True] for token in custom_tokens)))

结论

本教程向您介绍了使用 Python 3 中的 nltk 库的基本情感分析模型。 首先,您通过对推文进行标记、对单词进行规范化和去除噪音来对推文进行预处理。 接下来,您可视化了数据中频繁出现的项目。 最后,您构建了一个模型,将推文与特定情绪相关联。

监督学习模型的好坏取决于它的训练数据。 为了进一步加强模型,您可以考虑添加更多类别,例如兴奋和愤怒。 在本教程中,您只是通过构建一个基本模型来触及表面。 这是 一个关于各种注意事项的详细指南 ,在执行情绪分析时必须注意这些事项。