一.自然语言处理简介
1. 什么是自然语言处理
- 自然语言处理(Natural Language Processing, 简称NLP)是计算机科学与语言学中关注于计算机与人类语言间转换的领域.
2.自然语言处理的应用场景
- 语音助手
- 机器翻译
- 搜索引擎
- 智能问答
3.2015年,人工智能时代到来

二.文本预处理
1.文本处理的基本方法
1.分词
什么是分词?
分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符。分词过程就是找到这样分界符的过程
分词的作用:
- 分词的作用: * 词作为语言语义理解的最小单元, 是人类理解文本语言的基础. 因此也是AI解决NLP领域高阶任务, 如自动问答, 机器翻译, 文本生成的重要基础环节.
- jieba的特性: 支持多种分词模式 ,精确模式 , 全模式 , 搜索引擎模式 ,支持中文繁体分词 和支持用户自定义词典
- 精确模式分词: 试图将句子最精确地切开,适合文本分析
- 全模式分词: 把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能消除歧义
- 搜索引擎模式分词: 在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词
2.命名实体识别
通常我们将人名, 地名, 机构名等专有名词统称命名实体. 如: 周杰伦, 黑山县, 孔子学院, 24辊方钢矫直机,命名实体识别(Named Entity Recognition,简称NER)就是识别出一段文本中可能存在的命名实体.
举个例子:
浙江绍兴人, 五四新文化运动的重要参与者, 代表作朝花夕拾. ==> 鲁迅(人名) / 浙江绍兴(地名)人 / 五四新文化运动(专有名词) / 重要参与者 / 代表作 / 朝花夕拾(专有名词)
3.词性标注
词性: 语言中对词的一种分类方法,以语法特征为主要依据、兼顾词汇意义对词进行划分的结果, 常见的词性有14种, 如: 名词, 动词, 形容词等;词性标注(Part-Of-Speech tagging, 简称POS)就是标注出一段文本中每个词汇的词性
二.文本张量表示方法
1.文本张量表示
将一段文本使用张量进行表示,其中一般将词汇表示成向量,称作词向量,再由各个词向量按顺序组成矩阵形成文本表示
- 文本张量表示的作用: 将文本表示成张量(矩阵)形式,能够使语言文本可以作为计算机处理程序的输入,进行接下来一系列的解析工作.
- 文本张量表示的方法: one-hot编码,Word2vec,Word Embedding
2.one-hot词向量表示
又称独热编码,将每个词表示成具有n个元素的向量,这个词向量中只有一个元素是1,其他元素都是0,不同词汇元素为0的位置不同,其中n的大小是整个语料中不同词汇的总数
e.["改变", "要", "如何", "起手"]`
==> [[1, 0, 0, 0],
0, 1, 0, 0\], \[0, 0, 1, 0\], \[0, 0, 0, 1\]
python
import jieba
# 导入keras中的词汇映射器Tokenizer
from tensorflow.keras.preprocessing.text import Tokenizer
# 导入用于对象保存与加载的joblib
from sklearn.externals import joblib
# 思路分析 生成onehot
# 1 准备语料 vocabs
# 2 实例化词汇映射器Tokenizer, 使用映射器拟合现有文本数据 (内部生成 index_word word_index)
# 2-1 注意idx序号-1
# 3 查询单词idx 赋值 zero_list,生成onehot
# 4 使用joblib工具保存映射器 joblib.dump()
def dm_onehot_gen():
# 1 准备语料 vocabs
vocabs = {"周杰伦", "陈奕迅", "王力宏", "李宗盛", "吴亦凡", "鹿晗"}
# 2 实例化词汇映射器Tokenizer, 使用映射器拟合现有文本数据 (内部生成 index_word word_index)
# 2-1 注意idx序号-1
mytokenizer = Tokenizer()
mytokenizer.fit_on_texts(vocabs)
# 3 查询单词idx 赋值 zero_list,生成onehot
for vocab in vocabs:
zero_list = [0] * len(vocabs)
idx = mytokenizer.word_index[vocab] - 1
zero_list[idx] = 1
print(vocab, '的onehot编码是', zero_list)
# 4 使用joblib工具保存映射器 joblib.dump()
mypath = './mytokenizer'
joblib.dump(mytokenizer, mypath)
print('保存mytokenizer End')
# 注意5-1 字典没有顺序 onehot编码没有顺序 []-有序 {}-无序 区别
# 注意5-2 字典有的单词才有idx idx从1开始
# 注意5-3 查询没有注册的词会有异常 eg: 狗蛋
print(mytokenizer.word_index)
print(mytokenizer.index_word)
python
陈奕迅 的onehot编码是 [1, 0, 0, 0, 0, 0]
王力宏 的onehot编码是 [0, 1, 0, 0, 0, 0]
鹿晗 的onehot编码是 [0, 0, 1, 0, 0, 0]
周杰伦 的onehot编码是 [0, 0, 0, 1, 0, 0]
李宗盛 的onehot编码是 [0, 0, 0, 0, 1, 0]
吴亦凡 的onehot编码是 [0, 0, 0, 0, 0, 1]
保存mytokenizer End
{'陈奕迅': 1, '王力宏': 2, '鹿晗': 3, '周杰伦': 4, '李宗盛': 5, '吴亦凡': 6}
{1: '陈奕迅', 2: '王力宏', 3: '鹿晗', 4: '周杰伦', 5: '李宗盛', 6: '吴亦凡'}
one-hot编码的优劣势:
优势:操作简单,容易理解.
劣势:完全割裂了词与词之间的联系,而且在大语料集下,每个向量的长度过大,占据大量内存.
正因为one-hot编码明显的劣势,这种编码方式被应用的地方越来越少,取而代之的是接下来我们要学习的稠密向量的表示方法word2vec和word embedding.
3.word2vec模型
word2vec是一种流行的将词汇表示成向量的无监督训练方法, 该过程将构建神经网络模型, 将网络参数作为词汇的向量表示, 它包含CBOW和skipgram两种训练模式
1.CBOW(Continuous bag of words)模式: * 给定一段用于训练的文本语料, 再选定某段长度(窗口)作为研究对象, 使用上下文词汇预测目标词汇
2.skipgram模式: 给定一段用于训练的文本语料, 再选定某段长度(窗口)作为研究对象, 使用目标词汇预测上下文词汇
3.词向量的检索获取神经网络训练完毕后,神经网络的参数矩阵w就我们的想要词向量。如何检索某1个单词的向量呢?以CBOW方式举例说明如何检索a单词的词向量。如下图所示:a的onehot编码[10000],用参数矩阵[3,5] * a的onehot编码[10000],可以把参数矩阵的第1列参数给取出来,这个[3,1]的值就是a的词向量。


4.词嵌入word embedding介绍
- 通过一定的方式将词汇映射到指定维度(一般是更高维度)的空间.
- 广义的word embedding包括所有密集词汇向量的表示方法,如之前学习的word2vec, 即可认为是word embedding的一种.
- 狭义的word embedding是指在神经网络中加入的embedding层, 对整个网络进行训练的同时产生的embedding矩阵(embedding层的参数), 这个embedding矩阵就是训练过程中所有输入词汇的向量表示组成的矩阵
python
import torch
from tensorflow.keras.preprocessing.text import Tokenizer
from torch.utils.tensorboard import SummaryWriter
import jieba
import torch.nn as nn
# 实验:nn.Embedding层词向量可视化分析
# 1 对句子分词 word_list
# 2 对句子word2id求my_token_list,对句子文本数值化sentence2id
# 3 创建nn.Embedding层,查看每个token的词向量数据
# 4 创建SummaryWriter对象, 可视化词向量
# 词向量矩阵embd.weight.data 和 词向量单词列表my_token_list添加到SummaryWriter对象中
# summarywriter.add_embedding(embd.weight.data, my_token_list)
# 5 通过tensorboard观察词向量相似性
# 6 也可通过程序,从nn.Embedding层中根据idx拿词向量
def dm02_nnembeding_show():
# 1 对句子分词 word_list
sentence1 = '传智教育是一家上市公司,旗下有黑马程序员品牌。我是在黑马这里学习人工智能'
sentence2 = "我爱自然语言处理"
sentences = [sentence1, sentence2]
word_list = []
for s in sentences:
word_list.append(jieba.lcut(s))
# print('word_list--->', word_list)
# 2 对句子word2id求my_token_list,对句子文本数值化sentence2id
mytokenizer = Tokenizer()
mytokenizer.fit_on_texts(word_list)
# print(mytokenizer.index_word, mytokenizer.word_index)
# 打印my_token_list
my_token_list = mytokenizer.index_word.values()
print('my_token_list-->', my_token_list)
# 打印文本数值化以后的句子
sentence2id = mytokenizer.texts_to_sequences(word_list)
print('sentence2id--->', sentence2id, len(sentence2id))
# 3 创建nn.Embedding层
embd = nn.Embedding(num_embeddings=len(my_token_list), embedding_dim=8)
# print("embd--->", embd)
# print('nn.Embedding层词向量矩阵-->', embd.weight.data, embd.weight.data.shape, type(embd.weight.data))
# 4 创建SummaryWriter对象 词向量矩阵embd.weight.data 和 词向量单词列表my_token_list
summarywriter = SummaryWriter()
summarywriter.add_embedding(embd.weight.data, my_token_list)
summarywriter.close()
# 5 通过tensorboard观察词向量相似性
# cd 程序的当前目录下执行下面的命令
# 启动tensorboard服务 tensorboard --logdir=runs --host 0.0.0.0
# 通过浏览器,查看词向量可视化效果 http://127.0.0.1:6006
print('从nn.Embedding层中根据idx拿词向量')
# # 6 从nn.Embedding层中根据idx拿词向量
for idx in range(len(mytokenizer.index_word)):
tmpvec = embd(torch.tensor(idx))
print('%4s'%(mytokenizer.index_word[idx+1]), tmpvec.detach().numpy())
python
my_token_list--> dict_values(['是', '黑马', '我', '传智', '教育', '一家', '上市公司', ',', '旗下', '有', '程序员', '品牌', '。', '在', '这里', '学习', '人工智能', '爱', '自然语言', '处理'])
sentence2id---> [[4, 5, 1, 6, 7, 8, 9, 10, 2, 11, 12, 13, 3, 1, 14, 2, 15, 16, 17], [3, 18, 19, 20]] 2
从nn.Embedding层中根据idx拿词向量
是 [ 0.46067393 -0.9049023 -0.03143226 -0.32443136 0.03115687 -1.3352231
-0.08336695 -2.4732168 ]
黑马 [ 0.66760564 0.08703537 0.23735243 1.5896837 -1.8869231 0.22520915
-1.0676078 -0.7654686 ]
我 [-0.9093167 -0.6114051 -0.6825029 0.9269122 0.5208822 2.294128
-0.11160549 -0.34862307]
传智 [-1.1552105 -0.4274638 -0.8121502 -1.4969801 -1.3328248 -1.0934378
0.6707438 -1.1796173]
教育 [ 0.01580311 -1.1884228 0.59364647 1.5387698 -1.0822943 0.36760855
-0.4652998 -0.57378227]
一家 [-1.1898873 -0.42482868 -1.9391155 -1.5678993 -1.6960118 0.22525501
-1.0754168 0.41797593]
上市公司 [ 0.590556 2.4274144 1.6698223 -0.9776848 -0.6119061 0.4434897
-2.3726876 -0.2607738]
, [-0.17568143 1.0074369 0.2571488 1.8940887 -0.5383494 0.65416646
0.63454026 0.6235991 ]
旗下 [ 2.8400452 -1.0096515 2.247107 0.30006626 -1.2687006 0.05855403
0.01199368 -0.6156502 ]
有 [ 0.89320636 -0.43819678 1.0345292 1.3546743 -1.4238662 -1.6994532
0.30445674 2.673923 ]
程序员 [ 1.2147354 0.24878891 0.36161897 0.37458655 -0.48264053 -0.0141514
1.2033817 0.7899459 ]
品牌 [ 0.59799325 -0.01371854 0.0628166 -1.4829391 0.39795023 -0.39259398
-0.60923046 0.54170054]
。 [ 0.59599686 1.6038656 -0.10832139 0.25223547 0.37193906 1.1944667
-0.91253406 0.6869221 ]
在 [-1.161504 2.6963246 -0.6087775 0.9399654 0.8480068 0.684357
0.96156543 -0.3541162 ]
这里 [ 0.1034054 -0.01949253 0.8989019 1.61057 -1.5983531 0.17945968
-0.17572908 -0.9724814 ]
学习 [-1.3899843 -1.0846052 -1.1301199 -0.4078141 0.40511298 0.6562911
0.9231357 -0.34704337]
人工智能 [-1.4966388 -1.0905199 1.001238 -0.75254333 -1.4210068 -1.854177
1.0471514 -0.27140012]
爱 [-1.5254552 0.6189947 1.2703396 -0.4826037 -1.4928672 0.8320283
1.7333516 0.16908517]
自然语言 [-0.3856235 -1.2193452 0.9991112 -1.5821775 0.45017946 -0.66064674
0.08045111 0.62901515]
处理 [ 1.5062869 1.3156213 -0.21295634 0.47610474 0.08946162 0.57107806
-1.0727187 0.16396333]
词向量和词显示标签 写入磁盘ok 在当前目录下查看 ./runs 目录
四.文本数据分析
文本数据分析能够有效帮助我们理解数据语料, 快速检查出语料可能存在的问题, 并指导之后模型训练过程中一些超参数的选择;
- 常用的几种文本数据分析方法: 标签数量分布 ,句子长度分布 ,词频统计与关键词词云
我们将基于真实的中文酒店评论语料来讲解常用的几种文本数据分析方法,以下是语料链接
通过网盘分享的文件:
链接: https://pan.baidu.com/s/1wWCQRva7UCia_6xqMydWFQ?pwd=nspk 提取码: nspk 复制这段内容后打开百度网盘手机App,操作更方便哦
1.获取标签数量分布:
python
# 导入必备工具包
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
# 思路分析 : 获取标签数量分布
# 0 什么标签数量分布:求标签0有多少个 标签1有多少个 标签2有多少个
# 1 设置显示风格plt.style.use('fivethirtyeight')
# 2 pd.read_csv(path, sep='\t') 读训练集 验证集数据
# 3 sns.countplot() 统计label标签的0、1分组数量
# 4 画图展示 plt.title() plt.show()
# 注意1:sns.countplot()相当于select * from tab1 group by
def dm_label_sns_countplot():
# 1 设置显示风格plt.style.use('fivethirtyeight')
plt.style.use('fivethirtyeight')
# 2 pd.read_csv 读训练集 验证集数据
train_data = pd.read_csv(filepath_or_buffer = './cn_data/train.tsv', sep='\t')
dev_data = pd.read_csv(filepath_or_buffer = './cn_data/dev.tsv', sep='\t')
# 3 sns.countplot() 统计label标签的0、1分组数量
sns.countplot(x='label', data = train_data)
# 4 画图展示 plt.title() plt.show()
plt.title('train_label')
plt.show()
# 验证集上标签的数量分布
# 3-2 sns.countplot() 统计label标签的0、1分组数量
sns.countplot(x='label', data = dev_data)
# 4-2 画图展示 plt.title() plt.show()
plt.title('dev_label')
plt.show()


2.获取句子长度分布
python
# 思路分析 : 获取句子长度分布 -绘制句子长度分布-柱状图 句子长度分布-密度曲线图
# 0 什么是句子长度分布:求长度为50的有多少个 长度51的有多少个 长度为52的有多少个
# 1 设置显示风格plt.style.use('fivethirtyeight')
# 2 pd.read_csv(path, sep='\t') 读训练集 验证集数据
# 3 新增数据长度列:train_data['sentence_length'] = list(map(lambda x:len(x) , ...))
# 4-1 绘制数据长度分布图-柱状图 sns.countplot(x='sentence_length', data=train_data)
# 画图展示 plt.xticks([]) plt.show()
# 4-2 绘制数据长度分布图-曲线图 sns.displot(x='sentence_length', data=train_data)
# 画图展示 plt.yticks([]) plt.show()
def dm_len_sns_countplot_distplot():
# 1 设置显示风格plt.style.use('fivethirtyeight')
plt.style.use('fivethirtyeight')
# 2 pd.read_csv 读训练集 验证集数据
train_data = pd.read_csv(filepath_or_buffer='./cn_data/train.tsv', sep='\t')
dev_data = pd.read_csv(filepath_or_buffer='./cn_data/dev.tsv', sep='\t')
# 3 求数据长度列 然后求数据长度的分布
train_data['sentence_length'] = list( map(lambda x: len(x), train_data['sentence']))
# 4 绘制数据长度分布图-柱状图
sns.countplot(x='sentence_length', data=train_data)
# sns.countplot(x=train_data['sentence_length'])
plt.xticks([]) # x轴上不要提示信息
# plt.title('sentence_length countplot')
plt.show()
# 5 绘制数据长度分布图-曲线图
sns.displot(x='sentence_length', data=train_data)
# sns.displot(x=train_data['sentence_length'])
plt.yticks([]) # y轴上不要提示信息
plt.show()
# 验证集
# 3 求数据长度列 然后求数据长度的分布
dev_data['sentence_length'] = list(map(lambda x: len(x), dev_data['sentence']))
# 4 绘制数据长度分布图-柱状图
sns.countplot(x='sentence_length', data=dev_data)
# sns.countplot(x=dev_data['sentence_length'])
plt.xticks([]) # x轴上不要提示信息
# plt.title('sentence_length countplot')
plt.show()
# 5 绘制数据长度分布图-曲线图
sns.displot(x='sentence_length', data=dev_data)
# sns.displot(x=dev_data['sentence_length'])
plt.yticks([]) # y轴上不要提示信息
plt.show()
训练集句子长度分布:


验证集句子长度分布:


通过绘制句子长度分布图, 可以得知我们的语料中大部分句子长度的分布范围, 因为模型的输入要求为固定尺寸的张量,合理的长度范围对之后进行句子截断补齐(规范长度)起到关键的指导作用. 上图中大部分句子长度的范围大致为20-250之间
3.获取正负样本长度分布散点图
python
# 获取正负样本长度散点分布,也就是按照x正负样本进行分组 再按照y长度进行散点图
# train_data['sentence_length'] = list(map(lambda x: len(x), train_data['sentence']))
# sns.stripplot(y='sentence_length', x='label', data=train_data)
def dm03_sns_stripplot():
# 1 设置显示风格plt.style.use('fivethirtyeight')
plt.style.use('fivethirtyeight')
# 2 pd.read_csv 读训练集 验证集数据
train_data = pd.read_csv(filepath_or_buffer='./cn_data/train.tsv', sep='\t')
dev_data = pd.read_csv(filepath_or_buffer='./cn_data/dev.tsv', sep='\t')
# 3 求数据长度列 然后求数据长度的分布
train_data['sentence_length'] = list(map(lambda x: len(x), train_data['sentence']))
# 4 统计正负样本长度散点图 (对train_data数据,按照label进行分组,统计正样本散点图)
sns.stripplot(y='sentence_length', x='label', data=train_data)
plt.show()
sns.stripplot(y='sentence_length', x='label', data=dev_data)
plt.show()
训练集:

验证集:

4.获取不同词汇总数统计
python
# 导入jieba用于分词
# 导入chain方法用于扁平化列表
import jieba
from itertools import chain
# 进行训练集的句子进行分词, 并统计出不同词汇的总数
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))
训练集共包含不同词汇总数为: 12147 训练集共包含不同词汇总数为: 6857
5.获取训练集高频形容词词云
python
# 使用jieba中的词性标注功能
import jieba.posseg as pseg
from wordcloud import WordCloud
# 每句话产生形容词列表
def get_a_list(text):
r = []
# 使用jieba的词性标注方法切分文本 找到形容词存入到列表中返回
for g in pseg.lcut(text):
if g.flag == "a":
r.append(g.word)
return r
# 根据词云列表产生词云
def get_word_cloud(keywords_list):
# 实例化词云生成器对象
wordcloud = WordCloud(font_path="./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()
# 思路分析 训练集正样本词云 训练集负样本词云
# 1 获得训练集上正样本 p_train_data
# eg: 先使用逻辑==操作检索符合正样本 train_data[train_data['label'] == 1]
# 2 获取正样本的每个句子的形容词 p_a_train_vocab = chain(*map(a,b))
# 3 调用绘制词云函数
def dm_word_cloud():
# 1 获得训练集上正样本p_train_data
# eg: 先使用逻辑==操作检索符合正样本 train_data[train_data['label'] == 1]
train_data = pd.read_csv(filepath_or_buffer='./cn_data/train.tsv', sep='\t')
p_train_data = train_data[train_data['label'] == 1 ]['sentence']
# 2 获取正样本的每个句子的形容词 p_a_train_vocab = chain(*map(a,b))
p_a_train_vocab = chain(*map(lambda x: get_a_list(x) , p_train_data))
# print(p_a_train_vocab)
# print(list(p_a_train_vocab))
# 3 调用绘制词云函数
get_word_cloud(p_a_train_vocab)
print('*' * 60 )
# 训练集负样本词云
n_train_data = train_data[train_data['label'] == 0 ]['sentence']
# 2 获取正样本的每个句子的形容词 p_a_train_vocab = chain(*map(a,b))
n_a_train_vocab = chain(*map(lambda x: get_a_list(x) , n_train_data) )
# print(n_a_dev_vocab)
# print(list(n_a_dev_vocab))
# 3 调用绘制词云函数
get_word_cloud(n_a_train_vocab)
训练集正样本训练集负样本
6.获取验证集形容词词云
python
# 获得验证集上正样本
p_valid_data = valid_data[valid_data["label"]==1]["sentence"]
# 对正样本的每个句子的形容词
valid_p_a_vocab = chain(*map(lambda x: get_a_list(x), p_valid_data))
#print(train_p_n_vocab)
# 获得验证集上负样本
n_valid_data = valid_data[valid_data["label"]==0]["sentence"]
# 获取负样本的每个句子的形容词
valid_n_a_vocab = chain(*map(lambda x: get_a_list(x), n_valid_data))
# 调用绘制词云函数
get_word_cloud(valid_p_a_vocab)
get_word_cloud(valid_n_a_vocab)
验证集正样本形容词词云:
验证集负样本形容词词云:
根据高频形容词词云显示, 我们可以对当前语料质量进行简单评估, 同时对违反语料标签含义的词汇进行人工审查和修正, 来保证绝大多数语料符合训练标准. 上图中的正样本大多数是褒义词, 而负样本大多数是贬义词, 基本符合要求, 但是负样本词云中也存在"便利"这样的褒义词, 因此可以人工进行审查
五.文本特征处理
1.什么是n-gram特征
给定一段文本序列, 其中n个词或字的相邻共现特征即n-gram特征, 常用的n-gram特征是bi-gram和tri-gram特征, 分别对应n为2和3
e.
假设给定分词列表: ["是谁", "敲动", "我心"]
对应的数值映射列表为: [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]
python
# 一般n-gram中的n取2或者3, 这里取2为例
ngram_range = 2
def create_ngram_set(input_list):
"""
description: 从数值列表中提取所有的n-gram特征
:param input_list: 输入的数值列表, 可以看作是词汇映射后的列表,
里面每个数字的取值范围为[1, 25000]
:return: n-gram特征组成的集合
eg:
>>> create_ngram_set([1, 3, 2, 1, 5, 3])
{(3, 2), (1, 3), (2, 1), (1, 5), (5, 3)}
"""
return set(zip(*[input_list[i:] for i in range(ngram_range)]))
调用
python
input_list = [1, 3, 2, 1, 5, 3]
res = create_ngram_set(input_list)
print(res)
结果
python
# 该输入列表的所有bi-gram特征
{(3, 2), (1, 3), (2, 1), (1, 5), (5, 3)}
2.文本长度规范及其作用
一般模型的输入需要等尺寸大小的矩阵, 因此在进入模型前需要对每条文本数值映射后的长度进行规范, 此时将根据句子长度分布分析出覆盖绝大多数文本的合理长度, 对超长文本进行截断, 对不足文本进行补齐(一般使用数字0), 这个过程就是文本长度规范.
python
from tensorflow.keras.preprocessing import sequence
# cutlen根据数据分析中句子长度分布,覆盖90%左右语料的最短长度.
# 这里假定cutlen为10
cutlen = 10
def padding(x_train):
"""
description: 对输入文本张量进行长度规范
:param x_train: 文本的张量表示, 形如: [[1, 32, 32, 61], [2, 54, 21, 7, 19]]
:return: 进行截断补齐后的文本张量表示
"""
# 使用sequence.pad_sequences即可完成
return sequence.pad_sequences(x_train, cutlen)
调用:
# 假定x_train里面有两条文本, 一条长度大于10, 一天小于10
x_train = [[1, 23, 5, 32, 55, 63, 2, 21, 78, 32, 23, 1],
[2, 32, 1, 23, 1]]
res = padding(x_train)
print(res)
结果
python
[[ 5 32 55 63 2 21 78 32 23 1]
[ 0 0 0 0 0 2 32 1 23 1]]
六.文本数据增强
回译数据增强法
回译数据增强目前是文本数据增强方面效果较好的增强方法, 一般基于google、有道等翻译接口, 将文本数据翻译成另外一种语言(一般选择小语种),之后再翻译回原语言, 即可认为得到与与原语料同标签的新语料, 新语料加入到原数据集中即可认为是对原数据集数据增强.
1.回译数据增强优势: 操作简便, 获得新语料质量高.
2.回译数据增强存在的问题: 在短文本回译过程中, 新语料与原语料可能存在很高的重复率, 并不能有效增大样本的特征空间.
3.高重复率解决办法: 进行连续的多语言翻译, 如: 中文→韩文→日语→英文→中文, 根据经验, 最多只采用3次连续翻译, 更多的翻译次数将产生效率低下, 语义失真等问题.
python
# 导入必备的工具包
import requests
# 思路分析
# 1 定义需要访问的有道翻译API接口--url
# 2 定义需要翻译的文本:text
# 3 定义data数据:from代表原始语言, to代表目标语言, i代表需要翻译的文本, doctype:文本的类型
# 4 requests.post(url=url, params=data)即代表访问api接口的方法
def dm_translate():
url = 'http://fanyi.youdao.com/translate'
# 第一次翻译,目标语言英文
text1 = '这个价格非常便宜'
data1 = {'from': 'zh-CHS', 'to': 'en', 'i': text1, 'doctype': 'json'}
response1 = requests.post(url=url, params=data1)
res1 = response1.json()
# 打印第一次翻译结果
print(res1)
# 第二次翻译, 目标语言中文
text2 = 'The price is very cheap'
data2 = {'from': 'en', 'to': 'zh-CHS', 'i': text2, 'doctype': 'json'}
response2 = requests.post(url=url, params=data2)
res2 = response2.json()
# 打印第二次翻译结果
print(res2)
python
第一次翻译结果:{'type': 'ZH_CN2EN', 'errorCode': 0, 'elapsedTime': 1, 'translateResult': [[{'src': '这个价格非常便宜', 'tgt': 'The price is very cheap'}]]}
第二次翻译结果:{'type': 'EN2ZH_CN', 'errorCode': 0, 'elapsedTime': 1, 'translateResult': [[{'src': 'The price is very cheap', 'tgt': '价格非常便宜'}]]}
