使用 NLTK 进行自然语言处理入门






4.63/5 (5投票s)
在本文中,我们将了解您可以使用自然语言工具包 (NLTK) 做什么。
这是我们学习 Python 及其在机器学习和人工智能中应用的系列的第六个模块。在前一个模块中,我们讨论了使用 OpenCV 进行图像识别。现在,让我们看看您可以使用自然语言工具包 (NLTK) 做什么。
安装
可以使用 Anaconda 安装 NTLK
conda install nltk
或者使用 pip,在 Jupyter Notebook 单元格中运行此命令
!pip install --upgrade nltk
如果以下 Python 代码运行没有错误,则安装成功
import nltk
NLTK 附带大量数据(语料库、语法、模型等),您可以下载。只需运行此 Python 命令即可显示交互式下载窗口
ntlk.download()
对于此模块,您需要安装“stopwords”语料库。下载后,创建一个名为 NLTK_DATA
的环境变量,其中包含下载目录的路径(如果您进行集中安装,则不需要此步骤;请参阅文档以获取有关安装数据的完整指南)。
文本分类
对文本进行分类意味着为其分配一个标签。文本可以以各种方式进行分类,例如情感分析(正面/负面/中性)、垃圾邮件分类(垃圾邮件/非垃圾邮件)、按文档主题等等。
在本模块中,我们将通过一个文本分类示例,使用大型电影评论数据集,该数据集提供了 25,000 条电影评论(正面和负面)用于训练,并提供了相同数量的评论用于测试。
NLTK 提供了朴素贝叶斯分类器来处理机器学习工作。我们的主要任务是编写一个从文本中提取“特征”的函数。分类器使用这些特征来执行其分类。
我们的函数,称为特征提取器,将一个字符串(文本)作为参数,并返回一个字典,该字典将特征名称映射到其值,称为特征集。
对于电影评论,我们的特征将是前N个单词(不包括停用词)。因此,特征提取器将返回一个特征集,其中包含这些N个单词作为键,以及一个指示它们是否存在的值(布尔值)。
第一步是遍历评论,存储所有单词(除了停用词),并找到最常见的单词。
首先,此辅助函数获取一个文本并输出其非停用词
import nltk
import nltk.sentiment.util
from nltk.corpus import stopwords
import nltk.sentiment.util
stop = set(stopwords.words("english"))
def extract_words_from_text(text):
tokens = nltk.word_tokenize(text)
tokens_neg_marked = nltk.sentiment.util.mark_negation(tokens)
return [t for t in tokens_neg_marked
if t.replace("_NEG", "").isalnum() and
t.replace("_NEG", "") not in stop]
word_tokenize
将文本拆分为标记列表(仍然保留标点符号)。
mark_negation
用_NEG标记否定词之后的标记。例如,“I did not enjoy this.”在分词和标记否定后变为
["I", "did", "not", "enjoy_NEG", "this_NEG", "."]
.
最后一行删除所有停用词(包括否定词)和标点符号。文本中仍然有很多无用的词,例如“I”或“This”,但这种过滤对于我们的演示来说已经足够了。
接下来,我们构造一个从评论文件中读取的所有单词的列表。我们保留一个单独的正面和负面单词列表,以确保在获取前几个单词后保持平衡。(我还测试了它,没有单独保留单词列表,结果发现大多数正面评论被归类为负面。)同时,我们还可以创建所有正面评论和所有负面评论的列表。
import os
positive_files = os.listdir("aclImdb/train/pos")
negative_files = os.listdir("aclImdb/train/neg")
positive_words = []
negative_words = []
positive_reviews = []
negative_reviews = []
for pos_file in positive_files:
with open("aclImdb/train/pos/" + pos_file, "r") as f:
txt = f.read().replace("<br />", " ")
positive_reviews.append(txt)
positive_words.extend(extract_words_from_text(txt))
for neg_file in negative_files:
with open("aclImdb/train/neg/" + neg_file, "r") as f:
txt = f.read().replace("<br />", " ")
negative_reviews.append(txt)
negative_words.extend(extract_words_from_text(txt))
运行此代码可能需要一段时间,因为有很多文件。
然后,我们仅保留来自正面和负面单词列表的前N个单词(在本例中为 2000 个单词),并将它们组合在一起。
N = 2000
freq_pos = nltk.FreqDist(positive_words)
top_word_counts_pos = sorted(freq_pos.items(), key=lambda kv: kv[1], reverse=True)[:N]
top_words_pos = [twc[0] for twc in top_word_counts_pos]
freq_neg = nltk.FreqDist(negative_words)
top_word_counts_neg = sorted(freq_neg.items(), key=lambda kv: kv[1], reverse=True)[:N]
top_words_neg = [twc[0] for twc in top_word_counts_neg]
top_words = list(set(top_words_pos + top_words_neg))
现在我们可以编写一个特征提取器。如前所述,它应该返回一个字典,其中每个顶级单词作为键,并且值为 True
或 False
,具体取决于该单词是否出现在文本中。
def extract_features(text):
text_words = extract_words_from_text(text)
return { w: w in text_words for w in top_words }
然后我们创建一个训练集,我们将把它输入到朴素贝叶斯分类器中。训练集应该是一个元组列表,其中每个元组的第一个元素是特征集,第二个元素是标签。
training = [(extract_features(review), "pos") for review in positive_reviews] + [(extract_features(review), "neg") for review in negative_reviews]
上面的代码消耗了大量 RAM 并且速度很慢,因此您可能希望使用评论的子集代替,方法是截取评论列表的一部分。
训练分类器很简单
classifier = nltk.NaiveBayesClassifier.train(training)
现在要对评论进行分类,请在新特征集上使用 classify
方法
print(classifier.classify(extract_features("Your review goes here.")))
如果要查看每个标签的概率,请改用 prob_classify
def get_prob_dist(text):
prob_dist = classifier.prob_classify(extract_features(text))
return { "pos": prob_dist.prob("pos"), "neg": prob_dist.prob("neg") }
print(get_prob_dist("Your review goes here."))
分类器有一种内置方法可以根据测试集确定模型的准确性。此测试集的形状与训练集相同。电影评论数据集有一个单独的目录,其中包含可用于此目的的评论。
test_positive = os.listdir("aclImdb/test/pos")[:2500]
test_negative = os.listdir("aclImdb/test/neg")[:2500]
test = []
for pos_file in test_positive:
with open("aclImdb/test/pos/" + pos_file, "r") as f:
txt = f.read().replace("<br />", " ")
test.append((extract_features(txt), "pos"))
for neg_file in test_negative:
with open("aclImdb/test/neg/" + neg_file, "r") as f:
txt = f.read().replace("<br />", " ")
test.append((extract_features(txt), "neg"))
print(nltk.classify.accuracy(classifier, test))
使用 N = 2000,训练集中有 5000 条正面评论和 5000 条负面评论,使用此代码,我得到了大约 85% 的准确率。
结论
在本模块中,我们介绍了 NLTK 在文本分类中的工作方式,并使用情感分析进行了演示。您可以以相同的方式将其用于其他分类,包括那些具有两个以上标签的分类。
在下一个模块中,我们将介绍 Keras。