自然语言工具包(NLTK)是一个为符号和自然语言处理任务创建的 Python 库。
它有潜力让每个人都可以进行自然语言处理,从英语到任何自然人类语言。
安装 Python NLTK
首先,您需要在计算机上安装 NLTK。运行以下命令:
!pip install nltk
安装后,需要导入NLTK并下载必要的包。
import nltk
nltk.download('punkt')
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')
nltk.download('stopwords')
nltk.download('maxent_ne_chunker')
nltk.download('words')
这是您应该期望的输出:
[nltk_data] Downloading package punkt to /home/user/nltk_data...
[nltk_data] Unzipping tokenizers/punkt.zip.
[nltk_data] Downloading package wordnet to /home/user/nltk_data...
[nltk_data] Unzipping corpora/wordnet.zip.
[nltk_data] Downloading package averaged_perceptron_tagger to
...
上面的命令使用以下命令下载几个NLTK包nltk.download()
.
您将需要它们来执行词性标记、停用词删除和词形还原等任务。
安装自然语言工具包后,我们现在准备探索预处理的后续步骤。
文本预处理
文本预处理是为机器学习算法清理和准备文本数据的实践。主要步骤包括分词、删除停用词、词干提取、词形还原等。
这些步骤有助于降低数据的复杂性并从中提取有意义的信息。
在本教程的后续部分中,我们将引导您使用 NLTK 完成每个步骤。
句子和单词标记化
标记化是将文本分解为单词、短语、符号或其他称为标记的有意义元素的过程。分词器的输入是 unicode 文本,输出是句子或单词的列表。
在 NLTK 中,我们有两种类型的分词器——单词分词器和句子分词器。
让我们看一个例子:
from nltk.tokenize import sent_tokenize, word_tokenize
text = "Natural language processing is fascinating. It involves many tasks such as text classification, sentiment analysis, and more."
sentences = sent_tokenize(text)
print(sentences)
words = word_tokenize(text)
print(words)
Output:
['Natural language processing is fascinating.', 'It involves many tasks such as text classification, sentiment analysis, and more.']
['Natural', 'language', 'processing', 'is', 'fascinating', '.', 'It', 'involves', 'many', 'tasks', 'such', 'as', 'text', 'classification', ',', 'sentiment', 'analysis', ',', 'and', 'more', '.']
The sent_tokenize
函数将文本分割成句子,word_tokenize
函数将文本分割成单词。如您所见,标点符号也被视为单独的标记。
停用词删除
在自然语言处理中,停用词是您想要忽略的单词,因此您在处理文本时将其过滤掉。
这些通常是在任何文本中出现频率很高且没有太多含义的单词,例如“is”、“an”、“the”、“in”等。
NLTK 附带了多种语言(包括英语)的预定义停用词列表。
让我们使用 NLTK 从标记化单词列表中过滤掉停用词:
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
text = "Natural language processing is fascinating. It involves many tasks such as text classification, sentiment analysis, and more."
stop_words = set(stopwords.words('english'))
words = word_tokenize(text)
filtered_words = [word for word in words if word.casefold() not in stop_words]
print(filtered_words)
Output:
['Natural', 'language', 'processing', 'fascinating', '.', 'involves', 'many', 'tasks', 'text', 'classification', ',', 'sentiment', 'analysis', ',', '.',]
在这段代码中,我们首先从 NLTK 导入停用词,对文本进行分词,然后过滤掉停用词。这casefold()
方法用于在将单词与停用词列表进行比较时忽略大小写。
Stemming
词干提取是将单词的词形变化(例如 running、runs)减少为其词根形式(例如 run)的过程。在这种情况下,“词根”实际上可能不是真正的词根,而只是原始词的规范形式。 NLTK提供了几个著名的词干分析器接口,例如PorterStemmer。
以下是如何使用 NLTK 的 PorterStemmer:
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
text = "He was running and eating at same time. He has bad habit of swimming after playing long hours in the Sun."
porter_stemmer = PorterStemmer()
words = word_tokenize(text)
stemmed_words = [porter_stemmer.stem(word) for word in words]
print(stemmed_words)
Output:
['he', 'wa', 'run', 'and', 'eat', 'at', 'same', 'time', '.', 'he', 'ha', 'bad', 'habit', 'of', 'swim', 'after', 'play', 'long', 'hour', 'in', 'the', 'sun', '.']
在这段代码中,我们首先对文本进行标记,然后将每个单词传递到stem
我们的词干分析器的功能。
请注意“跑步”、“吃”、“游泳”和“玩”等词如何被简化为它们的词根形式:分别是“跑”、“吃”、“游泳”和“玩”。
词形还原
词形还原是一个考虑单词的形态分析并有效地将单词还原为其基本形式或词根形式的过程。
与词干提取不同,它适当地减少词形变化,确保根词(也称为词条)属于该语言。
我们将使用 WordNet 词汇数据库进行词形还原。 WordNetLemmatizer 是一个获取单词词元的类。
这是一个例子:
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
text = "He was running and eating at same time. He has bad habit of swimming after playing long hours in the Sun."
lemmatizer = WordNetLemmatizer()
words = word_tokenize(text)
lemmatized_words = [lemmatizer.lemmatize(word) for word in words]
print(lemmatized_words)
Output:
['He', 'wa', 'running', 'and', 'eating', 'at', 'same', 'time', '.', 'He', 'ha', 'bad', 'habit', 'of', 'swimming', 'after', 'playing', 'long', 'hour', 'in', 'the', 'Sun', '.']
在此代码中,我们首先对文本进行标记,然后将每个单词传递到lemmatize
我们的词形还原器的功能。
请注意单词“was”和“has”如何分别简化为它们的引理:“wa”和“ha”。
词性标注
词性 (POS) 标记是根据单词的定义和上下文将文本中的单词标记为与特定词性(名词、动词、形容词等)相对应的过程。
NLTK库有一个函数叫做pos_tag
用词性描述符来标记单词。
让我们看看它的实际效果:
from nltk.tokenize import word_tokenize
from nltk import pos_tag
text = "Natural language processing is fascinating. It involves many tasks such as text classification, sentiment analysis, and more."
words = word_tokenize(text)
tagged_words = pos_tag(words)
print(tagged_words)
Output:
[('Natural', 'JJ'), ('language', 'NN'), ('processing', 'NN'), ('is', 'VBZ'), ('fascinating', 'VBG'), ('.', '.'), ('It', 'PRP'), ('involves', 'VBZ'), ('many', 'JJ'), ('tasks', 'NNS'), ('such', 'JJ'), ('as', 'IN'), ('text', 'NN'), ('classification', 'NN'), (',', ','), ('sentiment', 'NN'), ('analysis', 'NN'), (',', ','), ('and', 'CC'), ('more', 'JJR'), ('.', '.')]
The pos_tag
函数返回一个元组,其中包含单词和表示词性的标签。例如,“NN”代表名词,“JJ”是形容词,“VBZ”是第三人称动词,等等。
以下是 NLTK 中使用的一些常见 POS(词性)标签及其含义的列表:
Tag |
Meaning |
CC |
Coordinating conjunction |
CD |
Cardinal number |
DT |
Determiner |
EX |
Existential there |
FW |
Foreign word |
IN |
Preposition or subordinating conjunction |
JJ |
Adjective |
JJR |
Adjective, comparative |
JJS |
Adjective, superlative |
LS |
List item marker |
MD |
Modal |
NN |
Noun, singular or mass |
NNS |
Noun, plural |
NNP |
Proper noun, singular |
NNPS |
Proper noun, plural |
PDT |
Predeterminer |
POS |
Possessive ending |
PRP |
Personal pronoun |
PRP$ |
Possessive pronoun |
RB |
Adverb |
RBR |
Adverb, comparative |
RBS |
Adverb, superlative |
RP |
Particle |
SYM |
Symbol |
TO |
to |
UH |
Interjection |
VB |
Verb, base form |
VBD |
Verb, past tense |
VBG |
Verb, gerund or present participle |
VBN |
Verb, past participle |
VBP |
Verb, non-3rd person singular present |
VBZ |
Verb, 3rd person singular present |
WDT |
Wh-determiner |
WP |
Wh-pronoun |
WP$ |
Possessive wh-pronoun |
WRB |
Wh-adverb |
这些标签是宾夕法尼亚树库标签集.
命名实体识别
命名实体识别 (NER) 是定位文本中存在的命名实体并将其分类为预定义类别的过程,例如人名、组织、位置、医疗代码、时间表达、数量、货币价值、百分比等。
让我们尝试一个简单的例子:
from nltk.tokenize import word_tokenize
from nltk import pos_tag, ne_chunk
text = "John works at Google in Mountain View, California."
words = word_tokenize(text)
tagged_words = pos_tag(words)
named_entities = ne_chunk(tagged_words)
print(named_entities)
输出将是一棵树,其中命名实体作为子树。子树的标签将指示实体的类型(即人员、组织、位置等)。例如:
(S
(PERSON John/NNP)
works/VBZ
at/IN
(ORGANIZATION Google/NNP)
in/IN
(GPE Mountain/NNP View/NNP)
,/,
(GPE California/NNP)
./.)
在此代码中,我们首先对文本进行标记,然后用其词性标记每个单词。
The ne_chunk
然后函数识别命名实体。结果,“约翰”被识别为一个人,“Google”被识别为一个组织,“山景城”和“加利福尼亚”被识别为地理位置。
理解同义词集
同义词集(或同义词集)是在某些上下文中可互换的同义词的集合。
这些对于构建知识图、语义链接或在上下文中查找单词的含义来说是非常有用的资源。
NLTK 提供了 WordNet API 的接口,可用于查找单词及其同义词、定义和示例。
让我们演示一下如何使用它:
from nltk.corpus import wordnet
syn = wordnet.synsets("dog")[0]
print(f"Synset name: {syn.name()}")
print(f"Lemma names: {syn.lemma_names()}")
print(f"Definition: {syn.definition()}")
print(f"Examples: {syn.examples()}")
Output:
Synset name: dog.n.01
Lemma names: ['dog', 'domestic_dog', 'Canis_familiaris']
Definition: a member of the genus Canis (probably descended from the common wolf) that has been domesticated by man since prehistoric times; occurs in many breeds
Examples: ['the dog barked all night']
在这段代码中,wordnet.synsets("dog")[0]
给了我们“狗”这个词的第一个同义词。这name
方法返回同义词集的名称,lemma_names
给出所有同义词,definition
提供了一个简短的定义,并且examples
提供使用示例。
语义关系
单词之间的语义关系是自然语言理解任务的一个组成部分。 NLTK 提供了易于使用的界面来探索这些关系:
-
Hyponyms: 更具体的术语。例如,“贵宾犬”是“狗”的下位词。
-
上位词:更一般的术语。例如,“dog”是“poodle”的上位词.
-
Antonyms: 相反的术语。例如,“善”是“恶”的反义词。
以下是如何使用 NLTK 探索这些关系:
from nltk.corpus import wordnet
syn = wordnet.synsets('dog')[0]
# Get hyponyms for dog
hyponyms = syn.hyponyms()
print("Hyponyms of 'dog': ", [h.lemmas()[0].name() for h in hyponyms])
syn = wordnet.synsets('poodle')[0]
# Get hypernyms for poodle
hypernyms = syn.hypernyms()
print("Hypernyms of 'dog': ", [h.lemmas()[0].name() for h in hypernyms])
# Get Antonym
synsets = wordnet.synsets('good')
antonym = None
# Search for an antonym in all synsets/lemmas
for syn in synsets:
for lemma in syn.lemmas():
if lemma.antonyms():
antonym = lemma.antonyms()[0].name()
break
if antonym:
break
if antonym:
print("Antonym of 'good': ", antonym)
else:
print("No antonym found for 'good'")
Output:
Hyponyms of 'dog': ['basenji', 'corgi', 'cur', 'dalmatian', 'Great_Pyrenees', 'griffon', 'hunting_dog', 'lapdog', 'Leonberg', 'Mexican_hairless', 'Newfoundland', 'pooch', 'poodle', 'pug', 'puppy', 'spitz', 'toy_dog', 'working_dog']
Hypernyms of 'dog': ['dog']
Antonym of 'good': evil
The hyponyms
方法给出了更具体的术语(下位词)列表,而hypernyms
给出更通用术语(上位词)的列表。
对于反义词,我们首先迭代“good”的所有同义词。然后它迭代同义词集的所有引理。如果它找到反义词,它就会从循环中中断并打印反义词。
如果在检查所有同义词集和引理后未找到反义词,则会打印一条消息以指示未找到反义词。
测量语义相似度
我们还可以根据上位词树中两个单词之间的距离来衡量两个单词之间的语义相似度。
这是一个例子:
from nltk.corpus import wordnet
# Get the first synset for each word
dog = wordnet.synsets('dog')[0]
cat = wordnet.synsets('cat')[0]
# Get the similarity value
similarity = dog.path_similarity(cat)
print("Semantic similarity between 'dog' and 'cat': ", similarity)
Output:
Semantic similarity: 0.2
在此代码中,我们首先使用以下命令获取每个单词的第一个同义词集wordnet.synsets()
。然后我们使用以下方法测量这些同义词集之间的语义相似度path_similarity()
.
在此示例中,我们仅比较每个单词的第一个含义。如果您想要更全面地衡量相似性,您可能需要比较单词的所有含义,并可能以某种方式汇总相似性分数。
以下是如何执行此操作的示例:
from nltk.corpus import wordnet
# Get all synsets for each word
synsets_dog = wordnet.synsets('dog')
synsets_cat = wordnet.synsets('cat')
# Initialize max similarity
max_similarity = 0
# Compare all pairs of synsets
for synset_dog in synsets_dog:
for synset_cat in synsets_cat:
similarity = synset_dog.path_similarity(synset_cat)
if similarity is not None: # If the words are connected in the hypernym/hyponym taxonomy
max_similarity = max(max_similarity, similarity)
print("Comprehensive semantic similarity between 'dog' and 'cat': ", max_similarity)
Output:
Comprehensive semantic similarity between 'dog' and 'cat': 0.2
在此脚本中,我们首先使用以下命令获取每个单词的所有同义词wordnet.synsets()
。然后我们将最大相似度初始化为0。
我们比较所有的同义词集对,并在每次发现更高的相似性时更新最大相似性。最后,我们打印最大相似度。
上下文无关语法
在自然语言处理中,上下文无关语法(CFG)是一种形式语法,用于生成给定形式语言中所有可能的句子。
以下是如何在 NLTK 中定义 CFG 并从中生成句子:
from nltk import CFG
from nltk.parse.generate import generate
grammar = CFG.fromstring("""
S -> NP VP
VP -> V NP | V NP PP
PP -> P NP
V -> "saw" | "ate"
NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
Det -> "a" | "an" | "the" | "my"
N -> "dog" | "cat" | "cookie" | "park"
P -> "in" | "on" | "by" | "with"
""")
for sentence in generate(grammar, n=10): # generating only 10 sentences
print(' '.join(sentence))
Output:
John saw John
John saw Mary
John saw Bob
John saw a dog
John saw a cat
John saw a cookie
John saw a park
John saw an dog
John saw an cat
John saw an cookie
在此代码中,我们首先使用 NLTK 定义上下文无关语法CFG.fromstring
method.
该字符串包含 CFG 的规则,格式为"LHS -> RHS"
, where LHS
是单个非终结符,并且RHS
是终结符号和非终结符号的序列。
然后我们使用 CFG 生成句子nltk.parse.generate.generate
功能。
解析树
解析树或解析树是一棵有序的有根树,它根据某种上下文无关语法表示字符串的语法结构。
以下是如何为给定上下文无关语法的句子生成解析树:
from nltk import CFG
from nltk.parse import RecursiveDescentParser
grammar = CFG.fromstring("""
S -> NP VP
VP -> V NP | V NP PP
PP -> P NP
V -> "saw" | "ate"
NP -> "John" | "Mary" | "Bob" | Det N | Det N PP
Det -> "a" | "an" | "the" | "my"
N -> "dog" | "cat" | "cookie" | "park"
P -> "in" | "on" | "by" | "with"
""")
rd_parser = RecursiveDescentParser(grammar)
sentence = 'John saw a cat'.split()
for tree in rd_parser.parse(sentence):
print(tree)
Output:
(S (NP John) (VP (V saw) (NP (Det a) (N cat))))
在此代码中,我们首先使用 NLTK 定义上下文无关语法CFG.fromstring
方法。然后我们创建一个RecursiveDescentParser
具有给定语法的实例。
之后,我们提供一个句子作为单词列表parse
的方法RecursiveDescentParser
实例。该方法返回一个生成器,它为给定的句子生成所有可能的解析树。
Chunking
分块是从非结构化文本中提取短语的过程。使用“南非”等短语作为单个单词而不是“南方”和“非洲”单独的单词,而不是仅仅使用可能无法代表文本实际含义的简单标记,是有益的。
以下是在 NLTK 中进行名词短语分块的方法:
import nltk
from nltk import pos_tag
from nltk.tokenize import word_tokenize
from nltk.chunk import RegexpParser
sentence = "The big cat ate the little mouse who was after fresh cheese"
# PoS tagging
tagged = pos_tag(word_tokenize(sentence))
# Define your grammar using regular expressions
grammar = ('''
NP: {<DT>?<JJ>*<NN>} # NP
''')
chunk_parser = RegexpParser(grammar)
result = chunk_parser.parse(tagged)
print(result)
Output:
(S
(NP The/DT big/JJ cat/NN)
ate/VBD
(NP the/DT little/JJ mouse/NN)
who/WP
was/VBD
after/IN
(NP fresh/JJ cheese/NN))
在这段代码中,我们首先对我们的句子进行标记和 PoS 标记。然后,我们将名词短语 (NP) 的语法定义为任何可选限定词 (DT),后跟任意数量的形容词 (JJ),然后是名词 (NN)。
然后我们用这个语法创建了一个块解析器RegexpParser
,最后解析了我们的标记句子。
Chinking
Chinking 是从块中删除一系列标记的过程。如果匹配的标记序列跨越整个块,则删除整个块;如果标记序列出现在块的中间,则这些标记将被删除,留下两个块,而之前只有一个块。
如果序列位于块的外围,则删除这些标记,并保留较小的块。
以下是在 NLTK 中进行 chinking 的方法:
from nltk import pos_tag, RegexpParser
from nltk.tokenize import word_tokenize
sentence = "The big cat ate the little mouse who was after fresh cheese"
# PoS tagging
tagged = pos_tag(word_tokenize(sentence))
# We are removing from the chink one or more verbs, prepositions, determiners, or the word 'to'.
grammar = r"""
NP:
{<.*>+} # Chunk everything
}<VBD|IN|DT|TO>+{ # Chink sequences of VBD, IN, DT, TO
"""
chunk_parser = RegexpParser(grammar)
result = chunk_parser.parse(tagged)
print(result)
Output:
(S
(NP The/DT big/JJ cat/NN)
ate/VBD
(NP the/DT little/JJ mouse/NN)
who/WP
was/VBD
after/IN
(NP fresh/JJ cheese/NN))
在此代码中,我们首先对我们的句子进行标记和 PoS 标记。然后我们定义一种用于 chinking 的语法:我们从词块中删除一个或多个动词、介词、限定词或单词“to”。
然后我们使用这个语法创建一个块解析器RegexpParser
,最后解析我们的标记句子。
N-Grams
文本 N 元语法广泛用于文本挖掘和自然语言处理任务。
它们基本上是给定窗口内一组同时出现的单词,在计算 n 元语法时,您通常会向前移动一个单词。
以下是使用 NLTK 生成二元组的方法:
from nltk import ngrams
from nltk.tokenize import word_tokenize
sentence = "The big cat ate the little mouse who was after fresh cheese"
# Tokenize the sentence
tokens = word_tokenize(sentence)
# Generate bigrams
bigrams = list(ngrams(tokens, 2))
print(bigrams)
Output:
[('The', 'big'), ('big', 'cat'), ('cat', 'ate'), ('ate', 'the'), ('the', 'little'), ('little', 'mouse'), ('mouse', 'who'), ('who', 'was'), ('was', 'after'), ('after', 'fresh'), ('fresh', 'cheese')]
在上面的代码中,我们首先对句子进行标记,然后使用ngrams
来自 NLTK 的函数。
第二个论点ngrams
函数是克数,在本例中为 2。因此,我们得到连续单词对。
情绪分析
对于情感分析,NLTK有一个内置模块,nltk.sentiment.vader
,它结合了词汇和语法启发法以及基于人工注释数据训练的统计模型。
以下是如何使用 NLTK 执行情感分析的基本示例:
from nltk.sentiment import SentimentIntensityAnalyzer
from nltk.sentiment.util import *
sia = SentimentIntensityAnalyzer()
text = "Python is an awesome programming language."
print(sia.polarity_scores(text))
Output:
{'neg': 0.0, 'neu': 0.439, 'pos': 0.561, 'compound': 0.6249}
在上面的代码中,我们首先创建一个SentimentIntensityAnalyzer
目的。然后,我们向分析器输入一段文本并打印结果情绪分数。
输出是一个包含四个键的字典:neg
, neu
, pos
, and compound
. The neg
, neu
, and pos
值分别表示文本中负面、中性和正面情绪的比例。
The compound
分数是一个汇总指标,表示文本的整体情感,根据前三个指标计算得出。
信息检索
信息检索是从这些资源的集合中获取与信息需求相关的信息系统资源的活动。
在 NLP 和文本挖掘方面,信息检索是一个关键组成部分。
以下是如何使用 NLTK 检索有关特定令牌的信息的示例:
from nltk.text import Text
from nltk.tokenize import word_tokenize
text = "Python is a high-level programming language. Python is an interpreted language. Python is interactive."
tokens = word_tokenize(text)
text = Text(tokens)
# Concordance gives words that appear in a similar range of contexts
print(text.concordance("Python"))
Output:
Displaying 3 of 3 matches:
Python is a high-level programming languag
a high-level programming language . Python is an interpreted language . Python
Python is an interpreted language . Python is interactive .
None
在此代码中,我们首先对文本进行标记并创建一个Text
对象与我们的令牌。然后我们调用concordance
我们的方法Text
带有“Python”一词的对象。这concordance
方法给出出现在与我们输入单词相似的上下文范围内的单词。
频率分布
频率分布用于统计文本中每个单词的频率。它是一个分布,因为它告诉我们文本中的单词标记总数如何在单词类型之间分布。
以下是使用 NLTK 计算频率分布的方法:
from nltk.probability import FreqDist
from nltk.tokenize import word_tokenize
text = "Python is an interpreted, high-level, general-purpose programming language."
# Tokenize the sentence
tokens = word_tokenize(text)
# Create frequency distribution
fdist = FreqDist(tokens)
# Print the frequency of each word
for word, freq in fdist.items():
print(f'{word}: {freq}')
Output:
Python: 1
is: 1
an: 1
interpreted: 1
,: 2
high-level: 1
general-purpose: 1
programming: 1
language: 1
.: 1
在上面的代码中,我们首先对文本进行标记,然后使用以下命令创建频率分布FreqDist
来自 NLTK 的课程。我们将代币传递给FreqDist
class.
The FreqDist
对象有一个items
返回元组列表的方法,其中每个元组都是文本中的一个单词及其相应的频率。我们打印每个单词及其频率。
进一步阅读
https://www.nltk.org/book/