当前位置: 首页 > news >正文

【NLP】文本预处理

目录

一、文本处理的基本方法

1.1 分词

1.2 命名体实体识别

1.3 词性标注 

二、文本张量的表示形式

2.1 one-hot编码

2.2 word2vec 模型

2.2.1 CBOW模式

2.2.2 skipgram模式

2.3 词嵌入word embedding

三、文本数据分析

3.1 标签数量分布

3.2 句子长度分布

3.3 词频统计与关键词词云

四、文本特征处理

4.1 n-gram特征

4.2 文本长度规范

五、文本数据增强


文本语料在输送给模型前一般需要一系列的预处理工作,才能符合模型输入的要求,如:将文本转化成模型需要的张量,规范张量的尺寸等,而且科学的文本预处理环节还将有效指导模型超参数的选择,提升模型的评估指标

一、文本处理的基本方法

1.1 分词

分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,分词过程就是找到这样分界符的过程

无线电法国别研究
['无线电法', '国别', '研究']

词作为语言语义理解的最小单元,是人类理解文本语言的基础。因此也是AI解决NLP领域高阶任务,如自动问答、机器翻译、文本生成的重要基础环节

  • 精确模式分词:试图将句子最精确地切开,适合文本分析
  • 全模式分词:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能消除歧义
  • 搜索引擎模式分词:在精确模式基础上,对长词再次切分,提高召回率,适合搜索引擎分词
import jieba# 精确模式
def test01():text = '无线电法国别研究'# cut_all默认为Falseobj = jieba.cut(text, cut_all=False)print(obj)# <generator object Tokenizer.cut at 0x0000019CB8CDC148># lcut直接返回分词列表内容words = jieba.lcut(text, cut_all=False)print(words)# ['无线电', '法国', '别', '研究']# 全模式分词
def test02():text = '无线电法国别研究'obj = jieba.cut(text, cut_all=True)print(obj)# <generator object Tokenizer.cut at 0x000001E6304AC148>words = jieba.lcut(text, cut_all=True)print(words)# ['无线', '无线电', '法国', '国别', '研究']# 搜索引擎模式分词
def test03():text = '无线电法国别研究'obj = jieba.cut_for_search(text)print(obj)# <generator object Tokenizer.cut_for_search at 0x000001CCE75DA748>words = jieba.lcut_for_search(text)print(words)# ['无线', '无线电', '法国', '别', '研究']if __name__ == '__main__':# test01()# test02()test03()

使用用户自定义词典

  • 添加自定义词典后,jieba能够准确识别词典中出现的词汇,提升整体的识别准确率
  • 词典格式:一行分三部分,词语、词频(可略)、词性(可略),空格隔开,顺序不可颠倒
云计算 5 n
李小福 2 nr
easy_install 3 eng
好用 300
韩玉赏鉴 3 nz
八一双鹿 3 nz
import jiebadef main():text = "八一双鹿更名为八一南昌篮球队!"# 精确模式words = jieba.lcut(text)print(words)# ['八', '一双', '鹿', '更名', '为', '八一', '南昌', '篮球队', '!']# 自定义词表jieba.load_userdict("./data/userdict.txt")words = jieba.lcut(text)print(words)# ['八一双鹿', '更名', '为', '八一', '南昌', '篮球队', '!']if __name__ == '__main__':main()

1.2 命名体实体识别

  1. 命名实体:通常将人名、地名、机构名等专有名词统称命名实体.。如:周杰伦、黑山县、孔子学院、24辊方钢矫直机
  2. 命名实体识别(Named Entity Recognition,简称NER)就是识别出一段文本中可能存在的命名实体
鲁迅, 浙江绍兴人, 五四新文化运动的重要参与者, 代表作朝花夕拾.
==>
鲁迅(人名) / 浙江绍兴(地名)人 / 五四新文化运动(专有名词) / 重要参与者 / 代表作 / 朝花夕拾(专有名词)

同词汇一样,命名实体也是人类理解文本的基础单元,是AI解决NLP领域高阶任务的重要基础环节

1.3 词性标注 

  • 语言中对词的一种分类方法,以语法特征为主要依据、兼顾词汇意义对词进行划分的结果,常见的词性有14种,如:名词、动词、形容词等
  • 词性标注(Part-Of-Speech tagging,简称POS)就是标注出一段文本中每个词汇的词性
我爱自然语言处理
==>
我/rr, 爱/v, 自然语言/n, 处理/vnrr: 人称代词
v: 动词
n: 名词
vn: 动名词

词性标注以分词为基础,是对文本语言的另一个角度的理解,因此也常常成为AI解决NLP领域高阶任务的重要基础环节

import jieba.posseg as psegdef main():text = '我爱北京天安门'words = pseg.lcut(text)print(words)# [pair('我', 'r'), pair('爱', 'v'), pair('北京', 'ns'), pair('天安门', 'ns')]if __name__ == '__main__':main()

二、文本张量的表示形式

将一段文本使用张量进行表示,其中一般将词汇为表示成向量,称作词向量,再由各个词向量按顺序组成矩阵形成文本表示

["人生", "该", "如何", "起头"]
==>
# 每个词对应矩阵中的一个向量
[[1.32, 4,32, 0,32, 5.2],[3.1, 5.43, 0.34, 3.2],[3.21, 5.32, 2, 4.32],[2.54, 7.32, 5.12, 9.54]]

将文本表示成张量(矩阵)形式,能够使语言文本可以作为计算机处理程序的输入,进行接下来一系列的解析工作

2.1 one-hot编码

独热编码,将每个词表示成具有n个元素的向量,这个词向量中只有一个元素是1,其他元素都是0,不同词汇元素为0的位置不同,其中n的大小是整个语料中不同词汇的总数

["改变", "要", "如何", "起手"]
==>
[[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, 1]]

onehot 编码实现: 

import joblib
from keras.preprocessing.text import Tokenizervocab = {"周杰伦", "陈奕迅", "王力宏", "李宗盛", "吴亦凡", "鹿晗"}
# 实例化一个词汇映射器对象
tokenizer = Tokenizer(num_words=None, char_level=False)
# 使用映射器拟合现有文本数据
tokenizer.fit_on_texts(vocab)for token in vocab:zero_list = [0] * len(vocab)# 使用映射器转化现有文本数据, 每个词汇对应从1开始的自然数# 返回样式如: [[2]], 取出其中的数字需要使用[0][0]index = tokenizer.texts_to_sequences([token])[0][0] - 1zero_list[index] = 1print(token, '的one-hot编码是:', zero_list)# 使用joblib工具保存映射器, 以便之后使用
tokenizer_path = "./data/Tokenizer"
joblib.dump(tokenizer, tokenizer_path)# 李宗盛 的one-hot编码是: [1, 0, 0, 0, 0, 0]
# 周杰伦 的one-hot编码是: [0, 1, 0, 0, 0, 0]
# 王力宏 的one-hot编码是: [0, 0, 1, 0, 0, 0]
# 陈奕迅 的one-hot编码是: [0, 0, 0, 1, 0, 0]
# 吴亦凡 的one-hot编码是: [0, 0, 0, 0, 1, 0]
# 鹿晗 的one-hot编码是: [0, 0, 0, 0, 0, 1]

one-hot 编码器的使用:

import joblibvocab = {"周杰伦", "陈奕迅", "王力宏", "李宗盛", "吴亦凡", "鹿晗"}
tokenizer_path = "./data/Tokenizer"
tokenizer = joblib.load(tokenizer_path)token = '李宗盛'
# 使用 token 获取 token_index
index = tokenizer.texts_to_sequences([token])[0][0] - 1
# 得到 one-hot 编码
zero_list = [0] * len(vocab)
zero_list[index] = 1
print(token, '的one-hot编码是:', zero_list)
# 李宗盛 的one-hot编码是: [1, 0, 0, 0, 0, 0]

one-hot 编码的优劣势:

  • 优势:操作简单,容易理解
  • 劣势:完全割裂了词与词之间的联系,在大语料集下,每个向量的长度过大,占据大量内存
  • 因为one-hot编码明显的劣势,这种编码方式被应用的地方越来越少,取而代之的是稠密向量的表示方法 word2vec 和 word embedding

2.2 word2vec 模型

word2vec 是一种流行的将词汇表示成向量的无监督训练方法,该过程将构建神经网络模型,将网络参数作为词汇的向量表示,包含 CBOW 和 skipgram 两种训练模式

2.2.1 CBOW模式

Continuous bag of words

给定一段文本语料,再选定某段长度(窗口)作为研究对象,使用上下文词汇预测目标词汇

上图中窗口大小为9,使用前后4个词汇对目标词汇进行预测

过程详解

假设给定的训练语料只有一句话:Hope can set you free (愿你自由成长),窗口大小为3,因此模型的第一个训练样本来自Hope can set,因为是CBOW模式,所以将使用Hope和set作为输入,can作为输出。在模型训练时, Hope,can,set 等词汇都使用其 one-hot 编码。输入数据的每个 one-hot 编码(5*1)与各自的变换矩阵(即参数矩阵3*5,这里的 3 是指最后得到的词向量维度)相乘之后再相加,得到上下文表示矩阵(3*1)

将上下文表示矩阵与变换矩阵(参数矩阵 5*3,所有的变换矩阵共享参数)相乘,得到 5*1 的结果矩阵,结果矩阵与目标矩阵即 can 的 one-hot 编码矩阵 (5*1) 进行损失的计算,然后更新网络参数完成一次模型迭代

2.2.2 skipgram模式

给定一段用于训练的文本语料,再选定某段长度(窗口)作为研究对象,使用目标词汇预测上下文词汇

图中窗口大小为9,使用目标词汇对前后四个词汇进行预测

过程详解

假设给定的训练语料只有一句话:Hope can set you free (愿你自由成长),窗口大小为3,因此模型的第一个训练样本来自Hope can set。因为是skipgram模式,所以将使用can作为输入 ,Hope和set作为输出,在模型训练时 Hope,can,set 等词汇都使用其 one-hot 编码。将 can 的 one-hot 编码与变换矩阵(即参数矩阵3*5,3是指最后得到的词向量维度)相乘,得到目标词汇表示矩阵(3*1)

将目标词汇表示矩阵与多个变换矩阵(参数矩阵5*3)相乘,得到多个 5*1 的结果矩阵,将与 Hope 和 set 对应的 one-hot 编码矩阵(5*1)进行损失计算, 然后更新网络参数完成一次模型迭代

最后窗口按序向后移动,重新更新参数,直到所有语料被遍历完成,得到最终的变换矩阵即参数矩阵(3*5),这个变换矩阵与每个词汇的one-hot编码(5*1)相乘,得到的3x1的矩阵就是该词汇的 word2vec 张量表示

2.3 词嵌入word embedding

  • 通过一定的方式将词汇映射到指定维度(一般是更高维度)的空间
  • 广义的 word embedding 包括所有密集词汇向量的表示方法,如之前学习的 word2vec 可认为是 word embedding 的一种
  • 狭义的 word embedding 是指在神经网络中加入的 embedding 层,对整个网络进行训练的同时产生的 embedding 矩阵(embedding层的参数),这个 embedding 矩阵就是训练过程中所有输入词汇的向量表示组成的矩阵

词嵌入层会根据输入的词的数量构建一个词向量矩阵。如:有 100 个词,每个词希望转换成 128 维度的向量,那么构建的矩阵形状即为100 * 128,输入的每个词都对应了矩阵中的一个向量

在 PyTorch 中,可以使用 nn.Embedding 词嵌入层来实现输入词的向量化

  • 先将语料进行分词,构建词与索引的映射,可以将这个映射称为词表,词表中每个词都对应了一个唯一的索引
  • 然后使用 nn.Embedding 构建词嵌入矩阵,词索引对应的向量即为该词对应的数值化后的向量表示

nn.Embedding 对象构建时,最主要有两个参数:

  • num_embeddings 表示词的数量
  • embedding_dim 表示用多少维的向量来表示每个词
import torch
import torch.nn as nn
import jiebadef main():text = '北京冬奥的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途。'# 1. 分词words = jieba.lcut(text)print('words:', words)# 2. 构建词表index_to_word = {}word_to_index = {}# 分词去重unique_words = list(set(words))for idx, word in enumerate(unique_words):index_to_word[idx] = wordword_to_index[word] = idx# 3.构建词嵌入层# num_embeddings为词的数量,embedding_dim为词嵌入的维度embedding = nn.Embedding(num_embeddings=len(index_to_word), embedding_dim=4)# 4.文本转为词向量表示for word in words:idx = word_to_index[word]word_vector = embedding(torch.tensor(idx))print('%3s\t' % word, word_vector)if __name__ == "__main__":main()
words: ['北京', '冬奥', '的', '进度条', '已经', '过半', ',', '不少', '外国', '运动员', '在', '完成', '自己', '的', '比赛', '后', '踏上', '归途', '。']北京    tensor([1.1339, 1.1262, 0.6638, 1.5691], grad_fn=<EmbeddingBackward0>)冬奥    tensor([0.2753, 0.3262, 1.7691, 1.2225], grad_fn=<EmbeddingBackward0>)的     tensor([-0.7507,  1.8850,  1.4340, -0.8074], grad_fn=<EmbeddingBackward0>)
进度条   tensor([ 0.5693, -0.0951, -0.4607,  0.0555], grad_fn=<EmbeddingBackward0>)已经    tensor([-0.5726,  0.0812,  1.1051, -0.0020], grad_fn=<EmbeddingBackward0>)过半    tensor([0.0691, 0.1430, 1.9346, 1.4653], grad_fn=<EmbeddingBackward0>),     tensor([-1.1009,  0.7833, -0.9021,  1.8811], grad_fn=<EmbeddingBackward0>)不少    tensor([ 0.7913,  0.0890, -0.7459,  1.1473], grad_fn=<EmbeddingBackward0>)外国    tensor([-0.6079,  0.2563,  0.8344, -0.5977], grad_fn=<EmbeddingBackward0>)
运动员   tensor([-1.9587,  0.0995, -1.0728, -0.2779], grad_fn=<EmbeddingBackward0>)在     tensor([-1.6571, -1.2508, -0.8138, -2.6821], grad_fn=<EmbeddingBackward0>)完成    tensor([-1.4124, -0.5624,  1.2548,  0.1708], grad_fn=<EmbeddingBackward0>)自己    tensor([-2.5485, -0.1839, -0.0079,  0.1326], grad_fn=<EmbeddingBackward0>)的     tensor([-0.7507,  1.8850,  1.4340, -0.8074], grad_fn=<EmbeddingBackward0>)比赛    tensor([ 0.3826, -1.8883,  0.5677,  0.1951], grad_fn=<EmbeddingBackward0>)后     tensor([ 0.2585, -1.2181,  1.0165, -0.4775], grad_fn=<EmbeddingBackward0>)踏上    tensor([-1.6933,  1.2826,  0.9993, -0.2306], grad_fn=<EmbeddingBackward0>)归途    tensor([ 3.8709,  0.5133,  0.1683, -0.9699], grad_fn=<EmbeddingBackward0>)。     tensor([-0.9352, -1.2663, -1.5860, -0.2301], grad_fn=<EmbeddingBackward0>)

词嵌入层默认使用的是均值为 0,标准差为 1 的正态分布进行初始化,也可以理解为是随机初始化。这个用来表示词的文本真的能够表达出词的含义吗?

nn.Embedding 中对每个词的向量表示都是随机生成的,当一个词输入进来后,会使用随机产生的向量来表示该词。该词向量参与到下游任务的计算,下游任务计算后,会和目标结果进行对比产生损失。接下来,通过反向传播更新所有的网络参数,就包括了 nn.Embedding 中的词向量表示。这样通过反复的前向计算、反向传播、参数更新,最终每个词的向量表示就会变得更合理

三、文本数据分析

文本数据分析能够有效帮助理解数据语料,快速检查出语料可能存在的问题,并指导之后模型训练过程中一些超参数的选择

后续文章中采用中文酒店评论语料来讲解

sentence    label
早餐不好,服务不到位,晚餐无西餐,早餐晚餐相同,房间条件不好,餐厅不分吸烟区.房间不分有无烟房.    0
去的时候 ,酒店大厅和餐厅在装修,感觉大厅有点挤.由于餐厅装修本来该享受的早饭,也没有享受(他们是8点开始每个房间送,但是我时间来不及了)不过前台服务员态度好!    1
有很长时间没有在西藏大厦住了,以前去北京在这里住的较多。这次住进来发现换了液晶电视,但网络不是很好,他们自己说是收费的原因造成的。其它还好。  1
非常好的地理位置,住的是豪华海景房,打开窗户就可以看见栈桥和海景。记得很早以前也住过,现在重新装修了。总的来说比较满意,以后还会住   1
交通很方便,房间小了一点,但是干净整洁,很有香港的特色,性价比较高,推荐一下哦 1
酒店的装修比较陈旧,房间的隔音,主要是卫生间的隔音非常差,只能算是一般的    0
酒店有点旧,房间比较小,但酒店的位子不错,就在海边,可以直接去游泳。8楼的海景打开窗户就是海。如果想住在热闹的地带,这里不是一个很好的选择,不过威海城市真的比较小,打车还是相当便宜的。晚上酒店门口出租车比较少。   1
位置很好,走路到文庙、清凉寺5分钟都用不了,周边公交车很多很方便,就是出租车不太爱去(老城区路窄爱堵车),因为是老宾馆所以设施要陈旧些,    1
酒店设备一般,套房里卧室的不能上网,要到客厅去。    0
...

第一列数据代表具有感情色彩的评论文本,第二列数据 0 或 1,代表每条文本数据是积极或者消极的评论,0代表消极,1代表积极

3.1 标签数量分布

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt# 设置显示风格
plt.style.use('fivethirtyeight')# 分别读取训练tsv和验证tsv
train_data = pd.read_csv("data/cn_data/train.tsv", sep="\t")
valid_data = pd.read_csv("data/cn_data/dev.tsv", sep="\t")# 获得训练数据标签数量分布
sns.countplot(x="label", data=train_data)
plt.title("train_data")
plt.show()# 获取验证数据标签数量分布
sns.countplot(x="label", data=valid_data)
plt.title("valid_data")
plt.show()

在深度学习模型评估中,一般使用ACC作为评估指标,若想将ACC的基线定义在50%左右(随机猜测的准确率是 50%),则需要正负样本比例维持在1:1左右,否则就要进行必要的数据增强或数据删减。上图中训练和验证集正负样本都稍有不均衡,可以进行一些数据增强

3.2 句子长度分布

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt# 设置显示风格
plt.style.use('fivethirtyeight')# 分别读取训练tsv和验证tsv
train_data = pd.read_csv("data/cn_data/train.tsv", sep="\t")
valid_data = pd.read_csv("data/cn_data/dev.tsv", sep="\t")# 在训练数据中添加新的句子长度列, 每个元素的值都是对应的句子列的长度
train_data["sentence_length"] = list(map(lambda x: len(x), train_data["sentence"]))
# 在验证数据中添加新的句子长度列, 每个元素的值都是对应的句子列的长度
valid_data["sentence_length"] = list(map(lambda x: len(x), valid_data["sentence"]))# 绘制句子长度列的数量分布图
sns.countplot(x="sentence_length", data=train_data)
# 主要关注count长度分布的纵坐标, 不需要绘制横坐标, 横坐标范围通过dist图进行查看
plt.xticks([])
plt.show()
# 绘制dist长度分布图
sns.distplot(train_data["sentence_length"])
# 主要关注dist长度分布横坐标, 不需要绘制纵坐标
plt.yticks([])
plt.show()# 绘制句子长度列的数量分布图
sns.countplot(x="sentence_length", data=valid_data)
# 主要关注count长度分布的纵坐标, 不需要绘制横坐标, 横坐标范围通过dist图进行查看
plt.xticks([])
plt.show()
# 绘制dist长度分布图
sns.distplot(valid_data["sentence_length"])
# 主要关注dist长度分布横坐标, 不需要绘制纵坐标
plt.yticks([])
plt.show()

 训练集句子长度分布:

验证集句子长度分布:

通过绘制句子长度分布图,可以得知语料中大部分句子长度的分布范围,因为模型的输入要求为固定尺寸的张量,合理的长度范围对之后进行句子截断补齐(规范长度)起到关键的指导作用。上图中大部分句子长度的范围大致为20-250之间

获取正负样本长度散点分布

# 绘制训练集长度分布的散点图
sns.stripplot(y='sentence_length', x='label', data=train_data)
plt.show()# 绘制验证集长度分布的散点图
sns.stripplot(y='sentence_length', x='label', data=valid_data)
plt.show()

训练集上正负样本的长度散点分布:

验证集上正负样本的长度散点分布:

通过查看正负样本长度散点图,可以有效定位异常点的出现位置,能更准确进行人工语料审查。上图中在训练集正样本中出现了异常点,句子长度近3500左右,需要人工审查

3.3 词频统计与关键词词云

不同词汇总数统计

import jieba
import pandas as pd
# 导入chain方法用于扁平化列表
from itertools import chain# 分别读取训练tsv和验证tsv
train_data = pd.read_csv("data/cn_data/train.tsv", sep="\t")
valid_data = pd.read_csv("data/cn_data/dev.tsv", sep="\t")# 进行训练集的句子进行分词, 并统计出不同词汇的总数
train_vocab = set(chain(*map(lambda x: jieba.lcut(x), train_data["sentence"])))
print("训练集共包含不同词汇总数为:", len(train_vocab))# 进行验证集的句子进行分词, 并统计出不同词汇的总数
valid_vocab = set(chain(*map(lambda x: jieba.lcut(x), valid_data["sentence"])))
print("训练集共包含不同词汇总数为:", len(valid_vocab))# 训练集共包含不同词汇总数为: 12162
# 训练集共包含不同词汇总数为: 6857

获取高频形容词词云

import jieba.posseg as pseg
import pandas as pd
import matplotlib.pyplot as plt
# 导入绘制词云的工具包
from wordcloud import WordCloud
# 导入chain方法用于扁平化列表
from itertools import chaindef get_a_list(text):"""用于获取形容词列表"""# 使用jieba的词性标注方法切分文本,获得具有词性属性flag和词汇属性word的对象# 从而判断flag是否为形容词,来返回对应的词汇r = []for g in pseg.lcut(text):if g.flag == "a":r.append(g.word)return rdef get_word_cloud(keywords_list):# 实例化绘制词云的类, 其中参数font_path是字体路径, 为了能够显示中文,# max_words指词云图像最多显示多少个词, background_color为背景颜色wordcloud = WordCloud(font_path="./data/SimHei.ttf", max_words=100, background_color="white")# 将传入的列表转化成词云生成器需要的字符串形式keywords_string = " ".join(keywords_list)# 生成词云wordcloud.generate(keywords_string)# 绘制图像并显示plt.figure()plt.imshow(wordcloud, interpolation="bilinear")plt.axis("off")plt.show()# 分别读取训练tsv和验证tsv
train_data = pd.read_csv("data/cn_data/train.tsv", sep="\t")
valid_data = pd.read_csv("data/cn_data/dev.tsv", sep="\t")# 获得训练集上正样本
p_train_data = train_data[train_data["label"] == 1]["sentence"]
# 获得训练集上负样本
n_train_data = train_data[train_data["label"] == 0]["sentence"]
# 获得验证集上正样本
p_valid_data = valid_data[valid_data["label"] == 1]["sentence"]
# 获得验证集上负样本
n_valid_data = valid_data[valid_data["label"] == 0]["sentence"]# 对训练集正样本的每个句子的形容词
train_p_a_vocab = chain(*map(lambda x: get_a_list(x), p_train_data))
#print(train_p_n_vocab)
# 获取训练集负样本的每个句子的形容词
train_n_a_vocab = chain(*map(lambda x: get_a_list(x), n_train_data))
# 对验证集正样本的每个句子的形容词
valid_p_a_vocab = chain(*map(lambda x: get_a_list(x), p_valid_data))
#print(train_p_n_vocab)
# 获取验证集负样本的每个句子的形容词
valid_n_a_vocab = chain(*map(lambda x: get_a_list(x), n_valid_data))# 调用绘制词云函数
get_word_cloud(train_p_a_vocab)
get_word_cloud(train_n_a_vocab)
get_word_cloud(valid_p_a_vocab)
get_word_cloud(valid_n_a_vocab)

训练集正样本形容词词云:

训练集负样本形容词词云:

验证集正样本形容词词云:

验证集负样本形容词词云:

根据高频形容词词云显示,可以对当前语料质量进行简单评估,同时对违反语料标签含义的词汇进行人工审查和修正,来保证绝大多数语料符合训练标准。上图中的正样本大多数是褒义词,而负样本大多数是贬义词,但是负样本词云中也存在"好"这样的褒义词,因此可以人工进行审查

四、文本特征处理

文本特征处理包括为语料添加具有普适性的文本特征,如:n-gram特征,以及对加入特征之后的文本语料进行必要的处理,如:长度规范。这些特征处理工作能够有效的将重要的文本特征加入模型训练中,增强模型评估指标

4.1 n-gram特征

给定一段文本序列,其中n个词或字的相邻共现特征即 n-gram 特征,常用的 n-gram 特征是 bi-gram 和 tri-gram 特征,分别对应n为2和3

假设给定分词列表: ["是谁", "敲动", "我心"]对应的数值映射列表为: [1, 34, 21]可以认为数值映射列表中的每个数字是词汇特征除此之外, 还可以把"是谁"和"敲动"两个词共同出现且相邻也作为一种特征加入到序列列表中假设1000就代表"是谁"和"敲动"共同出现且相邻此时数值映射列表就变成了包含 2-gram 特征的特征列表: [1, 34, 21, 1000]这里的"是谁"和"敲动"共同出现且相邻就是bi-gram特征中的一个"敲动"和"我心"也是共现且相邻的两个词汇, 因此也是 bi-gram 特征假设1001代表"敲动"和"我心"共同出现且相邻那么, 最后原始的数值映射列表 [1, 34, 21] 添加了bi-gram特征之后就变成了 [1, 34, 21, 1000, 1001]

提取n-gram特征

n_gram_range = 2def create_n_gram_set(input_list):"""description: 从数值列表中提取所有的 n-gram 特征:param input_list: 输入的数值列表, 可以看作是词汇映射后的列表,里面每个数字的取值范围为[1, 25000]:return: n-gram特征组成的集合>>> create_ngram_set([1, 4, 9, 4, 1, 4]){(4, 9), (4, 1), (1, 4), (9, 4)}"""return set(zip(*[input_list[i:] for i in range(n_gram_range)]))input_list = [1, 3, 2, 1, 5, 3]
result = create_n_gram_set(input_list)
print(result)
# {(3, 2), (1, 3), (2, 1), (1, 5), (5, 3)}

4.2 文本长度规范

一般模型的输入需要等尺寸大小的矩阵,因此在进入模型前需要对每条文本数值映射后的长度进行规范,此时将根据句子长度分布分析出覆盖绝大多数文本的合理长度,对超长文本进行截断, 对不足文本进行补齐(一般使用数字0),这个过程就是文本长度规范

from keras.utils import pad_sequences
text_length = 10def padding_cut(data):"""description: 对输入文本张量进行长度规范:param x_train: 文本的张量表示, 形如: [[1, 32, 32, 61], [2, 54, 21, 7, 19]]:return: 进行截断补齐后的文本张量表示"""# 使用pad_sequences即可完成return pad_sequences(data, text_length)data = [[1, 23, 5, 32, 55, 63, 2, 21, 78, 32, 23, 1], [2, 32, 1, 23, 1]]
res = padding_cut(data)
print(res)
# [[ 5 32 55 63  2 21 78 32 23  1]
#  [ 0  0  0  0  0  2 32  1 23  1]]

五、文本数据增强

回译数据增强目前是文本数据增强方面效果较好的增强方法,一般基于google翻译接口,将文本数据翻译成另外一种语言(一般选择小语种),之后再翻译回原语言,即可认为得到与与原语料同标签的新语料,新语料加入到原数据集中即可认为是对原数据集数据增强

  • 操作简便, 获得新语料质量高.
  • 在短文本回译过程中,新语料与原语料可能存在很高重复率,并不能有效增大样本的特征空间

高重复率解决办法:

进行连续的多语言翻译,如:中文→韩文→日语→英文→中文。根据经验,最多只采用3次连续翻译,更多的翻译次数将产生效率低下,语义失真等问题

相关文章:

【NLP】文本预处理

目录 一、文本处理的基本方法 1.1 分词 1.2 命名体实体识别 1.3 词性标注 二、文本张量的表示形式 2.1 one-hot编码 2.2 word2vec 模型 2.2.1 CBOW模式 2.2.2 skipgram模式 2.3 词嵌入word embedding 三、文本数据分析 3.1 标签数量分布 3.2 句子长度分布 3.3 词…...

deepseek r1从零搭建本地知识库10:嵌入模型和知识库建设

一、嵌入模型&#xff08;Embedding Model&#xff09;是什么&#xff1f; 1. 定义 嵌入模型是一种将文本、图像、音频等非结构化数据转化为**低维稠密向量&#xff08;Dense Vector&#xff09;**的算法模型&#xff0c;这些向量&#xff08;通常几百到几千维&#xff09;能够…...

Linux-文件IO

1.open函数 【1】基本概念和使用 #include <fcntl.h> int open(const char *pathname&#xff0c;int flags); int open(const char *pathname&#xff0c;int flags&#xff0c;mode_t mode); 功能: 打开或创建文件 参数: pathname //打开的文件名 f…...

3d pose 学习笔记2025

目录 champ nlf 3dpose 2025 55个关键点 推理代码: 要设置环境变量: 依赖项metrabs 渲染代码: tram4d 脚也不是特别好 GVHMR脚对不齐 推理代码: multiperson 2023年 genhmr还没开源: champ https://zhuanlan.zhihu.com/p/700326554 nlf 3dpose 2025 55个关键点…...

LC-随机链表的复制、排序链表、合并K个升序链表、LRU缓存

随机链表的复制 为了在 O(n) 时间复杂度内解决这个问题&#xff0c;并且使用 O(1) 的额外空间&#xff0c;可以利用以下技巧&#xff1a; 将新节点插入到原节点后面&#xff1a;我们可以将复制节点插入到原节点后面。例如&#xff0c;如果链表是 A -> B -> C&#xff0c…...

静态页面在安卓端可以正常显示,但是在ios打开这个页面就需要刷新才能显示全图片

这个问题可能有几个原因导致,我来分析一下并给出解决方案: 首要问题是懒加载实现方式的兼容性问题。当前的懒加载实现可能在 iOS 上不够稳定。建议修改图片懒加载的实现方式: // 使用 Intersection Observer API 实现懒加载 function initLazyLoading() {const imageObserver…...

四元数如何用于 3D 旋转(代替欧拉角和旋转矩阵)【ESP32指向鼠标】

四元数如何用于 3D 旋转&#xff08;代替欧拉角和旋转矩阵&#xff09; 在三维空间中&#xff0c;物体的旋转可以用 欧拉角、旋转矩阵 或 四元数 来表示。 四元数相比于欧拉角和旋转矩阵有 计算更高效、避免万向锁、存储占用少 等优点&#xff0c;因此广泛用于 游戏开发、机器…...

JavaScript 内置对象-日期对象

在JavaScript中&#xff0c;处理日期和时间是一个常见的需求。无论是显示当前时间、计算两个日期之间的差异&#xff0c;还是格式化日期字符串&#xff0c;Date 对象都能提供强大的支持。本文将详细介绍 Date 对象的使用方法&#xff0c;包括创建日期实例、获取和设置日期值、以…...

本地大模型编程实战(19)RAG(Retrieval Augmented Generation,检索增强生成)(3)

文章目录 准备创建矢量数据库对象创建 LangGraph 链将检索步骤转化为工具定义节点构建图 见证效果qwen2.5llama3.1MFDoom/deepseek-r1-tool-calling:7b 总结代码参考 上一篇文章我们演练了一个 用 langgraph 实现的 RAG(Retrieval Augmented Generation,检索增强生成) 系统。本…...

DeepSeek与ChatGPT:AI语言模型的全面对决

DeepSeek与ChatGPT&#xff1a;AI语言模型的全面对决 引言&#xff1a;AI 语言模型的时代浪潮一、认识 DeepSeek 与 ChatGPT&#xff08;一&#xff09;DeepSeek&#xff1a;国产新星的崛起&#xff08;二&#xff09;ChatGPT&#xff1a;AI 界的开拓者 二、DeepSeek 与 ChatGP…...

2024年年终总结

2024年终于过去了&#xff0c;这绝对是我人生中最惨痛的一年&#xff01;被小人欺骗、被庸人耽误、被自己蠢到&#xff01;不由的让我想起了22年那次算命&#xff0c;算命先生说我十年低谷期&#xff0c;如果从15年进创业公司开始&#xff0c;24年是最后一年&#xff0c;果然应…...

利用 Valgrind 检测 C++ 内存泄露

Valgrind 是一款运行在 Linux 系统上的编程工具集&#xff0c;主要用于调试和分析程序的性能、内存使用等问题。其中最常用的工具是 Memcheck&#xff0c;它可以帮助检测 C 和 C 程序中的内存管理错误&#xff0c;如内存泄漏、使用未初始化的内存、越界访问等。 安装 这里我以…...

Python中的HTTP客户端库:httpx与request | python小知识

Python中的HTTP客户端库&#xff1a;httpx与request | python小知识 在Python中&#xff0c;发送HTTP请求和处理响应是网络编程的基础。requests和httpx是两个常用的HTTP库&#xff0c;它们都提供了简洁易用的API来发送HTTP请求。然而&#xff0c;httpx作为新一代的HTTP客户端…...

【Python】Python入门基础——环境搭建

学习Python&#xff0c;首先需要搭建一个本地开发环境&#xff0c;或是使用线上开发环境&#xff08;各类练习网站&#xff09;&#xff0c;这里主要记录本地开发环境的配置。 目录&#xff1a; 一、下载和安装python解释器 官网下载地址&#xff1a;Download Python | Pytho…...

2025 pwn_A_childs_dream

文章目录 fc/sfc mesen下载和使用推荐 fc/sfc https://www.mesen.ca/docs/ mesen2安装&#xff0c;vscode安装zg 任天堂yyds w d 左右移动 u结束游戏 i崩溃或者卡死了 L暂停 D658地方有个flag 发现DEEE会使用他。且只有这个地方&#xff0c;maybe会输出flag&#xff0c;应…...

面试题整理:操作系统

文章目录 操作系统操作系统基础1. 操作系统的功能&#xff1f;2. 什么是用户态和内核态&#xff1f; 进程和线程1. 是什么&#xff1f;区别&#xff1f;2. ⭐线程间的同步的方式有哪些&#xff1f;3. PCB 是什么&#xff1f;包含哪些信息&#xff1f;4. 进程的状态有哪些&#…...

构建未来教育的基石:智慧校园与信息的重要性

随着科技的迅猛发展&#xff0c;教育领域正经历一场深刻的变革。在这个过程中&#xff0c;“智慧校园”作为教育信息化的重要实践&#xff0c;扮演着不可或缺的角色。智慧校园不仅仅是硬件设施的升级&#xff0c;更是一种全新的教育理念&#xff0c;强调利用信息技术优化教育资…...

C# 控制台相关 API 与随机数API

C# 控制台相关 API 与随机数API 控制台输入输出 功能说明 Console.WriteLine(string): 输出字符串并换行Console.Write(string, string): 输出字符串不换行Console.ReadLine(): 等待用户输入并返回字符串Console.ReadKey(bool).KeyChar: 读取按键&#xff0c;指定是否显示输…...

【踩坑】⭐️MyBatis的Mapper接口中不建议使用重载方法

目录 &#x1f378;前言 &#x1f37b;一、背景 &#x1f379;二、问题处理 &#x1f49e;️三、处理方法 &#x1f378;前言 小伙伴们大家好&#xff0c;很久没有水..不是&#xff0c;写文章了&#xff0c;都收到系统的消息了&#xff1b;我算下时间&#xff0c;上周是单休…...

CSS Grid 网格布局,以及 Flexbox 弹性盒布局模型,它们的适用场景是什么?

CSS Grid网格布局和Flexbox弹性盒布局模型都是现代CSS布局的重要工具&#xff0c;它们各自具有独特的优势和适用场景。 作为前端开发工程师&#xff0c;理解这些布局模型的差异和适用场景对于编写高效、可维护的代码至关重要。 CSS Grid网格布局 适用场景&#xff1a; 复杂…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

宇树科技,改名了!

提到国内具身智能和机器人领域的代表企业&#xff0c;那宇树科技&#xff08;Unitree&#xff09;必须名列其榜。 最近&#xff0c;宇树科技的一项新变动消息在业界引发了不少关注和讨论&#xff0c;即&#xff1a; 宇树向其合作伙伴发布了一封公司名称变更函称&#xff0c;因…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...