机器学习与人工智能:NLP分词与文本相似度分析

DIY AI & ML NLP — Tokenization & Text Similarity by Jacob Ingle in Data Science Collective

本文所使用的数据是在 Creative Commons license 下提供的。尽管我们已尽力确保信息的准确性和完整性,但我们不对数据的完整性或可靠性做任何保证。数据的使用符合相应许可条款,第三方使用时应遵守原始许可要求。

读者被鼓励查看与数据集相关的具体 Creative Commons license,以了解允许的使用、修改和署名要求的详细信息。

系列文章回顾

向所有 DIY AI & ML 系列的读者们问好!这是一段令人难以置信的旅程,我们才刚刚开始。如果你想查看到目前为止的任何文章,请见下方!

线性回归

逻辑回归

K-Means
决策树

自然语言处理

你有没有想过,生成式 AI 工具或大型语言模型背后究竟发生了什么?自然语言处理(NLP)是这些工具的核心,它使计算机能够理解人类语言。换句话说,NLP 是连接人类交流和机器(如计算机)的桥梁。因此,它是任何生成式 AI 工具的重要组成部分。

在本文中,我们将构建一个简单的 Python NLP 对象,它接受一组文档,执行各种标准的 NLP 预处理技术,最后,允许终端用户输入新的文档或文本,并从之前上传的文档组中提取最相似的文本。

分词与预处理

每个机器学习管道、数据科学项目和探索性数据分析任务都需要数据清洗或预处理步骤,自然语言处理也不例外。当我开始学习 NLP 时,我记得被从表格数据转换为实际单词的格式所淹没。了解这一点后,让我们逐步分解 NLP 任务中清理文本数据的各个部分。

分词将文本分解为更小的单元,如单个单词或字符。让我们来看一个例子,我们在一个句子上执行分词:

“Medium is a great place for writing content.”

分解成单个单词或 tokens 后,它看起来像这样:

“Medium”, “is”, “a”, “great”, “place”, “for”, “writing”, “content.”

开始将这段文本视为数据集中的一个观测值,并将每个单词视为一个二进制列。因此,对于这个句子,所有这些单词的列都将为 1True,对于所有其他单词或 tokens,它将是 0 或 False。我有点超前了,但如果你是 NLP 新手,早点这样思考会很有帮助。

现在分词步骤完成了,让我们学习如何预处理文本数据。假设我们还有另一个句子,内容如下:

“A great place for writing content is Medium.”

分词后,它将读作:

“A”, “great”, “place”, “for”, “writing”, “content”, “is”, “Medium.”

从人类交流的角度来看,这两个文本几乎完全相同,并且传达了相同的信息。然而,NLP 是关于构建人类交流和计算机之间的桥梁,计算机可能会将这些句子视为完全不同。你正在构建的 NLP 应用程序或工具的最终产品将决定你需要对文本进行何种预处理。我们将在本文中创建一个相似度模型,因此我们要确保用于训练该模型的文本是经过适当预处理的。

第一步是将所有内容转换为小写。注意单词 “a” 在每个陈述中都被用作一个单词。然而,在一个句子中它被大写,而在另一个句子中是小写。通过将所有内容转换为小写,计算机或 NLP 模型将理解这些是同一个标记的两个实例,而不是两个不同的标记。

None

作者提供的图片

None

作者提供的图片

你是否已经开始像 NLP 实践者那样思考了?换句话说,你是否已经开始理解我们所看到的与计算机所看到的之间的联系,以及它如何适用于我们的相似性引擎?想想我们可以在数据中去除的噪声。对于 NLP 来说,去除噪声的最常见技术是去除在大多数文本中出现的填充词或常见词。我们称这些为“停用词”。注意,这一步可能非常主观。然而,有许多开源库允许你下载一个停用词列表,你可以在你的 NLP 应用程序中使用。本着从头开始构建我们的对象的精神,我们将创建我们自己的停用词列表。为什么我们应该关心去除停用词?将停用词视为在数据集中每个观测值中都出现且没有明显模式的数据点。如果数据集中的每个观测值都有这样一个没有明显模式的目标的数据点,那么它只会为我们的模型增加噪声,甚至可能阻碍它。在 NLP 应用程序中,停用词也不例外。

None

作者提供的图片

让我们继续一个更高级的文本数据预处理方法:创建 n-grams。回到停用词,你应该总是去除它们吗?这取决于你的数据上下文和你的 NLP 模型。有时,停用词可能会根据它们在文本行中的位置提供必要的上下文。

目前,我们的数据将是顺序无关的。换句话说,将我们的分词文本输入模型会将多个句子中的同一个单词的多个实例视为相同,不管它在句子中的使用方式和位置如何。为了捕捉这些细微差别,我们可以将标记转换为 n-grams。例如,假设我们想要捕捉我们正在处理的句子中的每个两个单词的短语,更正式地说,就是二元组(bigrams)。我添加了停用词,看看包含它们的分词文本在应用二元组后会是什么样子。

None

作者提供的图片

现在,单词的顺序很重要了!这种增加的复杂性可以捕捉文本数据中的细微差别,使我们的相似性引擎更加精确。我们甚至可以将文本转换为三元组(trigrams)、四元组(quadragrams)等。注意,这可能会使你的 NLP 应用程序或模型变得复杂、计算成本高昂,甚至冗余。因此,一些 NLP 库中有内置逻辑,规定只有当 n-gram 在一定比例的文档中存在时,才能创建它。这种效率确保你不会执行任何冗余的预处理。我在这里谈论去除停用词和创建 n-grams 也不是巧合。这两种技术的预处理顺序将显著影响你的模型。

词袋模型(Bag-of-Words Model, BOW)

我们可以开始构建人类语言和计算机之间的桥梁了。我们回顾了清理文本数据的技术,现在将把它转换成计算机可以理解的格式。

词袋模型 是将文本建模成计算机或应用程序可以理解的最简单方式。它只是查看文档集合(也称为 语料库)中的所有唯一标记,并将每个文档转换为语料库中每个标记的计数集合。让我们来看一个假设的例子,语料库包含三个文档。

None

作者提供的图片

首先,让我们从这些文档中提取所有唯一的标记,这也就是所谓的 词汇表

None

接下来,我们将每个文档转换为一个 词袋 向量。为此,我们取词汇表,并为文档和词汇表中都出现的每个单词标记 1,否则为 0 。这个过程应该与对分类数据进行虚拟编码或独热编码非常相似。

None

仅此而已。这应该与对分类数据进行虚拟编码或独热编码非常相似。

余弦相似度

在创建我们的对象之前,是时候讨论我们相似性引擎的核心数学原理了,即 余弦相似度。它通过计算两个向量之间的夹角的余弦值来衡量两个向量之间的相似度。在我们将文本转换为 词袋 向量之前,这听起来可能会更疯狂一些。余弦相似度 是衡量文本相似度的绝佳选择,因为它可以让我们感受到文档之间的相似性,而不管一个文档是否比另一个大得多。它有助于捕捉提供相似上下文或总体信息的相似文档。余弦相似度 的分数范围从 -1 到 1,其中 1 表示最相似,0 表示没有相似性,-1 表示两个文档完全相反,我应该指出,使用 TF-IDF 分数计算的词袋向量中这种情况很少见。让我们来看看两个向量 A 和 B 之间的余弦相似度公式。

cos ⁡ ( θ ) = A ⋅ B ∥ A ∥ ∥ B ∥ \cos(\theta) = \frac{A \cdot B}{\|A\| \|B\|} cos(θ)=A∥∥BAB

作者提供的图片

在分子中,我们取两个向量的点积,在分母中,我们取两个向量的模的乘积。

None

在这个假设的例子中,我们可以看到,根据余弦相似度指标,两个向量 AB 非常相似;换句话说,它们的方向几乎相同。

DIYSimilarityEngine 类

尽管这个对象的名字如此,但大多数方法将致力于分词、预处理文本数据以及构建袋装词向量。通常,这些步骤是在构建一些基于 NLP 的模型之前通过其他库和框架完成的。然而,将这些步骤整合到同一个对象中是实用的。我应该指出,常见的 NLP 预处理框架,如 nltk 和 spacy,将提供比你在这里看到的更高级的技术,因为我的目标是在基础水平上展示这些,以便读者能够获得坚实的基础。

import pandas as pd
import re
import math
from collections import Counterclass DIYSimilarityEngine:def __init__(self, ngram_n=1, stopwords=None):self.ngram_n = ngram_nself.stopwords = set(stopwords) if stopwords else set(['the', 'is', 'at', 'which', 'on', 'a', 'an', 'and', 'in', 'it', 'of', 'to', 'with', 'as', 'for', 'by'])self.documents = []self.vocabulary = set()self.bow_vectors = []

_preprocess_generate_ngrams 方法

我们的前两个方法对文档列表中的每个文档进行预处理和分词。注意,创建 n-grams 的方法是在预处理方法中调用的。注意调用的顺序。首先,将文本转换为小写,去除标点符号,执行分词,最后,将标记转换为 n-grams,它们仍然是标记。始终在去除你认为是噪声的文本(如停用词)之后,将文本转换为 n-grams。

def _preprocess(self, text):# 将文本转换为小写text = text.lower()# 去除标点符号text = re.sub(r'[^\w\s]', '', text)# 分词tokens = text.split()# 去除停用词tokens = [t for t in tokens if t not in self.stopwords]if self.ngram_n > 1:# 如果需要,生成 n-gramstokens = self._generate_ngrams(tokens, self.ngram_n)return tokensdef _generate_ngrams(self, tokens, n):# 生成 n-gramsreturn ['_'.join(tokens[i:i+n]) for i in range(len(tokens)-n+1)]

_build_vocabulary_vectorizefit 方法

这两个方法基于现在分词后的文档列表构建一个唯一的标记集合;同样,这也就是我们袋装词模型的 词汇表。有了 词汇表_vectorize 方法利用 collections 库中的 Counter 方法为分词后的文档构建一个袋装词向量,该文档以 1 和 0 的列表形式表示。

这两个方法和 _preprocess 方法一起在 fit 方法中使用,以将模型的词汇表分配给词汇表属性,并将所有的袋装词向量分配给其属性。

def _build_vocabulary(self, tokenized_docs):vocab = set()for tokens in tokenized_docs:vocab.update(tokens)return sorted(vocab)def _vectorize(self, tokens, vocab):tf = Counter(tokens)return [tf[word] for word in vocab]def fit(self, documents):self.documents = documentstokenized = [self._preprocess(doc) for doc in documents]self.vocabulary = self._build_vocabulary(tokenized)self.bow_vectors = [self._vectorize(tokens, self.vocabulary) for tokens in tokenized]

_cosine_similaritymost_similar 方法

这两个方法是我们对象的核心,但如果没有之前的预处理,它将一无是处。记住,在调用 most_similar 方法之前,必须先将语料库拟合到对象中。这个方法接受一个新文档,对其进行预处理,然后利用 _cosine_similarity 方法来确定语料库中哪些文档最相似,通过返回一个列表,其中包含最相似的前三个文档及其相关的余弦相似度分数,以便用户能够了解它们的相似程度。

def _cosine_similarity(self, vec1, vec2):# 计算两个向量的点积dot_product = sum(a*b for a, b in zip(vec1, vec2))# 计算向量的模norm1 = math.sqrt(sum(a*a for a in vec1))norm2 = math.sqrt(sum(b*b for b in vec2))if norm1 == 0 or norm2 == 0:return 0.0return dot_product / (norm1 * norm2)def most_similar(self, query, top_n=3):# 对查询文本进行预处理query_tokens = self._preprocess(query)# 将查询文本转换为袋装词向量query_vector = self._vectorize(query_tokens, self.vocabulary)# 计算查询向量与语料库中每个文档向量的余弦相似度similarities = [(i, self._cosine_similarity(query_vector, bow_vector))for i, bow_vector in enumerate(self.bow_vectors)]# 按相似度降序排序similarities.sort(key=lambda x: x[1], reverse=True)# 返回最相似的前 top_n 个文档及其相似度分数return [(self.documents[i], sim) for i, sim in similarities[:top_n]]

现实世界应用:寻找最佳工作

无论当前就业市场的状况如何,了解一个人凭借其技能和经验最有可能获得哪些工作机会总是有益的,特别是对于数据科学家和类似职业。使用我们的相似性引擎对象,我们将对其进行测试,通过创建一个概述个人经验和技能集的假设文档,并使用来自 Kaggle 的 2023 数据科学家职位描述数据集 来查看哪个工作最匹配。

让我们先为一个有五年数据分析师经验的候选人编写描述和技能集:

经验丰富的数据分析师,拥有 5 年通过数据驱动的决策制定提供可操作见解的经验。熟练掌握 SQL、Excel 和 Tableau、Power BI 等可视化工具,具有扎实的 Python 高级分析基础。证明了设计和自动化报告仪表板、进行统计分析以及跨职能合作以支持业务战略的能力。擅长识别趋势、优化流程以及以清晰、有影响力的方式传达复杂发现。

让我们先初始化对象的一个实例,并拟合 Jobs 数据集中的职位描述。

nlp = DIYSimilarityEngine(ngram_n=3)
data = pd.read_csv('Jobs.csv')
docs = list(data['description'])
nlp.fit(docs)

现在,让我们找出候选人最有可能获得面试或录用的工作,理论上。

summary = """
经验丰富的数据分析师,拥有 5 年通过数据驱动的决策制定提供可操作见解的经验。
熟练掌握 SQL、Excel 和 Tableau、Power BI 等可视化工具,具有扎实的 Python 高级分析基础。
证明了设计和自动化报告仪表板、进行统计分析以及跨职能合作以支持业务战略的能力。
擅长识别趋势、优化流程以及以清晰、有影响力的方式传达复杂发现。
"""
_ = nlp.most_similar(summary)
most_similar_doc = _[0][0]
data[data['description'] == most_similar_doc]

None

这个结果得出了 0.06 的相似度分数!说实话,这并不理想,如果你仔细阅读职位描述并与候选人的总结进行比较,你会发现许多技能是匹配的。然而,一旦你看到这份工作需要很多小众的职责和背景,差异就相当明显了。如何改进呢?我们很容易说模型或预处理需要更多的细节,但也可以认为候选人的总结越详细越好。、

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RK3568平台OpenHarmony系统移植可行性评估

https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/quick-start/quickstart-appendix-compiledform.md 官方给的标准系统就是RK3568, 所以肯定可以, 关于硬件加速部分 看了鸿蒙RK3568开发板的GPU编译配置,只能说能用 https://docs.openharmony.cn/pages/v4.1/zh-cn/…

论文浅尝 | HOLMES:面向大语言模型多跳问答的超关系知识图谱方法(ACL2024)

笔记整理:李晓彤,浙江大学硕士,研究方向为大语言模型 论文链接:https://arxiv.org/pdf/2406.06027 发表会议:ACL 2024 1. 动机 多跳问答(Multi-Hop Question Answering, MHQA)技术近年来在自然语…

机器学习中的特征工程:解锁模型性能的关键

在机器学习领域,模型的性能往往取决于数据的质量和特征的有效性。尽管深度学习模型在某些任务中能够自动提取特征,但在大多数传统机器学习任务中,特征工程仍然是提升模型性能的关键环节。本文将深入探讨特征工程的重要性、常用方法以及在实际…

Kotlin与Java的融合趋势:从互操作到云原生实践

在2025年的软件开发领域,Kotlin和Java作为JVM生态的支柱语言,展现出强大的协同能力。Kotlin以其简洁的语法和现代特性迅速崛起,而Java凭借其成熟生态和稳定性依然占据主导地位。通过两者的融合,我们的实时聊天系统将开发效率提升了…

Python生成器:高效处理大数据的秘密武器

生成器概述 生成器是 Python 中的一种特殊迭代器,通过普通函数的语法实现,但使用 yield 语句返回数据。生成器自动实现了 __iter__() 和 __next__() 方法,因此可以直接用于迭代。生成器的核心特点是延迟计算(lazy evaluation&…

Flask框架入门与实践

Flask框架入门与实践 Flask是一个轻量级的Python Web框架,以其简洁、灵活和易于上手的特点深受开发者喜爱。本文将带您深入了解Flask的核心概念、基本用法以及实际应用。 什么是Flask? Flask是由Armin Ronacher于2010年开发的微型Web框架。与Django等…

数学复习笔记 14

前言 和家里人交流了一下,他们还是希望我全力以赴初试,我确实也得放开了干,不要束手束脚的。好好加油。感觉公共课都没有啥压力,主要是专业课要好好加油,真不能过不了线,要是过不了线,啥都白搭…

金格iWebOffice控件在新版谷歌Chrome中不能加载了怎么办?

金格iWebOffice控件是由江西金格网络科技有限责任公司开发的中间件软件,主要用于在浏览器中直接编辑Word、Excel、PowerPoint等Office文档,曾经是一款优秀国产的WebOffice插件。 由于2022年Chrome等浏览器取消支持PPAPI接口,导致这款金格iWe…

ChatGPT 能“记住上文”的原因

原因如下 你把对话历史传给了它 每次调用 OpenAI 接口时,都会把之前的对话作为参数传入(messages 列表),模型“看见”了之前你说了什么。 它没有长期记忆 它不会自动记住你是谁或你说过什么,除非你手动保存历史并再次…

微信小程序van-dialog确认验证失败时阻止对话框的关闭

使用官方(Vant Weapp - 轻量、可靠的小程序 UI 组件库)的before-close&#xff1a; wxml&#xff1a; <van-dialog use-slot title"名称" show"{{ show }}" show-cancel-button bind:cancel"onClose" bind:confirm"getBackInfo"…

K8S Ingress、IngressController 快速开始

假设有如下三个节点的 K8S 集群&#xff1a; ​ k8s31master 是控制节点 k8s31node1、k8s31node2 是工作节点 容器运行时是 containerd 一、理论介绍 1&#xff09;什么是 Ingress 定义&#xff1a;Ingress 是 Kubernetes 中的一种资源对象&#xff0c;它定义了外部访问集群内…

Vue3 + Element Plus 动态表单实现

完整代码 <template><div class"dynamic-form-container"><el-formref"dynamicFormRef":model"formData":rules"formRules"label-width"auto"label-position"top"v-loading"loading"&g…

Mac修改hosts文件方法

Mac修改hosts文件方法 在 macOS 上修改 hosts 文件需要管理员权限 步骤 1&#xff1a;打开终端 通过 Spotlight 搜索&#xff08;Command 空格&#xff09;输入 Terminal&#xff0c;回车打开。或进入 应用程序 > 实用工具 > 终端。 步骤 2&#xff1a;备份 hosts 文件…

深度学习—BP神经网络

文章目录 [TOC](文章目录) 一、基本概念二、 网络结构三、BP神经网络的原理总结特点&#xff1a;应用场景优缺点 一、基本概念 BP 神经网络&#xff08;Backpropagation Neural Network&#xff09;是一种基于误差反向传播算法的多层前馈神经网络&#xff0c;由输入层、隐藏层…

Spring AI(6)——向量存储

向量数据库是一种特殊类型的数据库&#xff0c;在 AI 应用中发挥着至关重要的作用。 在向量数据库中&#xff0c;查询与传统关系型数据库不同。它们执行的是相似性搜索&#xff0c;而非精确匹配。当给定一个向量作为查询时&#xff0c;向量数据库会返回与该查询向量“相似”的…

Qt功能区:简介与安装

Qt功能区 1. 功能区简介2. SARibbon2.1 简介2.2 编译与安装采用CMake-gui进行编译采用VS进行编译安装与使用 Qt 官方不支持 Ribbon 风格&#xff08;Ribbon UI 风格是微软开创的&#xff0c;具有专利许可协议&#xff0c;许可协议对从构建 UI 的指令到每个按钮间的空格数都做了…

iOS safari和android chrome开启网页调试与检查器的方法

手机开启远程调试教程&#xff08;适用于 Chrome / Safari&#xff09; 前端移动端调试指南&#xff5c;适用 iPhone 和 Android&#xff5c;WebDebugX 出品 本教程将详细介绍如何在 iPhone 和 Android 手机上开启网页检查器&#xff0c;配合 WebDebugX 实现远程调试。教程包含…

Golang企业级商城高并发微服务实战

Golang企业级商城高并发微服务实战包含内容介绍&#xff1a; 从零开始讲了百万级单体高并发架构、千万级微服务架构&#xff0c;其中包含Rpc实现微服务、微服务的跨语言调用jsonrpc和protobuf、protobuf的安装、protobuf高级语法、protobuf结合Grpc实现微服务实战、微服务服务…

实现可靠的 WebSocket 连接:心跳与自动重连的最佳实践

概览 本文将手把手教你如何从零编写一个可用于直播或在线聊天的 WSocket 类&#xff0c;依次实现连接建立、心跳检测、断线重连、消息收发以及资源清理等功能。我们将结合 WebSocket API 的标准用法、心跳保持 和 重连策略&#xff0c;并充分运用现代 JavaScript 语法&#xf…

UEFI Spec 学习笔记---33 - Human Interface Infrastructure Overview(1)

33 - Human Interface Infrastructure Overview 本章节主要用于介绍Human Interface Infrastructure&#xff08;HII&#xff09;架构介绍&#xff0c;描述如何通过 HII 来管理用户的输入&#xff0c;以及描述在 UEFI spec 中涉及 HII 相关的 Protocol、function 和类型定义。…