什么是潜在语义索引 (LSI) 及其工作原理?
了解 LSI 的内部工作原理,查看实际的 Python 实现,并探索为何这项基础技术在当今 AI 驱动的搜索领域中仍然具有重要意义。

潜在语义索引(LSI)是一种数学文档理解和检索方法。LSI 常用于搜索引擎、电子商务、网站搜索以及其他需要搜索功能的应用程序中。
本文全面概述了 LSI。具体而言,它回答了以下问题:
- 什么是 LSI,它是如何工作的?
- LSI 有哪些优势,它应用在哪里?
- 如何在 Python 中实现 LSI?(我们提供分步解释)
- LSI 的一些现代替代方案是什么?
那么,让我们直接开始吧。
什么是潜在语义索引 (LSI)?
LSI 是一种信息检索方法,在自然语言处理(NLP)中用于揭示文本中词语和概念之间的潜在(隐藏)关系。
与传统的基于关键词的方法不同,LSI 是一种语义搜索,它分析文档中术语之间的语义关系,以提取隐藏的概念并根据这些概念对文档进行分组。
LSI 使用奇异值分解(SVD)将复杂的高维数据分解为更小、隐藏的概念,从而简化数据。这有助于识别词语和文档之间关系的模式。LSI 解决了同义词和反义词的挑战,并将具有相同含义的词语投射到相似的更高维度中。
例如,在 LSI 的高维图中,相关术语“doctor”(医生)和“physician”(医师)将被放置得更近,反映相同的概念。当用户搜索文档时,查询会被投射到高维空间中,并返回最相关的文档。
LSI 是文档理解和检索的基础技术之一。由于其简单性和较低的计算成本,它仍然被广泛使用。
既然您了解了什么是 LSI,接下来让我们看看它是如何工作的。
潜在语义索引是如何工作的?
LSI 采用 SVD,这是一种数学技术,它将词-文档矩阵分解为更小的矩阵,从而捕获文档中词语和概念之间的潜在关系。
下图展示了 LSI 的工作流程。
让我们通过示例讨论以上步骤。
步骤1:导入数据集
第一步是创建您想要应用 LSI 的文档集。
假设您有以下四份文档:
文档 1 | 猫和狗是可爱的宠物。 |
---|---|
文档 2 | 狗是忠诚的宠物。 |
文档 3 | 宠物带来欢乐和幸福。 |
文档 4 | 幸福和快乐赋予生命意义。 |
步骤2:预处理文档
文本文档可能包含停用词,这些词对文档的含义或概念没有贡献。在预处理中,您可以删除停用词,将文本转换为小写,并删除其他无用的信息。
预处理后,我们的文档可能看起来像这样:
文档 1 | 猫 狗 可爱 宠物。 |
---|---|
文档 2 | 狗 忠诚 宠物 |
文档 3 | 宠物 带来 欢乐 幸福 |
文档 4 | 幸福 欢乐 带来 意义 生命。 |
步骤3:创建词-文档矩阵
在创建词-文档矩阵之前,您需要为所有文档创建一个独特的词语集合。这个集合通常被称为词汇表。我们样本数据集中文档的词汇表看起来像这样:
PATCH /network ['bring', 'cats', 'dogs', 'happiness', 'joy', 'life', 'loyal', 'meaning', 'pets' 'wonderful']
下一步是创建一个 N x M 形状的词-文档矩阵,其中 N 是文档数量,M 是词汇表大小。矩阵中的每一行对应一个文档中词语出现的频率。这个矩阵捕获了词语在文档中共同出现的模式,这对于识别潜在概念至关重要。
我们数据集的词-文档矩阵看起来像这样:
步骤4:奇异值分解
SVD 算法将一个矩阵分解为更小的矩阵。在 LSI 中,SVD 将词-文档矩阵 A 分解为三个矩阵:A=UΣVT
- 矩阵 U:将文档与潜在概念关联起来。它也被称为文档-概念相似度矩阵。这个矩阵显示了一个文档与特定概念的关联程度。
- 矩阵 Σ:一个对角矩阵,其奇异值表示每个概念的强度。
- VT:将术语与潜在概念关联起来,通常被称为术语-概念相似度矩阵。它显示了一个术语与特定概念的关联程度。
我在此不深入探讨 SVD 的数学细节。然而,我们数据集中为这两个概念检索到的三个矩阵看起来像这样。
步骤5:分析 LSI 矩阵
值得注意的是,LSI 中不会自动生成概念名称。相反,您必须查看分组的文档或术语并推断出概念。
例如,您可以看到文档 1 和文档 2 属于概念 2,因为它们在文档-概念相似度矩阵的第二列中具有更高的值。类似地,文档 3 和文档 4 属于概念 1。
文档 1 和 2 提到了动物和宠物。文档 3 和 4 更多地是关于幸福和快乐。因此,我们可以将这两个概念命名为:宠物动物和生活与幸福。这使得 LSI 能够检索到内容最相关的文档,即使没有精确匹配的术语。
您将在后面的章节中看到上述示例的完整 Python 应用;现在,让我们看看 LSI 的一些用途和优势。
潜在语义索引在哪里使用?
潜在语义索引应用于各种自然语言处理(NLP)领域,包括文本摘要、文档自动分类、在线客户支持和垃圾邮件过滤。
以下是 LSI 派上用场的一些用例:
- 搜索引擎:LSI 对用户查询和文档进行语义分析,以提高搜索引擎性能。这有助于搜索引擎理解用户的搜索意图,并检索更相关的网页和相关搜索。
- 文档自动分类:LSI 搜索算法能高效地将文档分类到预定义的类别中。它们常用于无监督情感分类、电子邮件分类等目的。
- 在线客户支持:与搜索引擎类似,LSI 可以在客户管理系统中将搜索者的查询与相关解决方案进行匹配。
- 垃圾邮件过滤:LSI 基于语义内容检测和过滤垃圾邮件。
- 信息可视化:通过 LSI 生成的文档聚类可以在低维空间中绘制,以查看文档之间的关系。
既然我们已经了解了 LSI 的一些用途,接下来让我们讨论它的优势。
潜在语义索引有哪些优势?
LSI 的主要优势如下:
- 基于概念的聚类:LSI 将相关文档分组,使大型数据集的组织和分析变得更加容易。
- 处理同义词和多义词:LSI 可以有效地处理同义词。例如,“car”和“automobile”这两个词将具有相似的语义表示。
- 可扩展性:LSI 是一种数学技术,它利用强大的计算能力高效地进行扩展,使其成为电子取证和企业搜索系统等应用的理想选择。
- 对拼写错误的鲁棒性:LSI 依赖语义意义,使其对拼写错误不那么敏感,从而改善了搜索和检索系统中的用户体验。
- 跨领域通用性:应用于搜索引擎、教育、金融等领域。
下一节将展示 LSI 和潜在语义分析之间的主要区别。
LSI 和 LSA 有什么区别?
LSI 和潜在语义分析(LSA)通常可以互换使用。两种技术的核心都是 SVD。然而,它们在应用和侧重点上略有不同。
LSI 最初是作为一种信息检索和搜索技术开发的,旨在解决文档的语义理解和同义词等挑战。LSI 的主要应用是根据用户的搜索查询检索语义相似的文档。
另一方面,潜在语义分析超越了信息检索,专注于其他自然语言处理(NLP)任务,如语音识别、文档聚类和分类以及认知建模。
让我们看看如何在 Python 中实现 LSI。
在 Python 中实现潜在语义索引
本节将展示一个在 Python 中实现 LSI 算法的实际示例。
安装和导入所需的库
我们将使用 Python 的 Scikit Learn 库和 NLTK 工具包在 Python 中实现 LSI。以下脚本安装这些库。
PATCH /network !pip install -qU scikit-learn nltk pandas
以下脚本导入了运行本文中提到的 Python 脚本所需的模块和类。
PATCH /network import numpy as np from sklearn.feature_extraction.text import CountVectorizer from sklearn.decomposition import TruncatedSVD from sklearn.metrics.pairwise import cosine_similarity from nltk.corpus import stopwords from nltk.tokenize import word_tokenize import nltk import matplotlib.pyplot as plt import pandas as pd nltk.download('stopwords') nltk.download('punkt') nltk.download('punkt_tab')
让我们一步步实现 LSI。值得一提的是,这些步骤与您在前面介绍 LSI 工作原理的章节中看到的步骤相同。在这里,它们将在 Python 中实现。
步骤1:导入文档
第一步是收集您想要实现 LSI 的文档。这些可以是您的个人、业务或客户文档。
本节将使用一个包含四份虚拟文档的小数据集,每份文档包含一个句子。
PATCH /network # Example documents documents = [ "Cats and dogs are wonderful pets.", "Dogs are loyal pets.", "Pets bring joy and happiness.", "Happiness and joy bring meaning to life." ]
步骤2:预处理文档
在预处理步骤中,我们将从文档中删除停用词和标点符号,如以下脚本所示:
PATCH /network # Preprocessing: Tokenization and stopword removal stop_words = set(stopwords.words('english')) def preprocess(doc): words = word_tokenize(doc.lower()) return ' '.join([word for word in words if word.isalnum() and word not in stop_words]) processed_docs = [preprocess(doc) for doc in documents] processed_docs
输出
步骤3:创建词-文档矩阵
您可以使用 Sklearn 库中 CountVectorizer()
类的 fit_transform()
方法来创建词-文档矩阵。您可以使用 get_feature_names_out()
方法检索文档词汇表。
PATCH /network vectorizer = CountVectorizer() term_document_matrix = vectorizer.fit_transform(processed_docs) feature_names = vectorizer.get_feature_names_out() print(feature_names) term_document_array = term_document_matrix.toarray() df_term_document = pd.DataFrame(term_document_array, columns=feature_names, index=[f"Doc {i+1}" for i in range(len(term_document_array))]) print(df_term_document)
输出
上述输出显示了文档的词汇表(唯一词语列表)和词-文档矩阵,展示了每个文档的词语频率。
步骤4:应用奇异值分解
您可以使用 Sklearn 库中的 TrancatedSVD
类来实现 SVD。您必须传递您希望从文档中提取的概念数量。
在下面的脚本中,我们提取了两个概念。输出显示了概念强度矩阵、文档-概念相似度矩阵和术语-概念相似度矩阵。概念强度矩阵显示概念 1 在文档中略占优势。
PATCH /network svd = TruncatedSVD(n_components=2, random_state=42) lsi_matrix = svd.fit_transform(term_document_matrix) # Display Results print(" Singular Values (Concept Strength): ", svd.singular_values_) print(" Document-Concept Similarity Matrix: ", lsi_matrix) print(" Term-Concept Similarity Matrix: ", svd.components_.T)
在下一步中,我们将分析文档-概念相似度矩阵和术语-概念相似度矩阵。
步骤5:分析 LSI 矩阵
让我们绘制一个二维图,在概念轴上显示文档。
PATCH /network # Extract values for Concept 1 (x-axis) and Concept 2 (y-axis) x = lsi_matrix[:, 0] # Values for Concept 1 y = lsi_matrix[:, 1] # Values for Concept 2 # Create a scatter plot plt.figure(figsize=(8, 6)) plt.scatter(x, y, color='blue', label='Documents') # Annotate each document for i, (x_val, y_val) in enumerate(zip(x, y)): plt.text(x_val + 0.02, y_val, f'Doc {i+1}', fontsize=9) # Add gridlines, labels, and title plt.axhline(0, color='gray', linestyle='--', linewidth=0.5) plt.axvline(0, color='gray', linestyle='--', linewidth=0.5) plt.title("Document-Concept Similarity") plt.xlabel("Concept 1") plt.ylabel("Concept 2") plt.grid() plt.legend() plt.show()
输出
输出显示文档 1 和 2 主要属于概念 2,而文档 3 和 4 属于概念 1。
为了了解每个概念中的信息,您可以绘制每个概念的术语。
PATCH /network terms = vectorizer.get_feature_names_out() concept1_weights = svd.components_[0] concept2_weights = svd.components_[1] fig, ax = plt.subplots(1, 2, figsize=(12, 6)) ax[0].barh(terms, concept1_weights, color='orange') ax[0].set_title("Term Weights for Concept 1") ax[0].set_xlabel("Weight") ax[1].barh(terms, concept2_weights, color='green') ax[1].set_title("Term Weights for Concept 2") ax[1].set_xlabel("Weight") plt.tight_layout() plt.show()
输出
上述输出显示,“pets”(宠物)、“joy”(欢乐)、“happiness”(幸福)、“bring”(带来)等相关关键词主要属于概念 1,该概念关于生活和情感。
另一方面,“pets”(宠物)、“wonderful”(可爱)、“cats”(猫)、“dogs”(狗)等术语主要属于概念 2。我们可以推断概念 2 是关于宠物和动物的。
现在您知道为什么文档 1 和 2 属于概念 2,而文档 3 和 4 属于概念 1 了。
就是这样。您已经使用自己的自定义文档开发了第一个 LSI 模型。
在下一步中,您将学习如何使用 LSI 针对用户查询检索相关的搜索结果。
搜索和检索
您需要像预处理 LSA 文档一样预处理查询。
PATCH /network user_query = "Joyful pets bring happiness to life." # Example query preprocessed_query = preprocess(user_query) # Preprocess query print("Preprocessed Query:", preprocessed_query)
输出
接下来,使用您用于创建文档-概念和术语-概念相似度矩阵的 SVD 模型,将查询嵌入到 LSI 空间中。
然后,您可以使用余弦相似度或任何其他向量相似度函数,在 LSI 空间中找到查询与文档之间的相似度。
PATCH /network query_vector = vectorizer.transform([preprocessed_query]) # Transform query to term-document matrix query_lsi = svd.transform(query_vector) # Map query to LSI latent space print(" Query in LSI Space (Concepts): ", query_lsi) # Use cosine similarity between the query and document vectors similarities = cosine_similarity(query_lsi, lsi_matrix) print(" Similarity Scores: ", similarities)
输出
最后,您可以根据文档与输入查询的相关性来检索和排序文档。在这种情况下,余弦相似度将是检索到的文档的排序因素。
PATCH /network # Rank documents by similarity doc_indices = np.argsort(similarities[0])[::-1] # Sort by descending similarity print(" Ranked Document Indices (Most Relevant First):", doc_indices) # Output relevant documents print(" Top Relevant Documents:") for idx in doc_indices: print(f"Doc {idx + 1}: {documents[idx]} (Similarity: {similarities[0][idx]:.3f})")
输出
输出显示了文档针对输入查询的搜索排名。文档 3 与查询中的搜索词最相关,这是有道理的,因为它同时讨论了宠物和幸福。
现在,让我们看看 LSI 是否仍然重要。
潜在语义索引仍然相关吗?
LSI 易于实现且计算成本不高。因此,在实现不需要深入理解词语和概念之间关系的简单文档理解和检索解决方案时,它仍然被使用。
然而,为了实现对文档更高级的理解,已经开发出更新的方法。这些方法包括基于机器学习和深度学习技术的向量搜索、词嵌入和 Transformer 方法。这些方法在几乎所有基准测试中都优于 LSI。
Meilisearch 是一款先进的 AI 搜索引擎,它利用尖端的向量搜索方法,将最先进的搜索引擎功能集成到您的应用程序中。它实现了基于词嵌入和向量搜索的语义搜索技术,从而能够更深入地理解文档中的关系和概念,提高了检索文档的相关性和鲁棒性。
Meilisearch 的 AI 搜索引擎可以无缝集成到电子商务、网站、应用内搜索以及任何其他涉及搜索项目或文档的应用程序中。
总结
LSI 是搜索和检索应用的基础技术。它易于实现,且计算成本低于先进的基于深度学习的技术。然而,它在可扩展性、实时相关性以及多语言理解方面存在问题。
但随着向量搜索和高级词嵌入的出现,Meilisearch 等工具正在重新定义文档理解和检索的可能性。Meilisearch 为文档搜索提供了最先进的功能:
- 极速性能:在 50 毫秒内提供搜索结果,带来流畅的用户体验。
- 即时搜索:用户输入时提供实时结果和即时反馈。
- 错别字容忍:即使查询中存在错别字或拼写错误,也能确保相关结果。
- 全面的语言支持:针对多种语言进行优化,包括拉丁语、中文、日语和希伯来语。
- 分面搜索和过滤:实现通过类别和过滤器的直观导航。
- 自定义排名和相关性:允许定制排名和相关性规则,以获得精确的搜索结果。
- AI 就绪集成:与 AI 模型无缝协作,实现混合语义和全文搜索功能。