65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (5投票s)

2020年6月19日

CPOL

4分钟阅读

viewsIcon

13392

downloadIcon

161

在本文中,我们将了解您可以使用自然语言工具包 (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))

现在我们可以编写一个特征提取器。如前所述,它应该返回一个字典,其中每个顶级单词作为键,并且值为 TrueFalse,具体取决于该单词是否出现在文本中。

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。

© . All rights reserved.