NLP:词中的数学

我们已经收集了一些词(词条),对这些词进行了计数,并将它们归并成词干或者词元,接下来就可以做一些有趣的事情了。分析词对一些简单的任务有用,例如得到词用法的一些统计信息,或者进行关键词检索。但是我们想知道哪些词对于某篇具体文档和整个语料库更重要。于是,我们可以利用这个“重要度”值,基于文档内的关键词重要度在语料库中寻找相关文档。

这样做的话,会使我们的垃圾邮件过滤器更不可能受制于电子邮件中单个粗鲁或者几个略微垃圾的词。也因为有较大范围的词都带有不同正向程度的得分或标签,因此我们可以度量一条推文的正向或者友好程度。如果知道一些词在某文档内相对于剩余文档的频率,就可以利用这个信息来进一步修正文档的正向程度。在本章中,我们将会学习一个更精妙的非二值词度量方法,它能度量词及其用法在文档中的重要度。几十年来,这种做法是商业搜索引擎和垃圾邮件过滤器从自然语言中生成特征的主流做法。

下一步我们要探索将第2章中的词转换成连续值,而非只表示词出现数目的离散整数,也不只是表示特定词出现与否的二值位向量。将词表示为连续空间之后,就可以使用更令人激动的数学方法来对这些表示进行运算。我们的目标是寻找词的数值表示,这些表示在某种程度上刻画了词所代表的信息内容或重要度。我们要等到在第4章中才能看到如何将这些信息内容转换成能够表示词的意义的数值。

本章将会考察以下3种表示能力逐步增强的对词及其在文档中的重要度进行表示的方法:

重要说明  

TF-IDF表示词项频率(term frequency)乘以逆文档频率(inverse document frequency)。在上一章中我们曾经学到过,词项频率是指每个词在某篇文档中的出现次数。而逆文档频率指的是文档集合中的文档总数除以某个词出现的文档总数。

上述3种技术中的每一种都可以独立应用或者作为NLP流水线的一部分使用。由于它们都基于频率,因此都是统计模型。在本书的后面部分,我们会看到很多更深入观察词之间关系、模式和非线性关系的方法。

但是,这些浅层的NLP机器已经很强大,对于很多实际应用已经很有用,例如垃圾邮件过滤和情感分析。

3.1 词袋

在第2章我们构建了文本的第一个向量空间模型。我们使用了每个词的独热向量,然后将所有这些向量用二进制OR运算(或者截断和,clipped sum)组合以创建文本的向量表示。如果被加载到一个诸如Pandas DataFrame的数据结构中,这种二值的词袋向量也可以为文档检索提供一个很棒的索引。

接下来考虑一个更有用的向量表示方法,它计算词在给定文本中的出现次数或者频率。这里引入第一个近似假设,假设一个词在文档中出现的次数越多,那么该词对文档的意义的贡献就越大。相比于多次提到“cats”和“gravity”的文档,一篇多次提到“wings”和“rudder”的文档可能会与涉及喷气式飞机或者航空旅行的主题更相关。或者,我们给出了很多表达正向情感的词,如good、best、joy和fantastic,一篇文档包含的这类词越多,就认为它越可能包含了正向情感。然而可以想象,一个只依赖这些简单规则的算法可能会出错或者误导用户。

下面给出了一个统计词出现次数很有用的例子:

>>> from nltk.tokenize import TreebankWordTokenizer
>>> sentence = """The faster Harry got to the store, the faster Harry,
...     the faster, would get home."""
>>> tokenizer = TreebankWordTokenizer()
>>> tokens = tokenizer.tokenize(sentence.lower())
>>> tokens
['the',
 'faster',
 'harry',
 'got',
 'to',
 'the',
 'store',
 ',',
 'the',
 'faster',
 'harry',
 ',',
 'the',
 'faster',
 ',',
 'would',
 'get',
 'home',
 '.']

我们希望通过简单的列表(list),来从文档中得到独立的词及其出现次数。Python的字典可以很好地实现这一目标,由于同时要对词计数,因此可以像前面章节那样使用Counter

>>> from collections import Counter
>>> bag_of_words = Counter(tokens)
>>> bag_of_words
Counter({'the': 4,
         'faster': 3,
         'harry': 2,
         'got': 1,
         'to': 1,
         'store': 1,
         ',': 3,
         'would': 1,
         'get': 1,
         'home': 1,
         '.': 1})

使用Python中任意一种较好的字典实现,键的次序都会发生变换。新的次序针对存储、更新和检索做了优化,而不是为了保持显示的一致性,包含在原始语句词序中的信息内容被忽略。

注意 

collections.Couter对象是一个无序的集合(collection),也称为袋(bag)或者多重集合(multiset)。基于所使用的平台和Python版本,我们发现Counter会以某种看似合理的次序来显示,就像词库序或者词条在语句中出现的先后词序一样。但是,对于标准的Pythondict,我们不能依赖词条(键)在Counter中的次序。

像上面这样的短文档,无序的词袋仍然包含了句子的原本意图中的很多信息。这些词袋中的信息对于有些任务已经足够强大,这些任务包括垃圾邮件检测、情感(包括倾向性、满意度等)计算甚至一些微妙意图的检测如讽刺检测。虽然这只是一个词袋,但是它装满了意义和信息。因此,下面我们将这些词按照某种方式进行排序,以便能够对此有所了解。Counter对象有一个很方便的方法most_common,可以实现上述目标:

>>> bag_of_words.most_common(4)   ⇽--- 在默认情况下,most_common()会按照频率从高到低列出所有的词条,这里只给出频率最高的4个词条
[('the', 4), (',', 3), ('faster', 3), ('harry', 2)]

具体来说,某个词在给定文档中出现的次数称为词项频率,通常简写为TF。在某些例子中,可以将某个词的出现频率除以文档中的词项总数从而得到归一化的词项频率结果[1]。

上面的例子中,排名最靠前的4个词项或词条分别是“the”“,”“harry”和“faster”,但是“the”和标点符号“,”对文档的意图而言信息量不大,并且这些信息量不大的词条可能会在我们的快速探索之旅中多次出现。对本例来说,我们通过标准的英语停用词表和标点符号表来去掉这些词。后面我们不会总是这样做,但是现在这样做有助于问题的简化。因此,最后我们在排名靠前的词项频率向量(词袋)中留下了“harry”和“faster”这两个词条。

接下来从上面定义的Counter对象(bag_of_words)中计算“harry”的词频。

>>> times_harry_appears = bag_of_words['harry']
>>> num_unique_words = len(bag_of_words)   ⇽--- 原始语句中的独立词条数
>>> tf = times_harry_appears / num_unique_words
>>> round(tf, 4)
0.1818

这里先暂停一下,我们更深入了解一下归一化词项频率这个贯穿本书的术语。它是经过文档长度“调和”后的词频。但是为什么要“调和”呢?考虑词“dog”在文档A中出现3次,在文档B中出现100次。显然,“dog”似乎对文档B更重要,但是等等!这里的文档A只是一封写给兽医的30个词的电子邮件,而文档B却是包含大约580 000个词的长篇巨著《战争与和平》(War &Peace)!因此,我们一开始的分析结果应该正好反过来,即“dog”对文档A更重要。下列计算中考虑了文档长度:

TF(“dog, ” documentA ) = 3/30 = 0.1

TF(“dog, ” document___B___ ) = 100/580 000 = 0.000 17

现在,我们可以看到描述关于两篇文档的一些东西,以及这两篇文档和词“dog”的关系和两篇文档之间的关系。因此,我们不使用原始的词频来描述语料库中的文档,而使用归一化词项频率。类似地,我们可以计算每个词对文档的相对重要程度。显然,书中的主人公Harry及其对速度的要求是文档中故事的中心。我们已经做了很多的工作将文本转换成数值,而且超越了仅表示特定词出现与否的范围。当然,我们现在看到的只是一个人为的例子,但是通过这个例子我们能够快速看出基于该方法可能得到多么有意义的结果。下面考虑一个更长的文本片段,它来自维基百科中有关风筝(kite)的文章的前几个段落:

A kite is traditionally a tethered heavier-than-air craft with wing surfaces that react against the air to create lift and drag. A kite consists of wings, tethers, and anchors. Kites often have a bridle to guide the face of the kite at the correct angle so the wind can lift it. A kite’s wing also may be so designed so a bridle is not needed; when kiting a sailplane for launch, the tether meets the wing at a single point. A kite may have fixed or moving anchors. Untraditionally in technical kiting, a kite consists of tether-set-coupled wing sets; even in technical kiting, though, a wing in the system is still often called the kite.

The lift that sustains the kite in flight is generated when air flows around the kite’s surface, producing low pressure above and high pressure below the wings. The interaction with the wind also generates horizontal drag along the direction of the wind. The resultant force vector from the lift and drag force components is opposed by the tension of one or more of the lines or tethers to which the kite is attached. The anchor point of the kite line may be static or moving (such as the towing of a kite by a running person, boat, free-falling anchors as in paragliders and fugitive parakites or vehicle).

The same principles of fluid flow apply in liquids and kites are also used under water. A hybrid tethered craft comprising both a lighter-than-air balloon as well as a kite lifting surface is called a kytoon.

Kites have a long and varied history and many different types are flown inpidually and at festivals worldwide. Kites may be flown for recreation, art or other practical uses. Sport kites can be flown in aerial ballet, sometimes as part of a competition. Power kites are multi-line steerable kites designed to generate large forces which can be used to power activities such as kite surfing, kite landboarding, kite fishing, kite buggying and a new trend snow kiting. Even Man-lifting kites have been made.

——维基百科

然后,将该文本赋给变量:

>>> from collections import Counter
>>> from nltk.tokenize import TreebankWordTokenizer
>>> tokenizer = TreebankWordTokenizer()
>>> from nlpia.data.loaders import kite_text  ⇽--- 和上面一样,kite_text = “A kite is traditionally …”
>>> tokens = tokenizer.tokenize(kite_text.lower())
>>> token_counts = Counter(tokens)
>>> token_counts
Counter({'the': 26, 'a': 20, 'kite': 16, ',': 15, ...})

注意

TreebankWordTokenizer会返回“kite.”(带有句点)作为一个词条。Treebank分词器假定文档已经被分割成独立的句子,因此它只会忽略字符串最末端的标点符号。句子分割也是一件棘手的事情,我们将在第11章中介绍。尽管如此,由于在一趟扫描中就完成句子的分割和分词处理(还有很多其他处理),spaCy分析器表现得更快且更精确。因此,在生产型应用中,可以使用spaCy而不是前面在一些简单例子中使用的NLTK组件。

好了,回到刚才的例子,里面有很多停用词。这篇维基百科的文章不太可能会与“the”“a”、连词“and”以及其他停用词相关。下面把这些词去掉:

>>> import nltk
>>> nltk.download('stopwords', quiet=True)
True
>>> stopwords = nltk.corpus.stopwords.words('english')
>>> tokens = [x for x in tokens if x not in stopwords]
>>> kite_counts = Counter(tokens)
>>> kite_counts
Counter({'kite': 16,
         'traditionally': 1,
         'tethered': 2,
         'heavier-than-air': 1,
         'craft': 2,
         'wing': 5,
         'surfaces': 1,
         'react': 1,
         'air': 2,
         ...,
         'made': 1})}

单纯凭借浏览词在文档中出现的次数,我们就可以学到一些东西。词项kite(s)、wing和lift都很重要。并且,如果我们不知道这篇文章的主题是什么,只是碰巧在大规模的类谷歌知识库中浏览到这篇文章,那么我们可能“程序化”地推断出,这篇文章与“flight”或者“lift”相关,或者实际上和“kite”相关。

如果考虑语料库中的多篇文档,事情就会变得更加有趣。有一个文档集,这个文档集中的每篇文档和某个主题有关,如放飞风筝(kite flying)的主题。可以想象,在所有这些文档中“string”和“wind”的出现次数很多,因此这些文档中的词项频率TF("string")TF("wind")都会很高。下面我们将基于数学意图来更优雅地表示这些数值。

3.2 向量化

我们已经将文本转换为基本的数值。虽然仍然只是把它们存储在字典中,但我们已经从基于文本的世界中走出一步,而进入了数学王国。接下来我们要一直沿着这个方向走下去。我们不使用频率字典来描述文档,而是构建词频向量,在Python中,这可以使用列表来实现,但通常它是一个有序的集合或数组。通过下列片段可以快速实现这一点:

>>> document_vector = []
>>> doc_length = len(tokens)
>>> for key, value in kite_counts.most_common():
...     document_vector.append(value / doc_length)
>>> document_vector
[0.07207207207207207,
 0.06756756756756757,
 0.036036036036036036,
 ...,
 0.0045045045045045045]

对于上述列表或者向量,我们可以直接对它们进行数学运算。

提示 

我们可以通过多种方式加快对上述数据结构的处理[2]。现在我们只是基于基本要素进行处理,但很快我们就会想加快上面的步骤。

如果只处理一个元素,那么在数学上没什么意思。只有一篇文档对应一个向量是不够的,我们可以获取更多的文档,并为每篇文档创建其对应的向量。但是每个向量内部的值必须都要相对于某个在所有向量上的一致性结果进行计算(即所有文档上有个通用的东西,大家都要对它来计算)。如果要对这些向量进行计算,那么需要相对于一些一致的东西,在公共空间中表示一个位置。向量之间需要有相同的原点,在每个维度上都有相同的表示尺度(scale)或者“单位”。这个过程的第一步是计算归一化词项频率,而不是像在上一节中那样计算文档中的原始词频。第二步是将所有向量都转换到标准长度或维度上去。

此外,我们还希望每个文档向量同一维上的元素值代表同一个词。但我们可能会注意到,我们写给兽医的电子邮件中不会包含《战争与和平》(War &Peace)中的许多词。(也许会,谁知道呢?)但是,如果允许向量在不同的位置上都包含0,那么这也是可以的(事实上也是必要的)。我们会在每篇文档中找到独立的词,然后将这些词集合求并集后从中找到每个独立的词。词汇表中的这些词集合通常称为词库(lexicon),这与前面章节中所引用的概念相同,只是前面都考虑的是某个特定的语料库。下面我们看看比《战争与和平》更短的电影会是什么样子。我们去看看Harry,我们已经有了一篇“文档”,下面我们用更多的文档来扩充语料库:

>>> docs = ["The faster Harry got to the store, the faster and faster Harry
➥ would get home."]
>>> docs.append("Harry is hairy and faster than Jill.")
>>> docs.append("Jill is not as hairy as Harry.")

提示

如果我们不只是在计算机上敲出来这段程序,而是想一起玩转的话,那么可以从nlpia包导入这段程序:from nlpia.data.loaders import harry_docs as docs

首先,我们来看看这个包含3篇文档的语料库的词库:

>>> doc_tokens = []
>>> for doc in docs:
...     doc_tokens += [sorted(tokenizer.tokenize(doc.lower()))]
>>> len(doc_tokens[0])
17
>>> all_doc_tokens = sum(doc_tokens, [])
>>> len(all_doc_tokens)
33
>>> lexicon = sorted(set(all_doc_tokens))
>>> len(lexicon)
18
>>> lexicon
[',',
 '.',
 'and',
 'as',
 'faster',
 'get',
 'got',
 'hairy',
 'harry',
 'home',
 'is',
 'jill',
 'not',
 'store',
 'than',
 'the',
 'to',
 'would']

尽管有些文档并不包含词库中所有的18个词,但是上面3篇文档的每个文档向量都会包含18个值。每个词条都会被分配向量中的一个槽位(slot),对应的是它在词库中的位置。正如我们能想到的那样,向量中某些词条的频率会是0:

>>> from collections import OrderedDict
>>> zero_vector = OrderedDict((token, 0) for token in lexicon)
>>> zero_vector
OrderedDict([(',', 0),
             ('.', 0),
             ('and', 0),
             ('as', 0),
             ('faster', 0),
             ('get', 0),
             ('got', 0),
             ('hairy', 0),
             ('harry', 0),
             ('home', 0),
             ('is', 0),
             ('jill', 0),
             ('not', 0),
             ('store', 0),
             ('than', 0),
             ('the', 0),
             ('to', 0),
             ('would', 0)])

接下来可以对上述基本向量进行复制,更新每篇文档的向量值,然后将它们存储到数组中:

>>> import copy
>>> doc_vectors = []
>>> for doc in docs:
...     vec = copy.copy(zero_vector)   ⇽---  copy.copy()构建了完全独立的副本,即0向量的一个独立的实例,而非复用一个指针指向原始对象的内存位置,否则,就会在每次循环中用新值重写相同的zero_vector,从而导致每次循环都没有使用新的零向量
...     tokens = tokenizer.tokenize(doc.lower())
...     token_counts = Counter(tokens)
...     for key, value in token_counts.items():
...         vec[key] = value / len(lexicon)
...     doc_vectors.append(vec)

现在每篇文档对应一个向量,我们有3个向量。那接下来怎么办?我们能对它们做些什么?实际上,这里的文档词频向量能够做任意向量能做的所有有趣的事情,因此,接下来我们首先学习一些有关向量和向量空间的知识[3]。

向量空间

向量是线性代数或向量代数的主要组成部分。它是一个有序的数值列表,或者说这些数值是向量空间中的坐标。它描述了空间中的一个位置,或者它也可以用来确定空间中一个特定的方向和大小或距离。空间(space)是所有可能出现在这个空间中的向量的集合。因此,两个值组成的向量在二维向量空间中,而3个值组成的向量在三维向量空间中,以此类推。

一张作图纸或者图像中的像素网格都是很好的二维向量空间。我们可以看到这些坐标顺序的重要性。如果把作图纸上表示位置的x坐标和y坐标倒转,而不倒转所有的向量计算,那么线性代数问题的所有答案都会翻转。由于x坐标和y坐标互相正交,因此作图纸和图像是直线空间或者欧几里得空间的例子。我们在本章中讨论的向量都是直线空间,或者欧几里得空间。

地图或地球仪上的经纬度算什么呢?地图或地球仪绝对是一个二维向量空间,因为它是经度和纬度两个数值的有序列表。但是每个经纬度对都描述了一个近似球面、凹凸不平的表面(地球的表面)上的一个点。经纬度坐标不是精确正交的,所以经纬度构成的向量空间并不是直线空间。这意味着我们计算像二维经纬度向量一样的向量对或者非欧几里得空间下的向量对所表示的两点之间的距离或相似度时,必须十分小心。设想一下如何基于经纬度坐标计算波特兰和纽约之间的距离[4]。

图3-1给出了二维向量(5, 5)、(3, 2)和(−1, 1)的一种图示方法。向量的头部(箭头的尖)用于表示向量空间中的一个位置。因此,图中3个向量的头部对应了3组坐标。位置向量的尾部(有向线段的尾部)总是在坐标原点(0, 0)。

NLP:词中的数学

图3-1 二维向量

如果是三维向量空间应该怎么办?我们生活的三维物理世界中的位置和速度可以用三维向量的坐标xyz来表示。或者,由所有经度-纬度-高度三元组形成的曲面空间可以描述近地球表面的位置。

但是,我们不仅仅局限于三维空间。我们可以有5维、10维、5000维等各种维度的空间。线性代数对它们的处理方式都是一样的。随着维数的增加,我们可能需要更加强大的算力。大家将会遇到所谓的“维数灾难”[5]问题,但是我们会到最后一章(即第13章)再处理这个问题。

对于自然语言文档向量空间,向量空间的维数是整个语料库中出现的不同词的数量。对于TF(和后面的TF-IDF),有时我们会用一个大写字母K,称它为K维空间。上述在语料库中不同的词的数量也正好是语料库的词汇量的规模,因此在学术论文中,它通常被称为|V|。然后可以用这个K维空间中的一个K维向量来描述每篇文档。在前面3篇关于Harry和Jill的文档语料库中,K = 18。因为人类无法轻易地对三维以上的空间进行可视化,所以我们接下来把大部分的高维空间放在一边,先看一下二维空间,这样我们就能在当前正在阅读的平面上看到向量的可视化表示。因此,在图3-2中,我们给出了18维Harry和Jill文档向量空间的二维视图,此时K被简化为2。

NLP:词中的数学

图3-2 二维词项频率向量

K维向量和一般向量的工作方式是完全一样的,只是不太容易地对其进行可视化而已。既然现在已经有了每个文档的表示形式,并且知道它们共享公共空间,那么接下来可以对它们进行比较。我们可以通过向量相减,然后计算结果向量的大小来得到两个向量之间的欧几里得距离,也称为2范数距离。这是“乌鸦”从一个向量的顶点位置(头)到另一个向量的顶点位置飞行的(直线)距离。读者可以查看一下关于线性代数的附录C,了解为什么欧几里得距离对词频(词项频率)向量来说不是一个好方法。

如果两个向量的方向相似,它们就“相似”。它们可能具有相似的大小(长度),这意味着这两个词频(词项频率)向量所对应的文档长度基本相等。但是,当对文档中词的向量表示进行相似度估算时,我们是否会关心文档长度?恐怕不会。我们在对文档相似度进行估算时希望能够找到相同词的相似使用比例。准确估算相似度会让我们确信,两篇文档可能涉及相似的主题。

余弦相似度仅仅是两个向量夹角的余弦值,如图3-3所示,可以用欧几里得点积来计算:

NLP:词中的数学

余弦相似度的计算很高效,因为点积不需要任何对三角函数求值。此外,余弦相似度的取值范围十分便于处理大多数机器学习问题:−1到+1。

NLP:词中的数学

图3-3 二维向量的夹角

在Python中,可以使用

a.dot(b) == np.linalg.norm(a) * np.linalg.norm(b) / np.cos(theta)求解cos(theta)的关系,得到如下余弦相似度的计算公式:

NLP:词中的数学

或者可以采用纯Python(没有numpy)中的计算方法,如代码清单3-1所示。

代码清单3-1 Python中的余弦相似度计算

>>> import math
>>> def cosine_sim(vec1, vec2):
...     """ Let's convert our dictionaries to lists for easier matching."""
...     vec1 = [val for val in vec1.values()]
...     vec2 = [val for val in vec2.values()]
...
...     dot_prod = 0
...     for i, v in enumerate(vec1):
...         dot_prod += v * vec2[i]
...
...     mag_1 = math.sqrt(sum([x**2 for x in vec1]))
...     mag_2 = math.sqrt(sum([x**2 for x in vec2]))
...
...     return dot_prod / (mag_1 * mag_2)

所以,我们需要将两个向量中的元素成对相乘,然后再把这些乘积加起来,这样就可以得到两个向量的点积。再将得到的点积除以每个向量的模(大小或长度),向量的模等于向量的头部到尾部的欧几里得距离,也就是它的各元素平方和的平方根。上述归一化的点积(normalized dot product)的输出就像余弦函数一样取−1到1之间的值,它也是这两个向量夹角的余弦值。这个值等于短向量在长向量上的投影长度占长向量长度的比例,它给出的是两个向量指向同一方向的程度。

余弦相似度为1表示两个归一化向量完全相同,它们在所有维度上都指向完全相同的方向。此时,两个向量的长度或大小可能不一样,但是它们指向的方向相同。记住在计算上述余弦相似度时,两个向量的点积除以每个向量的模的计算可以在点积之前或之后进行。因此,归一化向量在计算点积时它们的长度都已经是1。余弦相似度的值越接近于1,两个向量之间的夹角就越小。对于余弦相似度接近于1的NLP文档向量,我们知道这些文档应该使用了比例相近的相似词。因此,那些表示向量彼此接近的文档很可能涉及的是同一主题。

余弦相似度为0表示两个向量之间没有共享任何分量。它们是正交的,在所有维度上都互相垂直。对于NLP中的词频向量,只有当两篇文档没有公共词时才会出现这种情况。因为这些文档使用完全不同的词,所以它们一定在讨论完全不同的东西。当然,这并不意味着它们一定就有不同的含义或主题,而只表明它们使用完全不同的词。

余弦相似度为−1表示两个向量是反相似(anti-similar)的,即完全相反,也就是两个向量指向完全相反的方向。对于简单的词频向量,甚至是归一化的词频(词项频率)向量(我们稍后将讨论),都不可能会发生这种情况。因为词的数目永远不会是负数,所以词频(词项频率)向量总是处于向量空间的同一象限中。没有词项频率向量可以偷偷进入其他向量尾部后面的象限。词项频率向量的分量不可能与另一个词项频率向量分量的符号相反,这是因为频率不可能是负数。

在本章中,对于自然语言文档的向量对,我们不会看到任何负的余弦相似度的值。但是在下一章中,我们会给出互相“对立”的词和主题的某个概念,这表现为文档、词和主题之间的余弦相似度小于零,甚至等于−1。

异性相吸 

上述计算余弦相似度的方法会带来一个有趣的结果。如果两个向量或文档都与第三个向量的余弦相似度为−1(即与第三个向量完全相反),那么它们一定完全相似,一定是完全相同的两个向量。但是,这两个向量所代表的文档可能并不完全相同。不但词的顺序可能会被打乱,而且如果它们使用相同词的比例相同,那么其中一篇文档可能比另一篇长得多。

后面,我们将针对更精确地对文档建模而构建文档向量。但是现在,我们已经很好地介绍了所需的工具。

本文摘自《自然语言处理实战》

NLP:词中的数学

本书是介绍自然语言处理(NLP)和深度学习的实战书。NLP已成为深度学习的核心应用领域,而深度学习是NLP研究和应用中的必要工具。本书分为3部分:第一部分介绍NLP基础,包括分词、TF-IDF向量化以及从词频向量到语义向量的转换;第二部分讲述深度学习,包含神经网络、词向量、卷积神经网络(CNN)、循环神经网络(RNN)、长短期记忆(LSTM)网络、序列到序列建模和注意力机制等基本的深度学习模型和方法;第三部分介绍实战方面的内容,包括信息提取、问答系统、人机对话等真实世界系统的模型构建、性能挑战以及应对方法。

本书面向中高级Python开发人员,兼具基础理论与编程实战,是现代NLP领域从业者的实用参考书。

展开阅读全文

页面更新:2024-03-19

标签:欧几里得   词频   语料   余弦   经纬度   可能会   向量   词条   坐标   长度   频率   位置   两个   数学   文档   科技   空间

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top