python实战(三)——文本向量化/文本表示

news2024/12/27 11:57:32

一、概念

        文本向量化是自然语言处理领域的重要环节,也是现在大语言模型开发重要基础。计算机程序无法理解文字信息(实际上非数值类型的信息都无法理解),因此我们需要将文字信息转换成计算机程序可理解的数值类型。通俗来说就是我们的算法模型是一系列函数和公式的组合推导,那么变量自然得是数值类型的才能参与计算。因此,这么将文本转换成数值类型的向量的过程就是文本向量化,而转换得到的这个向量又称文本表示。

二、分词

        分词是文本向量化之前的必备步骤,为了让得到的文本表示不会损失太多的语义信息,我们需要有一个良好的分词结果。常见的中文分词库有jieba英文分词库有nltk,这些分词库的原理都是内置一个词典,通过词匹配的方式将词语分隔出来。实际上,英文由于有空格分隔各个单词,分词的步骤较为简单(前提是划分单词而非词组),但由于中文是连续的字符,不依赖词典是无法得到有效的分词结果的(除非按“字”的粒度进行分隔,例如命名实体识别任务)。以中文分词为例:

import jieba

# 示例中文文本
text = "我喜欢学习自然语言处理。"

# 使用jieba进行分词
seg_list = jieba.cut(text)

# 将分词结果转换为列表并打印
print("分词结果:", "/ ".join(seg_list))

        结果如下:

fd002a60796a409ab3bfa7fed3557a83.png

        内置词典的分词器有个弊端就是无法及时更新词典,从而导致对于新词的划分力度不足,例如如今我们倾向于将“大语言模型”作为一个词组,但是直接使用jieba分词的结果可能并不如我们所想:

a08f2226913a4d1c8ca8d238ccc7550c.png

        这时候,我们可以通过手动添加词典的方式进行词库的更新。

jieba.add_word('大语言模型')

4947ac90d0fc42e093103479529fa457.png

三、文本向量化常见方式

1、词袋模型

        词袋模型(Bag-of-Words,BOW)是一种自然语言处理中常用的文本表示方法,它的基本思想是将文本看作一个装着单词的“袋子”,不考虑单词的顺序和语法结构,只关注单词的出现频率。词袋模型的构建过程包括以下几个步骤:

  • 分词:将文本分割成单词或词汇单元。
  • 构建词汇表:从所有文档中提取唯一的单词,形成一个词汇表(这个过程也包括了去停用词等操作)。
  • 特征向量化:对于每个文档,统计出现在词汇表中的每个单词的出现频率,并形成一个特征向量。向量的每个维度对应词汇表中的一个单词,其值表示该单词在文档中的出现次数,未出现则为0(所以是一个及其稀疏的向量)。
  • 模型训练与预测:使用特征向量作为输入,训练机器学习模型,并进行预测。

(1)中文示例

import jieba
from sklearn.feature_extraction.text import CountVectorizer

# 示例中文文本数据
texts = [
    '苹果和梨子是很常见的水果。',
    '我喜欢吃芒果和百香果。',
    '苹果今年推出了新的手机。',
    '华为的新手机拍照性能非常好。'
]

# 使用jieba进行分词
texts_cut = [" ".join(jieba.cut(text)) for text in texts]

# 初始化CountVectorizer对象
vectorizer = CountVectorizer()

# 使用分词后的文本数据训练Vectorizer,即构建词汇表,并返回文档-词汇矩阵
X = vectorizer.fit_transform(texts_cut)

# 获取词汇表
vocabulary = vectorizer.get_feature_names_out()

# 打印词汇表
print("Vocabulary:", vocabulary)

# 打印文档-词汇矩阵
print("Document-term matrix:")
print(X.toarray())

        下面可以看到打印出来的词汇表和向量矩阵,可以发现构建词表的过程中默认会去掉常见的停用词,例如“的”、“和”。同时,文本向量中可以清晰得出词汇表对应词语的出现频次。例如第一句话“苹果和梨子是很常见的水果”对应向量中,第四位“常见”出现了1次,第十位“梨子”和十一位“水果”各出现1次,倒数第二位“苹果”出现了1次。

209d710123a6404182ce3945a6e4e54d.png

(2)英文示例

        由于英文有空格划分单词,因此单词粒度的词汇表构建过程中不需要进行分词即可直接使用词袋模型。

from sklearn.feature_extraction.text import CountVectorizer

# 示例文本数据
texts = [
    "Apple and pear are very common fruits.",
    "I like to eat mango and passion fruit.",
    "Apple has launched a new phone this year.",
    "HuaWei's new phone has excellent camera performance."
]

# 初始化CountVectorizer对象
vectorizer = CountVectorizer()

# 使用文本数据训练Vectorizer,即构建词汇表,并返回文档-词汇矩阵
X = vectorizer.fit_transform(texts)

# 获取词汇表
vocabulary = vectorizer.get_feature_names_out()

# 打印词汇表
print("Vocabulary:", vocabulary)

# 打印文档-词汇矩阵
print("Document-term matrix:")
print(X.toarray())

7fbc2d8cdb854a14a8c8ede21cd720cc.png

        由此可知,词袋模型的缺陷非常明显:首先,它并没有任何语义信息;其次,词汇表的长度决定了词袋向量的长度,如果词汇表有上百万个词语,那么每一个样本的词袋向量也有上百万维,这是不可容忍的。

2、Word2Vec

        Word2Vec由Google在2013年开发,用于生成词嵌入(词语的文本表示)。Word2Vec通过学习单词的上下文关系来生成每个单词的数值向量表示,这些向量能够捕捉单词的语义信息和句法信息,并将单词的语义相似性转化为向量空间中的几何关系。Word2Vec模型的核心思想是:在文本中经常一起出现的单词在向量空间中也会彼此接近。Word2Vec的训练过程如下:

  • 初始化词嵌入:为每个单词分配一个随机向量(向量维度由我们根据任务需要定义)。
  • 构建词汇表:创建一个包含所有单词的词汇表(实际应用中单词数量可选,如仅使用出现频率Top N的单词)。
  • 训练模型:使用文本数据训练模型,通过优化算法(如梯度下降)调整词嵌入向量,以最小化预测误差。
  • 生成词嵌入:训练完成后,每个单词都会有一个固定长度的向量表示。

        此外,Word2Vec有两种学习模式:

(1)CBOW(Continuous Bag of Words)

        CBOW模型的输入是单词的上下文,输出是中心词的预测,即使用周围的单词来预测中间的单词。CBOW模型的目标是最大化给定上下文词时目标词的条件概率,这等价于最小化交叉熵损失。对于CBOW模型,目标函数可以表示为:

eq?L%20%3D%20-%5Csum_%7Bt%3D1%7D%5E%7BT%7D%5Csum_%7Bk%3D1%7D%5E%7BV%7Dt_%7Bt%2Ck%7Dlog%5Chat%7Bp%7D%28w_%7Bk%7D%7Cw_%7Bt-c%7D%2C...%2Cw_%7Bt-1%7D%2Cw_%7Bt+1%7D%2C...%2Cw_%7Bt+c%7D%29

        其中,T是训练集中样本的总数,V是词汇表的大小,eq?w_%7Bk%7D是目标词,eq?w_%7Bt-c%7D%2C...%2Cw_%7Bt-1%7D%2Cw_%7Bt+1%7D%2C...%2Cw_%7Bt+c%7D是上下文词,eq?%5Chat%7Bp%7D%28w_%7Bk%7D%7Cw_%7Bt-c%7D%2C...%2Cw_%7Bt-1%7D%2Cw_%7Bt+1%7D%2C...%2Cw_%7Bt+c%7D%29是在给定上下文的情况下目标词的条件概率。

(2)Skip-Gram

        Skip-Gram模型的输入是中心词,输出是上下文单词的预测,即它使用一个单词来预测周围的单词。Skip-Gram模型的数学公式可以表示为最大化给定目标词的条件下上下文词的出现概率,即最大化下面的目标函数:

eq?L%20%3D%20-%5Csum_%7Bt%3D1%7D%5E%7BT%7D%5Csum_%7B-c%5Cleqslant%20j%5Cleqslant%20c%2Cj%5Cneq%200%7Dlog%5Chat%7Bp%7D%28w_%7Bt+j%7D%7Cw_%7Bt%7D%29

        其中,T是训练集中的样本总数,c是上下文窗口大小,eq?w_%7Bt%7D是目标词,eq?w_%7Bt+j%7D是上下文词,条件概率eq?%5Chat%7Bp%7D%28w_%7Bt+j%7D%7Cw_%7Bt%7D%29可以用softmax函数计算:

eq?%5Chat%7Bp%7D%28w_%7BO%7D%7Cw_%7BI%7D%29%20%3D%20%5Cfrac%7Bexp%28%7Bv%7D%27%5E%7BT%7D_%7Bw_%7Bo%7D%7Dv_%7Bw_%7BI%7D%7D%29%7D%7B%5Csum_%7Bw%3D1%7D%5E%7BW%7Dexp%28%7Bv%7D%27%5E%7BT%7D_%7Bw%7Dv_%7Bw_%7BI%7D%7D%29%7D

        这里,eq?v_%7Bw_%7BI%7D%7Deq?%7Bv%7D%27_%7Bw_%7BO%7D%7D分别是输入词eq?w_%7BI%7D和输出词eq?w_%7BO%7D的向量表示,W是词汇表的大小。

(1)中文示例

import jieba
from gensim.models import Word2Vec

# 示例中文文本数据
texts = [
    '苹果和梨子是很常见的水果。',
    '我喜欢吃芒果和百香果。',
    '苹果今年推出了新的手机。',
    '华为的新手机拍照性能非常好。'
]

# 使用jieba进行分词
texts_cut = [list(jieba.cut(text)) for text in texts]

# 训练Word2Vec模型
# 指定生成的词嵌入维度为30,学习的上下文窗口指定为5,用于构建词汇表的单词出现频次不低于min_count
model = Word2Vec(sentences=texts_cut, vector_size=30, window=5, min_count=1)

# 使用模型
vector = model.wv['梨子']  # 获取单词的向量表示
similar_words = model.wv.most_similar('梨子')  # 找到最相似的词汇

# 打印结果
print("向量表示:", vector)
print("与'梨子'最相似的词汇:", similar_words[:3])

        结果如下,我们指定了向量维度30,并查找模型学习到的词汇语义相似度知识(由于数据量较少模型学习效果欠佳):

8e6818f977da412aa32ba01f62b7ebc9.png

(2)英文示例

import jieba
from gensim.models import Word2Vec

# 示例中文文本数据
texts = [
    "Apple and pear are very common fruits.",
    "I like to eat mango and passion fruit.",
    "Apple has launched a new phone this year.",
    "HuaWei's new phone has excellent camera performance."
]

# 将文本数据分割成单词列表
texts_split = [text.split() for text in texts]

# 训练Word2Vec模型
# 指定生成的词嵌入维度为30,学习的上下文窗口指定为3,用于构建词汇表的单词出现频次不低于min_count
model = Word2Vec(sentences=texts_split, vector_size=30, window=3, min_count=1, epochs=20)

# 使用模型
vector = model.wv['pear']  # 获取单词的向量表示
similar_words = model.wv.most_similar('pear')  # 找到最相似的词汇

# 打印结果
print("向量表示:", vector)
print("与'pear'最相似的词汇:", similar_words[:3])

8b6bcce4f4a24b2289e7c68d1488ecad.png        这里需要注意几个参数:

  • sg:取值为0表示使用CBOW模式,为1表示使用skip-gram模式,默认为0。
  • vector_size:单词向量的维度数,默认100。
  • window:词嵌入训练过程中,句子中当前单词与预测单词的最大距离不能超过该值,默认5。
  • min_count:词汇表构建过程中,忽略总频率低于该值的所有单词,默认5。
  • epochs:迭代次数,默认5。

3、预训练模型

        这里我们使用BERT(Bidirectional Encoder Representations from Transformers)作为示例。Bert是基于Transformer架构的预训练语言模型,它通过预训练的方式学习语言的表示和理解,在多种自然语言处理任务中取得了显著的效果。Bert通过两个主要的任务进行预训练:

  • Masked Language Model(MLM):在MLM任务中,模型需要预测被遮盖(masked)的token,这个任务使得模型去学习token之间的关系以及上下文信息,类似于完形填空。MLM过程中,有15%的token会被随机掩盖,其中80%用[MASK]这个token来代替,10%用一个随机token来替换,10%保持原token不变。
  • Next Sentence Prediction(NSP):在NSP任务中,模型需要判断两句话是否为连续的上下文句子,这个任务让模型能够理解句子之间的逻辑关系(虽然后面的研究发现这个任务对于Bert性能的提升并无太大作用,更多还是MLM给它带来的能力)。

(1)中文示例

from transformers import BertTokenizer, BertModel
import torch

# 这是一个基础版本的bert中文模型,如果需要更强大的、在特定任务中微调过的模型,可以去HuggingFace查找
# 预训练模型同样依赖自身的词典进行分词,而在bert-base-chinese这个模型中,对中文的分词粒度是字,也就是按照字的粒度划分中文文本,有一些模型是按照词粒度进行中文分词的,这个同样可以到HF上去查找
model_name = 'bert-base-chinese'
# 初始化分词器
tokenizer = BertTokenizer.from_pretrained(model_name)
# 加载模型
model = BertModel.from_pretrained(model_name)

texts = ['苹果和梨子是很常见的水果。', '我喜欢吃芒果和百香果。', '苹果今年推出了新的手机。', '华为的新手机拍照性能非常好。']

# 分词器生成Bert模型必要的输入格式
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
# 禁用梯度,打开预测模式
with torch.no_grad():
    # 预测输出
    outputs = model(**inputs)

# 取最后一层的token平均向量
print('向量维度:')
print(sentence_embeddings.shape)
sentence_embeddings = outputs.pooler_output
print(sentence_embeddings)

63432db94ce44e98b2b63adb38598106.png

(2)英文示例

from transformers import BertTokenizer, BertModel
import torch

# 同样,可以去HuggingFace找更强大的模型
model_name = 'bert-base-uncased'

# 初始化分词器
tokenizer = BertTokenizer.from_pretrained(model_name)
# 加载模型
model = BertModel.from_pretrained(model_name)

texts = ["Apple and pear are very common fruits.", "I like to eat mango and passion fruit.", "Apple has launched a new phone this year.", "HuaWei's new phone has excellent camera performance."]

# 分词器生成Bert必要的输出格式
inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt")
# 禁用梯度,打开预测模式
with torch.no_grad():
    # 预测输出
    outputs = model(**inputs)

# 取最后一层的token平均向量
sentence_embeddings = outputs.pooler_output
print('向量维度:')
print(sentence_embeddings.shape)
print('文本向量:')
print(sentence_embeddings)

376a5070328b429e966f53a4ae21619c.png

        可见,Bert生成的向量维度默认为768维。

四、总结

        目前,对于文本向量化的任务,基本都会使用大型预训练模型了,这是由于它们最大程度保留了文本的原始语义,在诸多任务中表现良好。此外,传统的模型如Word2Vec对同一个单词的向量化表示是相同的,但我们知道同一个词在不同语境下应当有不同的含义。预训练模型结合了上下文进行文本表示,从而使得同一个词在不同语境下有不同的表征,这就是最明显的优势。例如,下面是第一句话中表示水果的Apple和第三句话中表示手机品牌的Apple的Bert文本表示截取,二者之间有着明显区别:

(1)水果“Apple”的向量:

b58f482680c241a6ac17b27c728761f1.png

(2)手机“Apple”的向量

2927fb54db0041ab8ae65ccde95203b9.png

        关于预训练模型的内容笔者后续会逐一详解。

 

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

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

相关文章

Python 精品学习资料收藏下载,Python 字符串处理备忘单

重点在这: (请移步图中作者处,获取高清大图下载链接) Python 中的字符串(String)是一种用于表示文本的数据类型。字符串是不可变的,这意味着一旦创建,你不能改变字符串中的字符&am…

【学习AI-相关路程-mnist手写数字分类-python-硬件:jetson orin NX-自我学习AI-基础知识铺垫-遇到问题(1) 】

【学习AI-相关路程-mnist手写数字分类-python-硬件:jetson orin NX-自我学习AI-基础知识铺垫-遇到问题(1) 】 1、前言2、先行了解(1)学习基础知识-了解jetson orin nx 设备(2)学习python&AI…

ClickHouse在百度MEG数据中台的落地和优化

导读 百度MEG上一代大数据产品存在平台分散、质量不均和易用性差等问题,导致开发效率低下、学习成本高,业务需求响应迟缓。为了解决这些问题,百度MEG内部开发了图灵3.0生态系统,包括Turing Data Engine(TDE)计算引擎、Turing Dat…

从0到1,搭建vue3项目

一 Vite创建Vue3项目 1.1.创建Vue3项目 1.1.1.运行创建项目命令 # 使用 npm npm create vitelatest 1.1.2、填写项目名称 1.1.3、选择前端框架 1.1.4、选择语法类型 1.1.5、按提示运行代码 1.1.6浏览器问 localhost:5173 预览 1.2项目结构 1.2.1vite.config.ts 1.2.2 pac…

基于线性回归(Linear Regression)的房屋价格预测

基于线性回归(Linear Regression)的房屋价格预测 一元线性回归加载数据假设函数损失函数(代价函数)梯度下降函数完整代码 多变量线性回归加载数据集特征缩放假设函数损失函数梯度下降函数算法步骤完整代码 线性回归是统计学中的一…

【二轮征稿启动】第三届环境工程与可持续能源国际会议持续收录优质稿件

第三届环境工程与与可持续能源国际会议(EESE 2024)由中南林业科技大学主办,湖南农业大学协办,将于2024年12月20日-22日在湖南长沙召开。 大会邀请到国家杰出青年科学基金获得者、华中科技大学能源与动力工程学院冯光教授&#xf…

R实验——logistic回归、LDA、QDAKNN

数据集介绍: mpg,miles per gallon即油耗,这个数据集来自卡内基梅隆大学维护的StatLib库。1983年美国统计协会博览会使用了该数据集。这个数据集是对StatLib库中提供的数据集稍加修改的版本。根据Ross Quinlan(1993)在预测属性“mpg”中的使…

计算机网络原理总结C-网络层

网络层 网络层提供的两种服务网际协议IP 虚拟互连网络IP地址子网掩码(无分类编址CIDR)IP地址和MAC地址IP数据报格式(路由)转发分组的流程 因特网的路由选择协议(动态路由协议) 网际控制报文协议ICMPIP多播…

认识CSS语法

CSS(网页美容) 重点:选择器、盒子模型、浮动、定位、动画,伸缩布局 Css的作用: 美化网页:CSS控制标签的样式 网页布局:CSS控制标签的位置 概念:层叠样式表(级联样式表…

UE5 第一人称示例代码阅读0 UEnhancedInputComponent

UEnhancedInputComponent使用流程 我的总结示例分析firstthenand thenfinally&代码关于键盘输入XYZ 我的总结 这个东西是一个对输入进行控制的系统,看了一下第一人称例子里,算是看明白了,但是感觉这东西使用起来有点绕,特此梳…

布隆过滤器:极简存储,高效检索

引言 在海量数据的存储与检索中,如何在保持快速检索的同时,降低内存占用是个巨大的挑战。有没有一种既能快速检索又能节省内存的方案?布隆过滤器(Bloom Filter)就是这样一种数据结构。 布隆过滤器的基本原理 如果我…

数据库、数据仓库、数据湖和数据中台有什么区别

很多企业在面对数据存储和管理时不知道如何选择合适的方式,数据库、数据仓库、数据湖和数据中台,这些方式都是什么?有什么样的区别?企业根据其业务类型该选择哪一种?本文就针对这些问题,来探讨下这些方式都…

【目标检测01】真实框、预测框、锚框和交并比IoU

文章目录 1. 任务定义2. 基本概念2.1 边界框(bounding box)2.2 真实框、预测框和锚框2.3 交并比 (IoU)2.4 代码实现 1. 任务定义 目标检测的主要目的是让计算机可以自动识别图片或者视频帧中所有目标的类别,并在该目标周围绘制边界框&#x…

【linux网络编程】| 网络基础 | 解析IP与Mac地址的区别

前言:本节内容讲解一些网络基础相关的知识点, 不涉及网络代码!同样的本节内容是作为前一篇的补充知识点, 前一篇文章地址:【linux网络编程】 | 网络基础Ⅰ| 认识网络-CSDN博客,本篇文章内容较少&#xff0c…

命名空间std, using namespace std

命名空间std&#xff0c;using namespace std 在标准C以前&#xff0c;都是用#include<iostream.h>这样的写法的&#xff0c;因为要包含进来的头文件名就是iostream.h。标准C引入了名字空间的概念&#xff0c;并把iostream等标准库中的东东封装到了std名字空间中&#x…

UE5 源码学习 初始化

跟着 https://www.cnblogs.com/timlly/p/13877623.html 学习 入口函数 UnrealEngine\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp WinMain 入口 int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ char* p…

unity开发之可视化制作动画

录制动画 1&#xff09;打开录制动画页面&#xff08;或者按快捷键ctrl6&#xff09; 2&#xff09;选中需要录制动画的对象 3&#xff09;创建动画列表&#xff0c;注意现在还没有录制动画&#xff0c;我这里创建了开门和关门动画列表 4&#xff09;选择需要录制动画的对象的相…

【计网】UDP Echo Server与Client实战:从零开始构建简单通信回显程序

目录 前言&#xff1a; 1.实现udpserver类 1.1.创建udp socket 套接字 --- 必须要做的 socket&#xff08;&#xff09;讲解 代码实现&#xff1a;​编辑 代码讲解&#xff1a; 1.2.填充sockaddr_in结构 代码实现&#xff1a; 代码解析&#xff1a; 1.3.bind sockfd和…

关于在vue2中接受后端返回的二进制流并进行本地下载

后端接口返回&#xff1a; 前端需要在两个地方写代码&#xff1a; 1.封装接口处&#xff0c;responseType: blob 2.接收相应处 download() {if (this.selectionList.length 0) {this.$message.error("请选择要导出的数据&#xff01;");} else {examineruleExport…

【Git】将本地代码提交到github仓库

一、创建仓库 复制这里的HTTP连接码 二、仓库初始化 进入你要提交的代码文件夹 右键选择 Git Bach Here 输入命令 git clone [HTTP连接码] 此时文件夹里会出现一个新的文件夹&#xff0c;将原来的文件当今这个新的文件夹 三、上传代码 执行命令 cd [新文件夹] 将所有文件放…