【ML特征工程】第 3 章 :文本数据:扁平化、过滤和分块

   🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎

 

📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​

📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】  深度学习【DL】

 🖍foreword

✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。

如果你对这个系列感兴趣的话,可以关注订阅哟👋

文章目录

Bag-of-X:将自然文本转换为平面向量

Bag-of-Words

Bag-of-n-Grams

过滤清洁功能

停用词

基于频率的过滤

常用词

生僻字

词干提取

意义的原子:从单词到 n-Grams 再到短语

解析和标记化

字符串对象:不止于此

用于短语检测的搭配提取

基于频率的方法

搭配提取的假设检验

掌握似然比检验

分块和词性标注

概括


如果你正在设计一种算法来分析以下段落,你会怎么做文字?

艾玛敲了敲门。没有答案。她又敲了敲门,等待着。房子旁边有一棵大枫树。艾玛抬头看着树,看到一只巨大的乌鸦栖息在树梢上。午后的阳光下,乌鸦熠熠生辉。它的喙又硬又尖,爪子锋利而有力。它看起来富丽堂皇。它统治着它所站立的树。乌鸦正用它圆圆的黑眼睛直直地看着艾玛。艾玛感到有点害怕。她从门口退了一步,试探着开口:“喂?”

这段包含了很多信息。我们知道它涉及一个名叫艾玛的人和一只乌鸦。有一所房子和一棵树,艾玛正试图进入房子,却看到了乌鸦。乌鸦很厉害,注意到艾玛,艾玛有点害怕,但正在尝试交流。

那么,这些信息中的哪些部分是我们应该提取的显着特征?首先,提取主要角色 Emma 和乌鸦的名字似乎是个好主意。接下来,注意房屋、门和树的环境也可能很好。那么乌鸦的描述呢?Emma 的行为如何——敲门、退后一步、打招呼?

本章介绍了文本特征工程的基础知识。我们从词袋开始,这是基于字数统计的最简单表示。一个非常相关的转换是tf-idf,它本质上是一种特征缩放技术。它被拉到自己的章节(下一章)中进行全面讨论。本章首先讨论文本提取特征,然后深入探讨如何过滤和清洗这些特征。

Bag-of-X:将自然文本转换为平面向量

无论是构建机器学习模型还是工程特征,如果结果简单且可解释,那就太好了。简单的东西很容易尝试,可解释的特征和模型比复杂的更容易调试。简单且可解释的特征并不总能产生最准确的模型,但最好从简单开始,只在绝对必要时才增加复杂性。

对于文本数据,我们可以从称为词袋的字数统计列表开始。字数列表不会特别努力地找到有趣的实体,例如 Emma 或乌鸦。但是这两个词在我们的示例段落中被重复提及,并且它们比“你好”这样的随机词有更高的计数。对于诸如对文档进行分类之类的简单任务,字数统计通常就足够了。该技术还可用于信息检索,其目标是检索与输入文本查询相关的文档集。词级特征可以很好地完成这两项任务,因为某些词的存在与否是文档主题内容的重要指标。

Bag-of-Words

在词袋 (BoW) 特征化中,文本文档被转换为计数向量。(向量只是n 个数字的集合。)向量包含词汇表中每个可能单词的条目。如果单词——比如“aardvark”——在文档中出现了 3 次,那么特征向量在与该单词对应的位置的计数为 3。如果词汇表中的一个词没有出现在文档中,那么它的计数为 0。例如,文本“it is a puppy and it is extremely cute”具有图 3-1所示的 BoW 表示。

图 3-1。将原始文本转换为词袋表示

词袋将文本文档转换为平面向量。它是“扁平”的,因为它不包含任何原始文本结构。 原始文本是一个单词序列。但是词袋没有顺序;它只记住每个单词在文本中出现的次数。因此,如图 3-2所示,向量中单词的顺序并不重要,只要它对于数据集中的所有文档都是一致的即可。词袋也不代表任何单词层次结构的概念。例如,“动物”的概念包括“狗”、“猫”、“乌鸦”等。但在词袋表示中,这些词都是向量的相等元素。

图 3-2。两个等价的 BoW 向量

这里重要的是特征空间中数据的几何形状。在词袋向量中,每个词都成为向量的一个维度。如果词汇表中有n 个词,那么一篇文档就成为n维空间 中的一个点1 。很难想象超出二维或三维的任何东西的几何形状,所以我们将不得不运用我们的想象力。 图 3-3 显示了我们的例句在二维特征空间中对应于单词“puppy”和“cute”的样子。

图 3-3。二维特征空间中示例文本文档的插图

图 3-4 显示了 3D 空间中的三个句子,对应于单词“puppy”、“extremely”和“cute”。

图 3-4。3D特征空间中的三个句子

这些数字两者都描述了特征空间中的数据向量。轴表示单个单词,它们是词袋表示中的特征,空间中的点表示数据点(文本文档)。有时查看数据空间中的特征向量也会提供信息。特征向量包含每个数据点中的特征值。轴表示单个数据点,点表示特征向量。图 3-5 显示了一个示例。对于文本文档的词袋特征化,一个特征就是一个词,一个特征向量包含这个词在每个文档中的计数。通过这种方式,一个词被表示为“文件袋”。正如我们将在 第 4 章中看到的,这些文档袋向量来自词袋向量的矩阵转置。

图 3-5。文档空间中的词向量

词袋并不完美。将一个句子分解成单个词会破坏语义。例如,“not bad”在语义上意味着“体面”甚至“好”(特别是如果你是英国人)。但“不是”和“不好”构成了浮动否定加负面情绪。“toy dog”和“dog toy”可能是非常不同的东西(除非它是玩具狗的 dog toy),单例词“toy”和“dog”失去了意义。很容易想出许多这样的例子。我们接下来讨论的 Bag-of- n - Grams 缓解了一些问题,但不是根本性的解决方案。最好记住,词袋是一种简单而有用的启发式方法,但它远非对文本的正确语义理解。

Bag-of-n-Grams

Bag-of- n - Grams,或bag-of- n - grams,是bag-of-words的自然延伸。n- gram是n 个标记的序列。一个词本质上是一个 1-gram,也称为unigram。代币化后的计数机制可以将单个标记整理成字数,或将重叠序列计为n- gram。例如,句子“Emma knocked on the door”生成n- grams“Emma knocked”、“knocked on”、“on the”和“the door”。

n- grams 保留了更多文本的原始序列结构,因此 bag-of- n - grams 表示可以提供更多信息。然而,这是有代价的。理论上,对于k个独特的单词,可能有2 个独特的 2-grams(也称为bigrams)。在实际上,几乎没有那么多,因为不是每个词都可以跟在其他词后面。然而,通常有比单词更多的不同的n- grams ( n > 1)。这意味着 bag-of- n - grams 是一个更大更稀疏的特征空间。这也意味着n- gram 的计算、存储和建模成本更高。n越大,信息越丰富,代价越大。

为了说明 n-gram 的数量如何随着n的增加而增长见图3-6),让我们计算Yelp 评论数据集上的n- gram  。在示例 3-1中,我们计算了n- grams前 10,000 条评论使用熊猫CountVectorizerscikit-learn 中 的转换器。

示例 3-1。计算 n-gram

>>> import pandas
>>> import json
>>> from sklearn.feature_extraction.text import CountVectorizer

# Load the first 10,000 reviews
>>> f = open('data/yelp/v6/yelp_academic_dataset_review.json')
>>> js = []
>>> for i in range(10000):
...     js.append(json.loads(f.readline()))
>>> f.close()
>>> review_df = pd.DataFrame(js)

# Create feature transformers for unigrams, bigrams, and trigrams.
# The default ignores single-character words, which is useful in practice because 
# it trims uninformative words, but we explicitly include them in this example for 
# illustration purposes.
>>> bow_converter = CountVectorizer(token_pattern='(?u)\\b\\w+\\b')
>>> bigram_converter = CountVectorizer(ngram_range=(2,2), 
...                                    token_pattern='(?u)\\b\\w+\\b')
>>> trigram_converter = CountVectorizer(ngram_range=(3,3), 
...                                     token_pattern='(?u)\\b\\w+\\b')

# Fit the transformers and look at vocabulary size
>>> bow_converter.fit(review_df['text'])
>>> words = bow_converter.get_feature_names()
>>> bigram_converter.fit(review_df['text'])
>>> bigrams = bigram_converter.get_feature_names()
>>> trigram_converter.fit(review_df['text'])
>>> trigrams = trigram_converter.get_feature_names()
>>> print (len(words), len(bigrams), len(trigrams))
26047 346301 847545

# Sneak a peek at the n-grams themselves
>>> words[:10]
['0', '00', '000', '0002', '00am', '00ish', '00pm', '01', '01am', '02']

>>> bigrams[-10:]
['zucchinis at',
 'zucchinis took',
 'zucchinis we',
 'zuma over',
 'zuppa di',
 'zuppa toscana',
 'zuppe di',
 'zurich and',
 'zz top',
 'à la']

>>> trigrams[:10]
['0 10 definitely',
 '0 2 also',
 '0 25 per',
 '0 3 miles',
 '0 30 a',
 '0 30 everything',
 '0 30 lb',
 '0 35 tip',
 '0 5 curry',
 '0 5 pork']

图 3-6。Yelp 数据集前 10,000 条评论中唯一的 n-gram 数

过滤清洁功能

有了文字,我们如何清楚地将信号与噪音分开? 通过过滤、技巧使用原始标记化和计数以生成简单单词或n- gram 的列表变得更有用。我们接下来将讨论的短语检测可以看作是一个特定的二元过滤器。 这里有几种执行过滤的方法。

停用词

分类和检索通常不需要对文本有深入的理解。例如,在“Emma knocked on the door”这句话中,“on”和“the”并没有改变这句话是关于一个人和一扇门的事实。对于分类等粗粒度任务,代词、冠词和介词可能不会增加太多价值。在情感分析中,情况可能非常不同,这需要对语义有细粒度的理解。

流行的 Python NLP 包NLTK包含一个语言学家为许多语言定义的停用词列表。(您将需要安装 NLTK 并运行nltk.download()以获取所有好处。)也可以在 Web 上找到各种停用词列表。例如,以下是英语停用词列表中的一些示例词:

a, about, above, am, an, been, didn't, couldn't, i'd, i'll, itself, let's, myself, 
our, they, through, when's, whom, ...

请注意,该列表包含撇号,并且单词未大写。为了按原样使用它,标记化过程不能吃掉撇号,并且需要将单词转换为小写。

基于频率的过滤

停用词列表是一种剔除构成空洞特征的常用词的方法。还有其他更多的统计方法来理解“常用词”的概念。在搭配抽取中,我们看到了依赖于手动定义的方法,以及那些使用统计数据的方法。同样的想法也适用于单词过滤。我们也可以在这里使用频率统计。

常用词

频率统计对于过滤掉特定于语料库的常用词以及通用停用词非常有用。 例如,短语“New York Times”及其中的每个单词都经常出现在New York Times Annotated Corpus 数据集中同样,在加拿大议会辩论的Hansard 语料库中,“House”一词经常出现在短语“House of Commons”中,该数据集广泛用于统计机器翻译,因为它包含所有文件的英语和法语版本。这些词在一般情况下是有意义的,但在那些特定的语料库中却没有。典型的停用词列表会捕获一般停用词,但不会捕获特定于语料库的停用词。

查看最频繁的词可以揭示解析问题并突出显示在语料库中恰好出现太多次的通常有用的词。例如,表 3-1 列出了 Yelp 评论数据集中出现频率最高的 40 个词。在这里,频率基于它们出现在文档(评论)中的数量,而不是它们在文档中的数量。正如我们所见,该列表包含许多停用词。它还包含一些惊喜。“s”和“t”在列表中是因为我们使用撇号作为标记化分隔符,并且诸如“Mary's”或“didn't”之类的词被解析为“Mary s”和“didnt”。此外,“good”、“food”和“great”等词分别出现在大约三分之一的评论中,但我们可能希望保留它们,因为它们对于情绪分析或业务分类等任务非常有用。

RankWordDocument frequencyRankWordDocument frequency
1the141605821t684049
2and138132422not649824
3a126312623s626764
4i123021424had620284
5to119623825so608061
6it102783526place601918
7of102563827good598393
8for99343028at596317
9is98854729are585548
10in96151830food562332
11was92970331be543588
12this84482432we537133
13but82231333great520634
14my78659534were516685
15that77704535there510897
16with77504436here481542
17on73541937all478490
18they72099438if475175
19you70101539very460796
20have69274940out460452

在实践中,它有助于将基于频率的过滤与停用词列表结合起来。还有一个棘手的问题是在哪里设置截止点。不幸的是,没有通用的答案。大多数情况下,截止值需要手动确定,并且可能需要在数据集发生变化时重新检查。

生僻字

根据任务的不同,可能还需要过滤掉不常用的词。这些可能是真正晦涩难懂的词,或者是常用词的拼写错误。对于统计模型来说,只出现在一两个文档中的词更像是噪音,而不是有用的信息。例如,假设任务是根据 Yelp 评论对企业进行分类,并且一条评论包含“gobbledygook”一词。如何根据这个词判断该企业是餐厅、美容院还是酒吧?即使我们知道这个案例中的企业恰好是一家酒吧,对于其他包含“gobbledygook”一词的评论,将其归类为酒吧也可能是错误的。

稀有词作为预测因子不仅不可靠,而且还会产生计算开销。160 万条 Yelp 评论集包含 357,481 个独特的单词(由空格和标点符号标记),其中 189,915 个出现在一条评论中,41,162 个出现在两条评论中。60%以上的词汇很少出现。这就是所谓的重尾分布,非常在现实世界的数据中很常见。许多统计机器学习模型的训练时间与特征数量呈线性关系,有些模型是二次方或更糟的。稀有词会产生大量计算和存储成本,而不会带来太多额外收益。

可以根据字数统计轻松识别和修剪生僻字。或者,它们的计数可以汇总到一个特殊的垃圾箱中,这可以作为一项附加功能。 图 3-7 演示了在包含一堆常用词和两个稀有词“gobbledygook”和“zylophant”的短文档上的这种表示。常用词保留自己的计数,可以通过停用词列表或其他基于频率的方法进一步过滤。稀有词失去了它们的身份,并被归类到垃圾箱特征中。

图 3-7。带有垃圾箱的词袋特征向量

由于在对整个语料库进行计数之前,人们不会知道哪些词是罕见的,因此需要收集垃圾桶特征作为后处理步骤。

由于本书是关于特征工程的,所以我们的重点是特征。但稀有性的概念也适用于数据点。如果文本文档非常短,那么它可能不包含任何有用的信息,不应在训练模型时使用。但是,在应用此规则时必须谨慎。维基百科转储包含许多不完整的存根页面,可以安全地过滤掉这些页面。另一方面,推文本质上很短,需要其他特征化和建模技巧。

词干提取

简单解析的一个问题是同一词的不同变体被计为不同的词。例如,“花”和“花”在技术上是不同的标记,“游泳者”、“游泳”和“游泳”也是如此,尽管它们的含义非常接近。如果所有这些不同的变体都映射到同一个词,那就太好了。

词干提取是一项 NLP 任务,它试图将每个单词分解成其基本的语言词干形式。有不同的方法。有些基于语言规则,有些基于观察到的统计数据。算法的一个子类在称为词形还原的过程中结合了词性标记和语言规则。

大多数词干提取工具都专注于英语,尽管其他语言的工作正在进行中。Porter 词干提取器是使用最广泛的免费英语词干提取工具。原始程序是用 ANSI C 编写的,但后来许多其他软件包对其进行了封装以提供对其他语言的访问。

下面是一个通过 NLTK Python 包运行 Porter 词干分析器的示例。如您所见,它处理了大量案例,但并不完美。“goes”这个词被映射到“goe”,而“go”被映射到它自己:

>>> import nltk
>>> stemmer = nltk.stem.porter.PorterStemmer()
>>> stemmer.stem('flowers')
u'flower'
>>> stemmer.stem('zeroes')
u'zero'
>>> stemmer.stem('stemmer')
u'stem'
>>> stemmer.stem('sixties')
u'sixti'
>>> stemmer.stem('sixty')
u'sixty'
>>> stemmer.stem('goes')
u'goe'
>>> stemmer.stem('go')
u'go'

词干提取确实有计算成本。最终收益是否超过成本取决于应用程序。同样值得注意的是,词干提取可能弊大于利。“新”和“新闻”这两个词的含义截然不同,但都可以归结为“新”。类似的例子比比皆是。因此,并不总是使用词干提取。

意义的原子:从单词到 n-Grams 再到短语

词袋的概念很简单。但是计算机怎么知道一个词是什么?文本文档以数字方式表示为一个字符串,它基本上是一个字符序列。人们还可能会遇到 JSON blob 或 HTML 页面形式的半结构化文本。但即使添加了标签和结构,基本单位仍然是字符串。如何将字符串转换为单词序列?这涉及到解析标记化的任务,我们接下来将讨论这些任务。

解析和标记化

当字符串包含的不仅仅是纯文本时,解析是必要的。例如,如果原始数据是网页、电子邮件或某种日志,那么它包含额外的结构。需要决定如何处理标记、页眉和页脚或日志中无趣的部分。如果文档是网页,那么解析器需要处理 URL。如果它是一封电子邮件,那么 From、To 和 Subject 等字段可能需要特殊处理——否则这些标题在最终计数中将作为正常单词结束,这可能没有用。

轻度解析后,文档的纯文本部分可以进行标记化。这会将字符串(字符序列)转换为标记序列。然后每个标记都可以算作一个单词。标记器需要知道哪些字符表示一个标记已经结束而另一个正在开始。空格字符通常是良好的分隔符,标点符号也是如此。如果文本包含推文,则井号 (#) 不应用作分隔符(也称为定界符)。

有时,分析需要对句子进行操作而不是整个文档。例如,n- grams,一个词概念的泛化,不应该超出句子的界限。更复杂的文本特征化方法(如 word2vec)也适用于句子或段落。在这些情况下,需要首先将文档解析为句子,然后进一步将每个句子标记为单词。

字符串对象:不止于此

字符串对象来了在各种编码中,像 ASCII 或 Unicode。纯英文文本可以用 ASCII 编码。大多数其他语言都需要 Unicode。如果文档包含非 ASCII 字符,请确保分词器可以处理该特定编码。否则,结果将不正确。

用于短语检测的搭配提取

一系列标记立即产生单词列表和n- grams。语义上不过,说起来我们更习惯于理解短语,而不是n- gram。在计算性自然语言处理 (NLP) 中,有用短语的概念称为搭配。用 Manning 和 Schütze (1999: 151) 的话来说,“搭配是一种由两个或多个词组成的表达方式,它们对应于某种常规的表达方式。”

搭配比各部分的总和更有意义。例如,“浓茶”除了“强壮的体力”和“茶”之外还有不同的含义;因此,它被认为是搭配。另一方面,短语“cute puppy”的意思恰好是其部分的总和:“cute”和“puppy”。因此,它不被视为搭配。

搭配不必是连续的序列。例如,句子“Emma knocked on the door”被认为包含搭配“knock door”。因此,并不是每一个搭配是一个 n-gram。相反,并非每个 n-gram 都被认为是有意义的搭配。

因为搭配不仅仅是它们各部分的总和,所以它们的含义不能通过单个单词计数来充分捕捉。Bag-of-words 不能作为一种表示。Bag-of- n - grams 也有问题,因为它捕获了太多无意义的序列(考虑 bag-of- n - grams 示例中的“this is”)而没有足够的有意义的序列(即,敲门)。

搭配作为特征很有用。但是如何从文本中发现和提取它们呢?一种方法是预定义它们。如果我们非常努力地尝试,我们可能会找到各种语言的完整成语列表,并且我们可以在文本中查找任何匹配项。这将非常昂贵,但它会起作用。如果语料库非常特定于领域并且包含深奥的行话,那么这可能是首选方法。但是这个列表需要大量的人工管理,并且需要不断更新以适应不断发展的语料库。例如,分析推文、博客和文章可能不太现实。

自从过去二十年统计 NLP 出现以来,人们越来越多地选择统计方法来查找短语。统计搭配提取方法不是建立固定的短语和惯用语列表,而是依靠不断发展的数据来揭示当今流行的谚语。

基于频率的方法

一个简单的技巧就是看最频繁出现的n- grams。这种方法的问题是最常出现的可能不是最有用的。 表 3-2 显示了最流行的二元组 (n=2) 在整个 Yelp 评论数据集中。正如我们所看到的,按文档计数排名前 10 位最常出现的二元组是非常笼统的术语,没有太多含义。

BigramDocument count
of the450,849
and the426,346
in the397,821
it was396,713
this place344,800
it s341,090
and i332,415
on the325,044
i was285,012
for the276,946

搭配提取的假设检验

原始人气计数过于粗略。我们必须找到更聪明的统计数据才能轻松挑选出有意义的短语。关键思想是询问两个词一起出现的频率是否比它们偶然出现的频率高。回答这个问题的统计机制称为假设检验

假设检验是一种将嘈杂数据归结为“是”或“否”答案的方法。它涉及将数据建模为从随机分布中抽取的样本。随机性意味着永远无法 100% 确定答案;总是有异常值的机会。因此,答案附有概率。

例如,假设检验的结果可能是“这两个数据集来自相同分布的概率为 95%”。有关假设检验的简单介绍,请参阅可汗学院关于假设检验和 p 值的教程。

在搭配提取的背景下,多年来提出了许多假设检验。  最成功的方法之一是基于似然比检验 (Dunning, 1993)。对于给定的一对单词,该方法在观察到的数据集上测试两个假设。假设 1(原假设)说词 1 独立于词 2 出现。另一种说法是,看到词 1 与我们是否也看到词 2 无关。假设 2(备择假设)说看到词 1改变了看到单词 2 的可能性。我们采用替代假设来暗示这两个单词形成一个共同的短语。因此,短语检测(又名搭配提取)的似然比检验会提出以下问题:在给定文本语料库中观察到的单词出现是否更有可能从两个单词彼此独立出现的模型中生成,

那是一口。让我们算一下。(数学非常擅长非常精确和简洁地表达事物,但它确实需要与自然语言完全不同的解析器。)

我们可以将原假设H null(独立)表示为P(w 2 | w 1 ) = P(w 2 | not w 1 ),备择假设H alternate(非独立)表示为P(w 2 | w 1 ) ≠ P(w 2 |不是w 1 )

最终的统计数据是两者之间比率的对数:

 似然函数L(Data; H)表示在单词对的独立或非独立模型下,在数据集中看到单词频率的概率。为了计算这个概率,我们必须对数据的生成方式做出另一个假设。最简单的数据生成模型是二项式模型,对于数据集中的每个单词,我们掷硬币,如果硬币正面朝上则插入我们的特殊单词,否则插入其他单词。在这个策略下,计数的数量特殊词的出现服从二项分布。二项分布完全由总词数、感兴趣词出现次数和正面概率决定。

检测算法常用短语通过似然比检验分析进行如下:

  1. 计算所有单独单词的出现概率:P(w)
  2. 计算所有唯一双字母组的条件成对词出现概率:P(w 2 | w 1 )
  3. 计算所有唯一双字母组的似然比 log  λ
  4. 根据似然比对二元组进行排序。
  5. 将似然比值最小的二元组作为特征。

掌握似然比检验

关键是测试比较的不是概率参数本身,而是在这些参数(和假设的数据生成模型)下看到观察到的数据的概率。似然法是统计学习的关键原则之一,但当您第一次看到它时,它绝对是一个令人头疼的问题。一旦你弄清楚了逻辑,它就会变得直观。

还有另一种基于逐点互信息的统计方法,但它对稀有词非常敏感,这些词总是存在于现实世界的文本语料库中。因此,它不常用,我们不会在这里演示。

请注意,所有用于搭配提取的统计方法,无论是使用原始频率、假设检验还是逐点互信息,都是通过过滤候选短语列表来操作的。生成这样一个列表的最简单和最便宜的方法是计算n- grams。可以生成不连续的序列,但它们的计算成本很高。在实践中,即使对于连续的n元语法,人们也很少超越二元语法或三元语法,因为它们太多了,即使在过滤之后也是如此。要生成更长的短语,还有其他方法,例如分块或与词性 (PoS) 标记相结合。

分块和词性标注

分块比查找n- gram 更复杂一些,因为它形成序列代币基于部分的演讲,使用基于规则的模型。

例如,我们可能最感兴趣的是在实体(在本例中为文本的主题)对我们最感兴趣的问题中找到所有名词短语。为了找到这一点,我们用词性对每个单词进行标记,然后检查标记的邻域以寻找词性分组或“块”。将单词映射到词性的模型通常是特定于语言的。多个开源 Python 库(例如 NLTK、  spaCyTextBlob)具有多种可用的语言模型。 

为了说明几个库在 Python 中使用 PoS 标记进行分块非常简单,让我们再次使用 Yelp 评论数据集。在示例 3-2中,我们评估词性以使用 spaCy 和 TextBlob 找到名词短语。

示例 3-2。PoS 标记和分块

>>> import pandas as pd
>>> import json

# Load the first 10 reviews
>>> f = open('data/yelp/v6/yelp_academic_dataset_review.json')
>>> js = []
>>> for i in range(10):
...     js.append(json.loads(f.readline()))
>>> f.close()
>>> review_df = pd.DataFrame(js)

# First we'll walk through spaCy's functions
>>> import spacy
# preload the language model
>>> nlp = spacy.load('en')

# We can create a Pandas Series of spaCy nlp variables
>>> doc_df = review_df['text'].apply(nlp)

# spaCy gives us fine-grained parts of speech using (.pos_) 
# and coarse-grained parts of speech using (.tag_)
>>> for doc in doc_df[4]:
...     print([doc.text, doc.pos_, doc.tag_])

Got VERB VBP
a DET DT
letter NOUN NN
in ADP IN
the DET DT
mail NOUN NN
last ADJ JJ
week NOUN NN
that ADJ WDT
said VERB VBD
Dr. PROPN NNP
Goldberg PROPN NNP
is VERB VBZ
moving VERB VBG
to ADP IN
Arizona PROPN NNP
to PART TO
take VERB VB
a DET DT
new ADJ JJ
position NOUN NN
there ADV RB
in ADP IN
June PROPN NNP
. PUNCT .
  SPACE SP
He PRON PRP
will VERB MD
be VERB VB
missed VERB VBN
very ADV RB
much ADV RB
. PUNCT .


SPACE SP
I PRON PRP
think VERB VBP
finding VERB VBG
a DET DT
new ADJ JJ
doctor NOUN NN
in ADP IN
NYC PROPN NNP
that ADP IN
you PRON PRP
actually ADV RB
like INTJ UH
might VERB MD
almost ADV RB
be VERB VB
as ADV RB
awful ADJ JJ
as ADP IN
trying VERB VBG
to PART TO
find VERB VB
a DET DT
date NOUN NN
! PUNCT .

# spaCy also does some basic noun chunking for us
>>> print([chunk for chunk in doc_df[4].noun_chunks])
[a letter, the mail, Dr. Goldberg, Arizona, a new position, June, He, I, 
a new doctor, NYC, you, a date]

#####
# We can do the same feature transformations using Textblob
from textblob import TextBlob

# The default tagger in TextBlob uses the PatternTagger, which is OK for our example.
# You can also specify the NLTK tagger, which works better for incomplete sentences.
>>> blob_df = review_df['text'].apply(TextBlob)

>>> blob_df[4].tags
[('Got', 'NNP'),
('a', 'DT'),
('letter', 'NN'),
('in', 'IN'),
('the', 'DT'),
('mail', 'NN'),
('last', 'JJ'),
('week', 'NN'),
('that', 'WDT'),
('said', 'VBD'),
('Dr.', 'NNP'),
('Goldberg', 'NNP'),
('is', 'VBZ'),
('moving', 'VBG'),
('to', 'TO'),
('Arizona', 'NNP'),
('to', 'TO'),
('take', 'VB'),
('a', 'DT'),
('new', 'JJ'),
('position', 'NN'),
('there', 'RB'),
('in', 'IN'),
('June', 'NNP'),
('He', 'PRP'),
('will', 'MD'),
('be', 'VB'),
('missed', 'VBN'),
('very', 'RB'),
('much', 'JJ'),
('I', 'PRP'),
('think', 'VBP'),
('finding', 'VBG'),
('a', 'DT'),
('new', 'JJ'),
('doctor', 'NN'),
('in', 'IN'),
('NYC', 'NNP'),
('that', 'IN'),
('you', 'PRP'),
('actually', 'RB'),
('like', 'IN'),
('might', 'MD'),
('almost', 'RB'),
('be', 'VB'),
('as', 'RB'),
('awful', 'JJ'),
('as', 'IN'),
('trying', 'VBG'),
('to', 'TO'),
('find', 'VB'),
('a', 'DT'),
('date', 'NN')]

>>> print([np for np in blob_df[4].noun_phrases])
['got', 'goldberg', 'arizona', 'new position', 'june', 'new doctor', 'nyc']

可以看到每个库找到的名词短语都有些不同。spaCy 包含英语中的常用词,如“a”和“the”,而 TextBlob 删除了这些词。这反映了驱动每个图书馆认为是名词短语的规则引擎的差异。您还可以编写您的词性关系来定义您正在寻找的块。见伯德等人。(2009) 从头开始​​真正深入研究 Python 分块。

概括

词袋表示简单易懂,容易计算,对分类和搜索任务很有用。但有时单个词过于简单,无法将文本中的某些信息封装起来。为了解决这个问题,人们寻求更长的序列。Bag-of- n - grams 是 bag-of-words 的自然推广。这个概念仍然很容易理解,而且它和词袋一样容易计算。

Bag-of- n - gram 生成更多不同的n- gram。它增加了特征存储成本,以及模型训练和预测阶段的计算成本。数据点的数量保持不变,但特征空间的维度现在要大得多。因此,数据更加稀疏。n越大,存储和计算成本越高,数据越稀疏。由于这些原因,更长的n- gram 并不总是会导致模型准确性(或任何其他性能指标)的提高。人们通常在n = 2 或 3时停止。很少使用更长的n- gram。

对抗稀疏性和成本增加的一种方法是过滤n- gram 并仅保留最有意义的短语。这就是搭配抽取的目标。理论上,搭配(或短语)可以在文本中形成不连续的标记序列。然而,在实践中,寻找不连续的短语的计算成本要高得多,收益也不大。因此,搭配提取通常从候选的二元组列表开始,并利用统计方法对其进行过滤。

所有这些方法都将一系列文本标记转换为一组不连续的计数。集合的结构比序列少得多;它们导致平坦的特征向量。

在本章中,我们使用简单的文本特征化技术将脚趾浸入水中。这些技术将一段充满丰富语义结构的自然语言文本变成了一个简单的平面向量。我们讨论了一些用于清理矢量条目的常用过滤技术。我们还引入了n- grams 和搭配提取作为向平面向量中添加更多结构的方法。下一章将更详细地介绍另一个名为tf-idf 的常见文本特征化技巧。后续章节将讨论更多将结构添加回平面向量的方法。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sonhhxg_柒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值