自然语言处理实战第二版(MEAP)(二)(3)

本文涉及的产品
NLP 自学习平台,3个模型定制额度 1个月
NLP自然语言处理_高级版,每接口累计50万次
NLP自然语言处理_基础版,每接口每天50万次
简介: 自然语言处理实战第二版(MEAP)(二)

自然语言处理实战第二版(MEAP)(二)(2)https://developer.aliyun.com/article/1517848

3.4.2 相关性排名

正如你之前看到的,你可以轻松比较两个向量并获得它们的相似性,但是你已经学到了,仅仅计算单词不如使用它们的 TF-IDF 值有效。因此,在每个文档向量中,你希望用单词的 TF-IDF 值(分数)替换每个单词的计数。现在你的向量将更全面地反映文档的意思或主题。

当你使用像 MetaGer.org、Duck.com 或 You.com 这样的搜索引擎时,10 多个搜索结果列表是从这些页面的 TF-IDF 向量中精心制作出来的。如果你想一想,一个算法能够给你几乎总是包含你正在寻找的重要信息的 10 个页面,这是相当了不起的。毕竟,搜索引擎可以从数十亿个网页中选择。这是怎么可能的?在幕后,所有搜索引擎都是通过计算查询的 TF-IDF 向量与其数据库中数十亿个网页的 TF-IDF 向量之间的相似度来开始的。这种与你的查询的相似度通常被称为相关性。以下是你如何通过相关性对任何文档进行排名。

>>> doc_tfidf_vectors = []
>>> for doc in docs:  # #1
...     vec = copy.copy(zero_vector)  # #2
...     tokens = [token.text for token in nlp(doc.lower())]
...     token_counts = Counter(tokens)
...
...     for token, count in token_counts.items():
...         docs_containing_key = 0
...         for d in docs:
...             if token in d:
...                 docs_containing_key += 1
...         tf = value / len(vocab)
...         if docs_containing_key:
...             idf = len(docs) / docs_containing_key
...         else:
...             idf = 0
...         vec[key] = tf * idf
...     doc_tfidf_vectors.append(vec)

有了这个设置,你在语料库中的每个文档都有一个 K 维向量表示。现在开始猎杀吧!或者说搜索,在你的情况下。从前一节中,你可能还记得我们如何定义向量之间的相似性。如果两个向量的余弦相似性高,则认为它们相似,因此如果它们最大化余弦相似性,你可以找到两个相似的向量靠近彼此。

现在你已经有了进行基于 TF-IDF 的基本搜索所需的一切。你可以将搜索查询本身视为一个文档,并因此获得其基于 TF-IDF 的向量表示。然后,最后一步是找到与查询具有最高余弦相似度的文档,并将它们作为搜索结果返回。

如果你拿出关于哈利的三个文档,并提出查询“到商店需要多长时间?”:

>>> query = "How long does it take to get to the store?"
>>> query_vec = copy.copy(zero_vector)  # #1
>>> tokens = [token.text for token in nlp(query.lower())]
>>> token_counts = Counter(tokens)
>>> for key, value in token_counts.items():
...     docs_containing_key = 0
...     for _doc in docs:
...       if key in _doc.lower():
...         docs_containing_key += 1
...     if docs_containing_key == 0:  # #1
...         continue
...     tf = value / len(tokens)
...     idf = len(docs) / docs_containing_key
...     query_vec[key] = tf * idf
>>> cosine_sim(query_vec, doc_tfidf_vectors[0])
0.5235048549676834
>>> cosine_sim(query_vec, doc_tfidf_vectors[1])
0.0
>>> cosine_sim(query_vec, doc_tfidf_vectors[2])
0.0

你可以放心地说文档 0 对你的查询最具相关性!有了这个,你可以在任何语料库中找到相关的文档,无论是维基百科的文章、古登堡计划的书籍,还是 ActivityPub(Mastodon)上的 toots。谷歌小心了!

实际上,谷歌的搜索引擎不会受到我们的竞争威胁。你必须对每个查询的 TF-IDF 向量进行“索引扫描”。这是一个 (O(N)) 算法。大多数搜索引擎可以在常数时间 ((O(1))) 内响应,因为它们使用了一个倒排索引。^([20]) 你不会在这里实现一个能够在常数时间内找到这些匹配项的索引,但如果你感兴趣,你可能会喜欢探索 Whoosh ^([21]) 包中的最先进的 Python 实现及其源代码。^([22])

提示

在前述代码中,你删除了在管道词汇表中找不到的键,以避免除零错误。但更好的方法是对每个 IDF 计算的分母加 1,以确保没有分母为零。实际上,这种方法非常常见,有一个名字叫做加法平滑或"Laplace 平滑"^([23]) — 通常会改善基于 TF-IDF 关键词搜索的搜索结果。

3.4.3 另一种向量化器

现在这是很多代码,但这些早已自动化。你在本章开头使用的 sklearn 包也有一个用于 TF-IDF 的工具。就像你之前看到的 CountVectorizer 一样,它进行标记化,省略标点,并一次性计算 tf-idf 分数。

下面是如何使用 sklearn 构建 TF-IDF 矩阵的方法。语法几乎与 CountVectorizer 完全相同。

列表 3.6 使用 Scikit-Learn 计算 TF-IDF 矩阵
>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> corpus = docs
>>> vectorizer = TfidfVectorizer(min_df=1) # #1
>>> vectorizer = vectorizer.fit(corpus)  # #2
>>> vectors = vectorizer.transform(corpus)  # #3
>>> print(vectors.todense().round(2))  # #4
[[0.16 0.   0.48 0.21 0.21 0.   0.25 0.21 ... 0.21 0.   0.64 0.21 0.21]
 [0.37 0.   0.37 0.   0.   0.37 0.29 0.   ... 0.   0.49 0.   0.   0.  ]
 [0.   0.75 0.   0.   0.   0.29 0.22 0.   ... 0.   0.   0.   0.   0.  ]]

使用 Scikit-Learn,只需四行代码,你就创建了一个矩阵,其中包含你的三个文档和词汇表中每个词的逆文档频率。它与之前从 CountVectorizer 得到的矩阵非常相似,只是这次它包含了词汇表中每个术语、标记或单词的 TF-IDF,构成了矩阵的列。在大型文本中,这种或其他一些预优化的 TF-IDF 模型将为你节省大量工作。

3.4.4 替代方案

几十年来,TF-IDF 矩阵(术语-文档矩阵)一直是信息检索(搜索)的主要方法。因此,研究人员和公司花费了大量时间来优化 IDF 部分,以尝试改善搜索结果的相关性。3.1 列出了一些你可以规范化和平滑化术语频率权重的方法。

表 3.1 替代 TF-IDF 规范化方法(Molino 2017)^([24])
方案 定义


TD-IDF


TF-ICF


Okapi BM25


ATC


LTU


MI


PosMI


T-Test


卡方检验 从分布到语义相似性 (www.era.lib.ed.ac.uk/bitstream/handle/1842/563/IP030023.pdf#subsection.4.3.5),作者詹姆斯·理查德·柯兰
Lin98a


Lin98b


Gref94


搜索引擎(信息检索系统)在语料库中匹配查询和文档之间的关键词(术语)。如果您正在构建一个搜索引擎,并希望提供可能与用户所寻找内容匹配的文档,您应该花一些时间研究皮耶罗·莫利诺在图 3.7 中描述的替代方案。

用于对查询结果进行排名的另一种替代方法是 Okapi BM25,或者其最新的变体 BM25F。

3.4.5 Okapi BM25

伦敦城市大学的聪明人提出了一种更好的方法来对搜索结果进行排名。他们不仅仅计算 TF-IDF 余弦相似度,还对相似度进行归一化和平滑处理。他们还忽略了查询文档中的重复术语,有效地将查询向量的术语频率剪切为 1。余弦相似度的点积不是由 TF-IDF 向量的规范化(文档和查询中的术语数)来规范化的,而是由文档长度本身的非线性函数来规范化的。

q_idf * dot(q_tf, d_tf[i]) * 1.5 / (dot(q_tf, d_tf[i]) + .25 + .75 * d_num_words[i] / d_num_words.mean()))

通过选择使用户获得最相关结果的加权方案,您可以优化您的管道。但是,如果您的语料库不太大,您可能会考虑进一步前进,以获得更有用和准确的单词和文档含义的表示。

3.5 使用 TF-IDF 为您的机器人

在本章中,您学习了如何使用 TF-IDF 来表示自然语言文档,并找到它们之间的相似性,并执行关键字搜索。但是,如果您想构建一个聊天机器人,您该如何利用这些功能来制作您的第一个智能助手?

实际上,许多聊天机器人严重依赖搜索引擎。一些聊天机器人使用他们的搜索引擎作为生成响应的唯一算法。您只需要额外采取一步,将您的简单搜索索引(TF-IDF)转换为聊天机器人即可。为了使本书尽可能实用,每一章都将向您展示如何使用您在该章中掌握的技能使您的机器人更智能。

在本章中,您将使您的聊天机器人回答数据科学问题。诀窍很简单:您将您的训练数据存储为问题和相应响应的对。然后,您可以使用 TF-IDF 搜索与用户输入文本最相似的问题。而不是返回数据库中最相似的语句,您返回与该语句相关联的响应。然后,您就可以聊天了!

让我们一步步来。首先,让我们加载我们的数据。你将使用 Hobson 的学生在过去几年中问他的数据科学问题的语料库。它们位于 qary 存储库中:

>>> DS_FAQ_URL = ('https://gitlab.com/tangibleai/qary/-/raw/main/'
...     'src/qary/data/faq/faq-python-data-science-cleaned.csv')
>>> qa_dataset = pd.read_csv(DS_FAQ_URL)

接下来,让我们为数据集中的问题创建 TF-IDF 向量。你将使用前一节中看到的 Scikit-Learn TfidfVectorizer 类。

>>> vectorizer = TfidfVectorizer()
>>> vectorizer.fit(df['question'])
>>> tfidfvectors_sparse = vectorizer.transform(df['question'])  # #1
>>> tfidfvectors = tfidfvectors_sparse.todense()  # #2

现在我们准备实现问答功能本身。你的机器人将使用你在数据集上训练的相同向量化器来回答用户的问题,并找到最相似的问题。

>>> def bot_reply(question):
...    question_vector = vectorizer.transform([question]).todense()
...    idx = question_vector.dot(tfidfvectors.T).argmax() # #1
...
...    print(
...        f"Your question:\n {question}\n\n"
...        f"Most similar FAQ question:\n {df['question'][idx]}\n\n"
...        f"Answer to that FAQ question:\n {df['answer'][idx]}\n\n"
...    )

你的第一个问答聊天机器人已经准备好了!让我们问它第一个问题:

>>> bot_reply("What's overfitting a model?")
Your question:
  What's overfitting a model?
Most similar FAQ question:
  What is overfitting?
Answer to that FAQ question:
  When your test set accuracy is significantly lower than your training set accuracy?

尝试与它玩耍,问它更多的问题,比如:- 什么是高斯分布?- 谁提出了感知器算法?

但你会很快意识到,你的聊天机器人经常失败 - 不仅仅是因为你训练它的数据集很小。

例如,让我们尝试以下问题:

>>> bot_reply('How do I decrease overfitting for Logistic Regression?')
Your question:
  How do I decrease overfitting for Logistic Regression?
Most similar FAQ question:
  How to decrease overfitting in boosting models?
Answer to that FAQ question:
  What are some techniques to reduce overfitting in general? Will they work with boosting models?

如果你仔细看了数据集,你可能会发现它实际上有一个关于减少提升模型过拟合的答案。然而,我们的向量化器只是有点太字面了 - 当它在错误的问题中看到“减少”一词时,这导致了对错误问题的点积更高。在下一章中,我们将看到如何通过查看含义而不是特定单词来克服这一挑战。

3.6 接下来要做什么

现在你可以将自然语言文本转换为数字了,你可以开始操作它们并计算它们。拿着牢牢的数字,在下一章中,你将对这些数字进行细化,试图代表自然语言文本的含义主题,而不仅仅是它的词语。在随后的章节中,我们将向你展示如何实现一个语义搜索引擎,该引擎找到与你查询中的单词“意思”相似的文档,而不仅仅是使用你查询中的这些确切单词的文档。语义搜索比 TF-IDF 加权和词干提取和词形还原能够实现的任何东西都要好得多。最先进的搜索引擎结合了 TF-IDF 向量和语义嵌入向量,以实现比传统搜索更高的准确性。

资金充裕的 OpenSearch 项目,一个 ElasticSearch 的分支,现在正在引领搜索创新之路。[25] ElasticSearch 在 2021 年开始封锁他们的技术花园。Google、Bing 和其他网络搜索引擎之所以不使用语义搜索方法,是因为它们的语料库太大了。语义词和主题向量无法扩展到数十亿个文档,但数百万个文档却没有问题。一些创业公司,比如 You.com,正在学习如何使用开源技术实现语义搜索和网络规模的对话式搜索(聊天)。

因此,你只需要最基本的 TF-IDF 向量来供给你的管道,以获得语义搜索、文档分类、对话系统以及我们在第一章提到的大多数其他应用的最先进性能。TF-IDF 只是你的管道中的第一阶段,是你从文本中提取的一组基本特征。在下一章中,你将从你的 TF-IDF 向量计算主题向量。主题向量甚至是比这些经过精心归一化和平滑处理的 TF-IDF 向量更好地表示文档的含义。当我们在第六章转向 Word2vec 单词向量和后续章节中的单词和文档含义的深度学习嵌入时,情况只会变得更好。

3.7 自测

  1. CountVectorizer.transform() 创建的计数向量和 Python collections.Counter 对象列表之间有什么区别?你能将它们转换成相同的 DataFrame 对象吗?
  2. 你能在一个大型语料库(超过 100 万个文档)和一个庞大的词汇表(超过 100 万个标记)上使用 TFIDFVectorizer 吗?你预计会遇到什么问题?
  3. 想象一个语料库或任务的例子,在这里术语频率(TF)会比 TF-IDF 表现更好。
  4. 我们提到过,字符 n-gram 的包可以用于语言识别任务。一个使用字符 n-gram 区分一种语言和另一种语言的算法会如何运作?
  5. 你在本章中看到的 TF-IDF 的限制或缺点是什么?你能想出未提及的其他缺点吗?
  6. 你会如何利用 TF-IDF 作为基础来改进今天大多数搜索引擎的工作方式?

3.8 总结

  • 任何具有毫秒响应时间的 Web 规模搜索引擎在引擎盖下都隐藏着 TF-IDF 术语文档矩阵的能力。
  • 希波夫定律可以帮助你预测各种事物的频率,包括单词、字符和人物。
  • 术语频率必须按其逆文档频率加权,以确保最重要、最有意义的词语得到应有的重视。
  • 词袋 / n-gram 词袋和 TF-IDF 是用实数向量表示自然语言文档的最基本算法。
  • 高维向量对之间的欧几里德距离和相似性并不能充分表示它们在大多数自然语言处理应用中的相似性。
  • 余弦距离,向量之间的“重叠”量,可以通过将归一化向量的元素相乘并将这些乘积相加来有效地计算。
  • 余弦距离是大多数自然语言向量表示的首选相似性评分。

[1] StackOverflow 讨论是否依赖于此功能(stackoverflow.com/questions/39980323/are-dictionaries-ordered-in-python-3-6/39980744#39980744

[2] Scikit-Learn 文档(scikit-learn.org/)。

[3] 如果你想要更多关于线性代数和向量的细节,请查看附录 C。

[4] “向量化和并行化” by WZB.eu (datascience.blog.wzb.eu/2018/02/02/vectorization-and-parallelization-in-python-with-numpy-and-pandas/)

[5] “动荡时代的知识与社会” (wzb.eu/en/node/60041)

[6] 你需要使用类似 GeoPy(geopy.readthedocs.io)的包来确保数学正确。

[7] 维度诅咒是,随着维度的增加,向量在欧几里得距离上会以指数方式远离彼此。许多简单操作在超过 10 或 20 个维度时变得不切实际,比如基于它们与“查询”或“参考”向量的距离对大量向量列表进行排序(近似最近邻搜索)。要深入了解,请查看维基百科的“维度诅咒”文章 (en.wikipedia.org/wiki/Curse_of_dimensionality)。

[8] 这些视频展示了如何使用 SpaCy 和 numpy 为单词创建向量,然后计算它们之间的余弦相似度 (www.dropbox.com/sh/3p2tt55pqsisy7l/AAB4vwH4hV3S9pUO0n4kTZfGa?dl=0)

[9] 如果这个参考对你来说陌生,请查看 H.P.洛夫克拉夫特的故事克苏鲁的呼唤www.hplovecraft.com/writings/texts/fiction/cc.aspx

[10] 于 2021 年 7 月 9 日从这里检索:en.wikipedia.org/wiki/Machine_learning

[11] 非营利性搜索引擎 MetaGer 严肃对待隐私、诚实和道德,不像你已经熟悉的顶级搜索引擎 (metager.org/)

[12] 维基百科 ROT13 文章 (en.wikipedia.org/wiki/ROT13)

[13] Zbwedicon 关于 Python 之禅的 YouTube 视频 (www.youtube.com/watch?v=i6G6dmVJy74)

[14] 你可以安装和导入 PyDanny 的 that 包,以便笑笑 Python 的反模式 (pypi.org/project/that)

[15] 查看标题为"Zipf 定律之外还有更多"的网页 (www.nature.com/articles/srep00812)

[16] 使用 Pandas 从维基百科下载的人口数据。查看 GitHub 上的 nlpia.book.examples 代码(gitlab.com/tangibleai/nlpia2/-/blob/main/src/nlpia2/ch03/ch03_zipf.py

[17] 完整列表请参见 icame.uib.no/brown/bcm-los.html

[18] Gerard Salton 和 Chris Buckley 首次在他们的论文《信息检索中的术语加权方法》中展示了对于信息检索的对数缩放的有用性(ecommons.cornell.edu/bitstream/handle/1813/6721/87-881.pdf)。

[19] 后面我们会向您展示如何在计算所有 TF-IDF 值后使用此对数缩放来归一化 TF-IDF 向量。

[20] 参见名为“倒排索引 - 维基百科”的网页(en.wikipedia.org/wiki/Inverted_index)。

[21] 参见名为“Whoosh : PyPI”的网页(pypi.python.org/pypi/Whoosh)。

[22] 参见名为“GitHub - Mplsbeb/whoosh: A fast pure-Python search engine”的网页(github.com/Mplsbeb/whoosh)。

[23] 参见名为“加法平滑 - 维基百科”的网页(en.wikipedia.org/wiki/Additive_smoothing)。

[24] Word Embeddings Past, Present and Future,Piero Molino,于 AI with the Best 2017

[25] “OpenSearch 中语义搜索的 ABC” ,Milind Shyani,(opensearch.org/blog/semantic-science-benchmarks/

第四章:在词频统计中找到含义(语义分析)

本章内容包括

  • 分析语义(含义)以创建主题向量
  • 使用主题向量之间的语义相似性进行语义搜索
  • 可伸缩的语义分析和大型语料库的语义搜索
  • 在你的 NLP 管道中使用语义组件(主题)作为特征
  • 导航高维向量空间

你已经学会了很多自然语言处理的技巧。但现在可能是你第一次能够做一点"魔术"。这是我们第一次讨论机器能够理解单词含义的时候。

第三章的 TF-IDF 向量(词频 - 逆文档频率向量)帮助你估计了文本块中单词的重要性。你使用 TF-IDF 向量和矩阵告诉你每个单词对文档集合中一小部分文本的整体含义的重要性。这些 TF-IDF"重要性"分数不仅适用于单词,还适用于短序列的单词,n-grams。如果你知道确切的单词或n-grams,它们对于搜索文本非常有效。但它们也有一定的局限性。通常,你需要一种不仅仅考虑单词计数,还考虑它们含义的表示。

研究人员发现了几种使用词语与其他词语的共现来表示词语含义的方法。在本章中,你将了解其中一些方法,比如潜在语义分析(LSA)和潜在狄利克雷分配。这些方法创建了用于表示词语和文档的语义主题向量。你将使用 TF-IDF 向量的加权频率分数,或者上一章学到的词袋(BOW)向量来创建它们。这些分数以及它们之间的相关性,将帮助你计算构成你的主题向量维度的主题"分数"。

主题向量将帮助你完成许多有趣的事情。它们使得根据其含义进行文档搜索成为可能 —— 语义搜索。大多数情况下,语义搜索返回的搜索结果要比关键词搜索好得多。有时,即使用户无法想到正确的查询词,语义搜索也会返回用户正要搜索的文档。

语义向量还可以用于识别最能代表语句、文档或语料库(文档集合)主题的单词和n-grams。有了这些单词及其相对重要性的向量,你可以为文档提供最有意义的单词 —— 一组总结其含义的关键词。

最后,你将能够比较任意两个语句或文档,并判断它们在含义上有多"接近"。

提示

“主题”、“语义”和“含义”这些术语在自然语言处理(NLP)中有着相似的意义,并且在讨论时通常可以互换使用。在本章中,您将学习如何构建一个 NLP 流水线,它可以自行找出这种同义词,甚至能够找出“搞明白”这个短语和“计算”这个词的含义相似之处。机器只能“计算”含义,而不能“搞明白”含义。

很快您将会发现,构成主题向量维度的单词的线性组合是相当强大的含义表示。

4.1 从单词计数到主题分数

您知道如何计算单词的频率,并在 TF-IDF 向量或矩阵中评分单词的重要性。但这还不够。让我们来看看这可能会产生哪些问题,以及如何处理文本的含义,而不仅仅是单个术语频率。

4.1.1 TF-IDF 向量和词形还原的局限性

TF-IDF 向量根据文档中单词的确切拼写进行计数。因此,如果文本以不同的方式表达相同的含义,它们的 TF-IDF 向量表示将完全不同,即使它们的拼写不同或使用不同的词汇。这会混淆搜索引擎和依赖于标记计数的文档相似性比较。

在第二章中,您对单词的词尾进行了归一化处理,以便将只在最后几个字符上有所不同的单词收集到一个单一的标记下。您使用了标准化方法,如词干提取和词形还原,来创建拼写相似、意思通常也相似的小型单词集合。您为这些单词的每一个小集合进行了标记,标记为它们的词元或词干,然后您处理了这些新标记,而不是原始单词。

这种词形还原方法将拼写相似的单词放在了一起进行分析,但并不一定是含义相似的单词。而且,它确实未能将大多数同义词配对起来。同义词通常在很多方面都不同,不仅仅是词形还原和词干提取处理的词尾。更糟糕的是,词形还原和词干提取有时会错误地将反义词(含义相反的单词)归类在一起。

结果是,两个讨论相同事物但使用不同词汇的文本片段在您的词形还原的 TF-IDF 向量空间模型中将不会“接近”彼此。有时,即使两个词形还原的 TF-IDF 向量彼此接近,它们的含义也完全不相似。即使是第三章中的最新的 TF-IDF 相似度评分,如 Okapi BM25 或余弦相似度,也无法连接这些同义词或将这些反义词分开。拼写不同的同义词产生的 TF-IDF 向量在向量空间中并不接近。

例如,在NLPIA这一章的 TF-IDF 向量,也就是你现在正在阅读的这一章,可能与关于潜在语义索引的大学教科书中的意思相去甚远。但这正是这一章所讨论的,只是我们在这一章中使用现代和口语化的术语。教授和研究人员在他们的教科书和讲座中使用更一致,更严格的语言。另外,教授们十年前使用的术语可能随着过去几年的快速进展而发生了变化。例如,像"潜在语义 索引"这样的术语比研究人员现在使用的"潜在语义分析"这个术语更受欢迎。^([3])

因此,具有相似含义的不同单词对 TF-IDF 造成问题。但是,看起来相似但含义完全不同的词也是如此。即使是由英语教授撰写的正式英语文本也无法避免大多数英语单词具有多重含义的事实,这对包括机器学习者在内的任何新学习者来说都是一个挑战。这种具有多重含义的单词的概念称为多义性

以下是一些多义词可能影响单词或语句语义的方式。

  • 同音异义词 — 拼写和发音相同,但含义不同的词(例如:乐队正在演奏老披头士的歌曲。她的发带非常漂亮。
  • 同形异义词 — 拼写相同但发音和含义不同的词。(例如:我反对这个决定。我不认识这个物体。
  • 双关语 — 在同一句子中同时使用一个词的两个含义(例如:皮克威克先生拿起了他的帽子和他的离开。

你可以看到所有这些现象会降低 TF-IDF 的性能,因为使具有相似但含义不同的单词的句子的 TF-IDF 向量更相似于彼此,而不应该是这样。为了解决这些挑战,我们需要更强大的工具。

话题向量

当你对 TF-IDF 向量进行数学运算,比如加法和减法时,这些和差只告诉你组合或差异化的向量所代表的文档中单词使用的频率。这种数学并不告诉你这些词背后的"含义"。你可以通过将 TF-IDF 矩阵乘以自身来计算单词与单词的 TF-IDF 向量(单词共现或相关向量)。但是用这些稀疏的,高维的向量进行"向量推理"并不奏效。当你将这些向量相加或相减时,它们并不能很好地代表一个现有的概念或单词或主题。

所以你需要一种方法来从单词统计中提取一些额外的信息和意义。你需要更好地估计文档中单词的"意义"。你需要知道在特定文档中那组词的含义是什么。你希望用一个类似于 TF-IDF 向量的向量来表示那个意义,只是更紧凑更有意义。

本质上,创建这些新向量时,您将定义一个新的空间。当您用 TF-IDF 或词袋向量表示单词和文档时,您正在一个由文档中出现的单词或术语定义的空间中操作。每个术语都有一个维度 - 这就是为什么您很容易达到数千个维度。每个术语与每个其他术语都是"正交"的 - 当您将表示一个单词的向量与表示另一个单词的向量相乘时,即使这些单词是同义词,您总是得到一个零。

主题建模的过程是找到一个维度较少的空间,使语义上相近的单词对齐到类似的维度。我们将这些维度称为主题,新空间中的向量称为主题向量。您可以拥有任意数量的主题。您的主题空间可以只有一个维度,也可以有数千个维度。

您可以像处理任何其他向量一样添加和减去您在本章中将计算的主题向量。只不过这一次,和差的含义比 TF-IDF 向量时更重要。主题向量之间的距离或相似度对于诸如查找与相似主题相关的文档或语义搜索等事情非常有用。

当您将您的向量转换到新空间时,您将为语料库中的每个文档有一个文档-主题向量。您的词汇表中每个单词都将有一个词-主题向量。因此,您只需将其所有词-主题向量相加,就可以计算任何新文档的主题向量。

创造出单词和句子语义(含义)的数值表示可能会有些棘手。这对于"模糊"语言如英语来说尤其如此,因为英语有多种方言,对相同单词有许多不同的解释。

考虑到这些挑战,您能想象如何将具有一百万维度(术语)的 TF-IDF 向量压缩为具有 10 或 100 维度(主题)的向量吗?这就像确定正确的基本颜色混合以尝试复制您公寓中的油漆颜色,以便您可以覆盖那些墙上的钉孔。

您需要找到那些在一个主题中“属于”一起的单词维度,并将它们的 TF-IDF 值相加,以创建一个新的数字来表示文档中该主题的数量。您甚至可以根据它们对主题的重要性对它们进行加权,以及您希望每个单词对"混合"的贡献有多少。您甚至可以为减少文本与该主题相关的可能性的单词添加负权重。

4.1.3 思想实验

让我们进行一个思想实验。假设您有某个特定文档的一些 TF-IDF 向量,并且您希望将其转换为一个主题向量。您可以考虑每个单词对您的主题的贡献。

假设你正在处理有关纽约市中央公园的宠物的一些句子(NYC)。让我们创建三个主题:一个关于宠物,一个关于动物,另一个关于城市。将这些主题称为“petness”、“animalness”和“cityness”。因此,关于宠物的“petness”主题将显著评分像“猫”和“狗”这样的词汇,但可能忽略像“NYC”和“苹果”这样的词汇。关于城市的“cityness”主题将忽略像“猫”和“狗”这样的词汇,但可能会对“苹果”稍微加权,仅仅因为与“大苹果”有关联。

如果你像这样“训练”你的主题模型,而不使用计算机,只使用你的常识,你可能会得出类似于清单 4.1 中的一些权重。

清单 4.1 你的主题的示例权重
>>> import numpy as np
>>> topic = {}
>>> tfidf = dict(list(zip('cat dog apple lion NYC love'.split(),
...     np.random.rand(6))))  # #1
>>> topic['petness'] = (.3 * tfidf['cat'] +\
...                     .3 * tfidf['dog'] +\
...                      0 * tfidf['apple'] +\
...                      0 * tfidf['lion'] -\
...                     .2 * tfidf['NYC'] +\
...                     .2 * tfidf['love'])  # #2
>>> topic['animalness']  = (.1 * tfidf['cat']  +\
...                         .1 * tfidf['dog'] -\
...                         .1 * tfidf['apple'] +\
...                         .5 * tfidf['lion'] +\
...                         .1 * tfidf['NYC'] -\
...                         .1 * tfidf['love'])
>>> topic['cityness']    = ( 0 * tfidf['cat']  -\
...                         .1 * tfidf['dog'] +\
...                         .2 * tfidf['apple'] -\
...                         .1 * tfidf['lion'] +\
...                         .5 * tfidf['NYC'] +\
...                         .1 * tfidf['love'])

在这个思想实验中,我们将可能是指示您的每个主题的单词频率相加起来。我们根据单词与主题相关的可能性加权单词频率(TF-IDF 值)。请注意,这些权重也可能是负值,因为某种意义上可能谈论与您的主题相反的内容的单词。

请注意,这不是一个真正的算法或示例实现,只是一个思想实验。你只是试图弄清楚如何教机器像你一样思考。你任意选择将你的单词和文档分解为只有三个主题(“petness”、“animalness”和“cityness”)。并且你的词汇是有限的,只有六个单词。

下一步是思考一个人可能如何在数学上决定哪些主题和单词是相关的,以及这些连接应该具有什么权重。一旦你决定了三个要建模的主题,你就必须确定为这些主题中的每个单词分配多少权重。你按比例混合单词以使你的主题“颜色混合”。主题建模转换(颜色混合配方)是一个 3 x 6 的比例(权重)矩阵,将三个主题与六个单词相连。你将该矩阵乘以一个想象中的 6 x 1 的 TF-IDF 向量,以获得该文档的 3 x 1 主题向量。

你做出了判断,认为术语“猫”和“狗”应该对“petness”主题具有类似的贡献(权重为 0.3)。因此,用于你的 TF-IDF 到主题转换的矩阵左上角的两个值都是 0.3。你能想象出可能使用软件“计算”这些比例的方法吗?记住,你有一堆计算机可以阅读,标记和计算标记的文档。你可以为尽可能多的文档制作 TF-IDF 向量。继续思考在阅读时如何使用这些计数来计算单词的主题权重。

你决定术语“NYC”在“petness”主题中应具有负权重。在某种意义上,城市名称,以及一般的专有名称,缩写和首字母缩写,与有关宠物的词汇几乎没有共同之处。思考一下单词“共同之处”在词汇中的含义。TF-IDF 矩阵中是否有表示单词共同含义的内容?

注意 “city” 这个主题向量中有少量的 “apple” 一词。这可能是因为你是手动进行的,而我们人类知道 “NYC” 和 “Big Apple” 经常是同义词。我们的语义分析算法有望能够根据 “apple” 和 “NYC” 在相同文档中出现的频率来计算出它们之间的同义关系。

在阅读清单 4.1 中的加权和之后,试着猜猜我们是如何得出这三个主题和六个单词的权重的。你脑海中可能有一个不同的"语料库",与我们在头脑中使用的不同。所以你可能对这些单词的"适当"权重有不同的看法。你会如何改变它们?你可以用什么客观的标准来衡量这些比例(权重)?我们将在下一节回答这个问题。

注意

我们选择了一种有符号的词权重来生成主题向量。这样可以使用负权重来表示与主题相反的词。因为你是手工进行的,我们选择使用易于计算的 L¹-norm (即向量维度的绝对值之和等于 1)来对你的主题向量进行归一化。不过,在本章稍后使用的真正的潜在语义分析(LSA)算法则通过更有用的 L²-norm 对主题向量进行归一化。我们将在本章后面介绍不同的范数和距离。

在阅读这些向量时,你可能已经意识到单词和主题之间的关系是可以"翻转"的。一个 3x6 的三个主题向量矩阵可以通过转置来产生你的词汇表中每个单词的主题权重。这些权重向量将成为你六个单词的词向量:

>>> word_vector = {}
>>> word_vector['cat']  =  .3*topic['petness'] +\
...                        .1*topic['animalness'] +\
...                         0*topic['cityness']
>>> word_vector['dog']  =  .3*topic['petness'] +\
...                        .1*topic['animalness'] -\
...                        .1*topic['cityness']
>>> word_vector['apple']=   0*topic['petness'] -\
...                        .1*topic['animalness'] +\
...                        .2*topic['cityness']
>>> word_vector['lion'] =   0*topic['petness'] +\
...                        .5*topic['animalness'] -\
...                        .1*topic['cityness']
>>> word_vector['NYC']  = -.2*topic['petness'] +\
...                        .1*topic['animalness'] +\
...                        .5*topic['cityness']
>>> word_vector['love'] =  .2*topic['petness'] -\
...                        .1*topic['animalness'] +\
...                        .1*topic['cityness']

这六个单词主题向量在图 4.1 中显示,每个单词对应一个向量,表示你的六个词的含义。

图 4.1. 关于宠物和纽约市的六个单词的思想实验的 3D 向量


之前,每个主题的向量都带有每个单词的权重,给出了表示三个主题中单词的线性组合的 6-D 向量。现在,你手工设计了一种通过主题来表示文档的方法。如果你只计算这些六个单词出现的次数,并将它们乘以相应的权重,就可以得到任何文档的 3D 主题向量。3D 向量非常有趣,因为人们可以很容易地进行可视化。你可以将它们绘制出来,并以图形形式分享关于你的语料库或特定文档的见解。

3D 向量(或任何低维向量空间)对于机器学习分类问题也非常有用。算法可以通过平面(或超平面)在向量空间中划分不同的类别。

你的语料库中的文档可能会使用更多的词,但是这个特定的主题向量模型只会受到这六个词的使用的影响。只要你的模型只需要根据三个不同的维度或主题来区分文档,你的词汇表可以按你的意愿不断增长。在这个思维实验中,你将六个维度(TF-IDF 规范化频率)压缩为三个维度(主题)。

这种主观的、劳动密集型的语义分析方法依赖于人类的直觉和常识来将文档分解成主题。人类的常识很难编码进算法中。^([4])显然,这种方法不能用于机器学习流程。而且在涉及更多主题和单词时,它的可扩展性也不强。

所以,让我们自动化这个手动的过程。让我们使用一种算法来为我们选择主题权重,而不依赖于常识。

如果你仔细思考一下,这些加权和实际上就是点积。而三个点积(加权和)就是矩阵乘法,或者内积。你需要用一个 TF-IDF 向量(文档中每个单词的值)乘以一个 3 x n 权重矩阵,其中 n 是词汇表中词项的数量,这样的乘法的输出就是该文档的新的 3 x 1 主题向量。你所做的就是将一个向量从一个向量空间(TF-IDFs)转换到另一个低维向量空间(主题向量)。你的算法应该创建一个 n x m 词项-主题矩阵,你可以用该矩阵乘以一个文档中的单词频率向量,以获得该文档的新的主题向量。

4.1.4 评分主题的算法

你仍然需要一种算法来确定这些主题向量,或者从你已经拥有的向量(如 TF-IDF 或词袋向量)中推导出它们。机器无法分辨哪些单词属于一起,或者它们代表着什么,不是吗?20 世纪的英国语言学家 J. R. Firth 研究了你可以估计一个词或词素代表的方式。在 1957 年,他给了你一个关于如何计算词的主题的线索。Firth 写道:

词的本性由它所携带的语境所决定。

— J. R. Firth

1957

那么如何确定一个词的 “公司” 呢?嗯,最直接的方法是在同一文档中统计共现次数。而你在第三章的 BOW 和 TF-IDF 向量中正好拥有所需的内容。这种 “计算共现次数” 的方法导致了开发出一些算法来创建向量来表示文档或句子中单词使用的统计信息。

在接下来的几节中,你将看到两种用于创建这些主题向量的算法。第一种,潜在语义分析(LSA),应用于你的 TF-IDF 矩阵以将单词聚合到主题中。它也适用于词袋向量,但 TF-IDF 向量的效果略好一些。LSA 优化这些主题以保持主题维度的多样性;当你使用这些新主题而不是原始单词时,仍然能捕捉到文档的大部分含义(语义)。你的模型所需的主题数量远远少于 TF-IDF 向量词汇表中的单词数量,因此 LSA 通常被称为一种维度缩减技术。LSA 减少了你需要捕捉文档含义的维度数量。^([6])

我们将要介绍的另一种算法被称为潜在狄利克雷分配,通常缩写为 LDA。因为在本书中我们使用 LDA 来表示潜在判别分析分类器,所以我们将潜在狄利克雷分配简称为 LDiA。

LDiA 将 LSA 的数学带入了不同的方向。它使用非线性统计算法将单词分组在一起。因此,通常比 LSA 之类的线性方法需要更长的训练时间。这使得 LDiA 在许多实际应用中不太实用,并且它很少是你尝试的第一种方法。尽管如此,它创建的主题的统计数据有时更接近人们对单词和主题的直觉。因此,LDiA 的主题通常更容易向你的老板解释。它还更适用于一些单文档问题,如文档摘要。

对于大多数分类或回归问题,通常最好使用 LSA。因此,我们首先解释 LSA 及其基础的 SVD 线性代数。

自然语言处理实战第二版(MEAP)(二)(4)https://developer.aliyun.com/article/1517855

相关文章
|
6天前
|
机器学习/深度学习 数据采集 人工智能
Python 高级实战:基于自然语言处理的情感分析系统
**摘要:** 本文介绍了基于Python的情感分析系统,涵盖了从数据准备到模型构建的全过程。首先,讲解了如何安装Python及必需的NLP库,如nltk、sklearn、pandas和matplotlib。接着,通过抓取IMDb电影评论数据并进行预处理,构建情感分析模型。文中使用了VADER库进行基本的情感分类,并展示了如何使用`LogisticRegression`构建机器学习模型以提高分析精度。最后,提到了如何将模型部署为实时Web服务。本文旨在帮助读者提升在NLP和情感分析领域的实践技能。
17 0
|
19天前
|
机器学习/深度学习 自然语言处理 PyTorch
【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
【从零开始学习深度学习】48.Pytorch_NLP实战案例:如何使用预训练的词向量模型求近义词和类比词
|
20天前
|
机器学习/深度学习 人工智能 自然语言处理
Python自然语言处理实战:文本分类与情感分析
本文探讨了自然语言处理中的文本分类和情感分析技术,阐述了基本概念、流程,并通过Python示例展示了Scikit-learn和transformers库的应用。面对多义性理解等挑战,研究者正探索跨域适应、上下文理解和多模态融合等方法。随着深度学习的发展,这些技术将持续推动人机交互的进步。
20 1
|
22天前
|
自然语言处理 监控 数据挖掘
NLP实战:Python中的情感分析
6月更文挑战第6天
35 2
|
2月前
|
自然语言处理 API 数据库
自然语言处理实战第二版(MEAP)(六)(5)
自然语言处理实战第二版(MEAP)(六)
30 3
|
2月前
|
机器学习/深度学习 自然语言处理 机器人
自然语言处理实战第二版(MEAP)(六)(4)
自然语言处理实战第二版(MEAP)(六)
27 2
|
2月前
|
机器学习/深度学习 自然语言处理 机器人
自然语言处理实战第二版(MEAP)(六)(3)
自然语言处理实战第二版(MEAP)(六)
30 1
|
2月前
|
机器学习/深度学习 人工智能 自然语言处理
自然语言处理实战第二版(MEAP)(六)(2)
自然语言处理实战第二版(MEAP)(六)
28 2
|
1天前
|
机器学习/深度学习 自然语言处理 算法
使用自然语言处理技术提升文本分类准确率
在当今信息爆炸的时代,准确的文本分类对于信息管理至关重要。本文探讨了如何利用先进的自然语言处理技术,结合深度学习模型,提升文本分类的准确率和效率。通过详细的实验分析和案例研究,展示了不同方法在不同场景下的应用效果和优劣比较,为技术人员提供了实用的指导和启发。
10 0
|
22天前
|
机器学习/深度学习 人工智能 自然语言处理
探索未来AI技术的前沿——自然语言处理的发展与应用
本文将深入探讨自然语言处理技术在人工智能领域中的重要性和应用前景。通过分析当前自然语言处理技术的发展趋势和实际应用案例,揭示了其在改善用户体验、提升工作效率以及推动产业创新方面的巨大潜力。