文本预处理
word2vec之skipGram word2vec的训练和使用 ·有关词向量训练工具包FastText ·facebook 开源 …
word2vec之skipGram

word2vec的训练和使用
·有关词向量训练工具包FastText ·facebook 开源的,作为NLP工程领域常用的工具包 ·fasttext有两大作用:进行文本分类、训练词向量 ·Word2Vec的作者Tomas Mikolov是一位产出多篇高质量paper的学者,从RNN、Word2Vec再到流行的FastText · 训练词向量步骤 ·第一步:获取训练数据 ·第二步:词向量的训练、保存、加载、查看 ·第三步:模型效果检验 · 第四步:模型超参数设定
训练和保存
#todo1.定义函数,实现:训练向量模型,并保存模型
def dm01_train_save():
my_model = fasttext.train_unsupervised('./data/wh02ad')
my_model.save_model('./model/wh02_fil9.bin')
print("训练完毕,保存成功")


加载和测试

模型超参设定
def dm04_set_hyper_parameters():
my_model = fasttext.train_unsupervised('./data/wh02ad',
model = 'cbow',
dim = 50,
epoch = 1,
lr = 0.01,
thread = 10
)
my_model.save_model('./model/wh02_fil9_new.bin')
word embedding
word embedding词嵌入 ·通过一定的方式将词汇映射到指定维度(一般是更高维度)的空间 ·广义的wordembedding:所有密集词汇向量的表示方法。word2vec可认为是word embedding的一种。 ·广义的wordembedding可使用浅层神经网络,也可使用深层神经网络表示词向量 ·狭义的word embedding:指深度神经网络中嵌入一个层
·问:Word2Vec方式产生词向量和**word embedding(nn.Embedding)**方式产生有何异同? ·相同点:都可用来对文本训练词向量 · 不同点如下: word2vec产生词向量后,某一个词向量比如单词“the”词向量就固定下来了,是静态的。 nn.Embedding层产生词向量后,词嵌入层作为整体神经网络的一部分,权重参数会参与更新,是动态的
·word2vec使用起来一般需要两步:1)输入单词the拿到词向量,2)再送给神经网络进行使
·nn.Embedding层使用起来更方便就1步。直接嵌入到神经网络中,更易使用

重点
CBOW在训练数据较大的情况下往往表现较好,特别是在高频词的情况下。
Skip-gram对于低频词的处理更为出色,尤其在大规模数据集中,但相对计算效率较低。
可视化
import os
os.environ['TF_ENABLE_ONEDNN_OPTS'] ='0'
import torch
from tensorflow.keras.preprocessing.text import Tokenizer
from torch.utils.tensorboard import SummaryWriter
import jieba
import torch.nn as nn
#todo1.定义函数,演示:word embedding将文本转换为词向量,并可视化
def dm01():
#1.定义变量,记录待处理的文本
sentence1 = '传智教育是一家上市公司,旗下有黑马程序员品牌。我是在黑马这里学习人工智能'
sentence2 = '我爱自然语言处理'
#2.把上述的两句话,封装成:列表
sentences = [sentence1, sentence2]
#3.使用jieba进行分词处理
#3.1 定义变量,记录分词结果
word_list =[]
#3.2 遍历列表,对列表中的每一句话进行分词
for sentence in sentences:
word_list.append(list(jieba.cut(sentence)))
print(f'分词结果:{word_list}')
#4.构建词汇表,进行文本数值化(词向量)
#4.1初始化词汇映射器
my_tokenizer = Tokenizer()
#4.2拟合训练数据,统计词频,并构建:词汇表
my_tokenizer.fit_on_texts(word_list)
#4.3 查看词 和 索引的映射关系
print(f'词汇映射关系:{my_tokenizer.word_index}')
#4.4获取 去重后的 词汇列表
my_token_list = my_tokenizer.word_index.values()
print(my_token_list)
#4.5将分词后的文本-->转成 数字序列
seq2id = my_tokenizer.texts_to_sequences(word_list)
print(f'文本转为数字序列:{seq2id}')
#5.创建词嵌入层,把文本(即:词对应的编号)转成 词向量
#5.1 创建词嵌入层对象
#参1:词汇表大小,即:去重后的词数量 参2:词向量的维度
embed = nn.Embedding(num_embeddings=len(my_token_list),embedding_dim=8)
#5.2 查看词嵌入层的权重参数 即:词向量
print(f'词嵌入层的权重参数:{embed.weight.data}')
print(f'embed.shape:{embed.weight.data.shape}')
print('=-='*30)
#6.词向量可视化
writer = SummaryWriter(log_dir='./runs')
#参1:词向量矩阵 参2:对应的词语列表,用来标注每个点
# 修复:按索引排序,取出词汇列表
sorted_vocab = sorted(my_tokenizer.word_index.items(), key=lambda x: x[1])
vocab_words = [word for word, _ in sorted_vocab]
writer.add_embedding(embed.weight.data, vocab_words)
writer.close()
#7.查看每个单词对应的词向量
for idx in range(len(my_tokenizer.word_index)):
temp_vector = embed(torch.tensor(idx))
# print(f'词向量:{temp_vector}')
word = my_tokenizer.index_word[idx+1]
print(f'单词:{word},词向量:{temp_vector.detach().numpy()}')
if __name__ == '__main__':
dm01()
输出:

文本分析
文本语料数据分析
· 作用 ·文本数据分析能够有效帮助我们理解数据语料,快速检查出语料可能存在的问题,指导模型训练过程中一些 超参数的选择
数据质量类:错别字,语法错误,内容重复,缺失值,噪声数据
分布不均衡问题:标签分布不均匀,句子长度分度异常
·比如:关于标签Y:分类问题查看标签是否均匀;关于数据X:数据有没有脏数据数据长度分布等等 · 常用的几种文本数据分析方法 · 标签数量分布 · 句子长度分布 · 词频统计与关键词词云
数据集说明
·基于中文酒店评论语料讲解常用的几种文本数据分析方法 ·属于二分类的中文情感分析语料,该语料存放在”./cn_data”目录下.
·其中train.tsv代表训练集,dev.tsv代表验证集,二者数据样式相同• train.tsv数据样式

标签分布可视化
def dm01_label_sns_countplot():
# 1. 设置538风格 → 一种具有现代感的可视化风格(不做也行)
# plt.style.use('fivethirtyeight')
# 2. 读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
# print(train_data.head())
# 3.统计训练集标签的 0(负样本)和 1(正样本)的数量,并可视化,采用:计数柱状图.
# 参1:x轴标签,参2:数据集,参3:用于分组的分类变量.参4:是否显示图例(默认为True)
sns.countplot(x='label',data=train_data,hue='label',legend=False)
plt.title('train_label')
plt.show()
sns.countplot(x='label',data=dev_data,hue='label',legend=False)
plt.title('dev_label')
plt.show()
输出:


获取句子长度分布
用map()函数实现:
def dm02_len_sns_histplot():
# 1.读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
# 2.计算训练集的每个句子的长度.
# 思路1:map()函数的方式实现.
train_data['sentence_length'] = list(map(lambda x:len(x),train_data['sentence']))
print(train_data.head())

绘制训练集的句子长度分布.
计数柱状图
sns.countplot(x='sentence_length',data=train_data)
plt.title('训练姐句子长度分布_计数柱状图')
plt.xticks()
plt.show()

密度曲线图
sns.histplot(x='sentence_length',data=train_data,kde=True)
plt.title('训练集句子长度分布_计数柱状图')
plt.show()

计算测试集的每个句子的长度
计数柱状图
sns.countplot(x='sentence_length',data=dev_data)
plt.title('测试集句子长度分布_计数柱状图')
plt.xticks()
plt.show()

密度曲线图
sns.histplot(x='sentence_length',data=dev_data,kde=True)
plt.title('测试集句子长度分布_密度曲线图')
plt.show()

大多数分布在[20,250)左右
获取正负样本长度散点分布
· 概念:也就是按照x正负样本进行分组再按照y长度进行散点图

通过查看正负样本长度散点图,可有效定位异常点的出现位置,帮助我们更准确进行人工语料审查 上图中在训练集正样本中出现了异常点,它的句子长度近3500左右,需要我们人工审查
训练集
sns.stripplot(x='label',y='sentence_length',data=train_data)
plt.title('训练集正负样本长度散点分布')
plt.show()

测试集
sns.stripplot(x='label',y='sentence_length',data=dev_data)
plt.title('测试集正负样本长度散点分布')
plt.show()

词汇统计
def dm04_get_vocab_count():
#1.读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
#2.统计训练集的词汇总数(去重后的)
train_vocab = set(chain(*map(lambda x:jieba.lcut(x),train_data['sentence'])))
print(f'训练集共包含不同词汇数为:{len(train_vocab)}')
#3.统计测试集的词汇总数(去重后的)
dev_vocab = set(chain(*map(lambda x:jieba.lcut(x),dev_data['sentence'])))
print(f'测试集共包含不同词汇数为:{len(dev_vocab)}')
输出:

获取训练集高频词云
import jieba
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from itertools import chain
import jieba.posseg as pesg
from wordcloud import WordCloud
#解决中文乱码问题
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
#todo1.定义函数,实现:训练集和 测试集的 标签分布的 可视化统计
def dm01_label_sns_countplot():
# 1. 设置538风格 → 一种具有现代感的可视化风格(不做也行)
# plt.style.use('fivethirtyeight')
# 2. 读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
print(train_data.head())
# 3.统计训练集标签的 0(负样本)和 1(正样本)的数量,并可视化,采用:计数柱状图.
# 参1:x轴标签,参2:数据集,参3:用于分组的分类变量.参4:是否显示图例(默认为True)
sns.countplot(x='label',data=train_data,hue='label',legend=False)
plt.title('train_label')
plt.show()
sns.countplot(x='label',data=dev_data,hue='label',legend=False)
plt.title('dev_label')
plt.show()
#todo 2.定义函数,实现:训练集和测试集的句子长度分布的 可视化统计。
def dm02_len_sns_histplot():
# 1.读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
# 2.计算训练集的每个句子的长度.
# 思路1:map()函数的方式实现.
train_data['sentence_length'] = list(map(lambda x:len(x),train_data['sentence']))
# print(train_data.head())
# 3.绘制训练集的 句子长度分布.
# #图1:计数柱状图
sns.countplot(x='sentence_length',data=train_data)
plt.title('训练集句子长度分布_计数柱状图')
plt.xticks()
plt.show()
# 图2:密度曲线图.
sns.histplot(x='sentence_length',data=train_data,kde=True)
plt.title('训练集句子长度分布_密度曲线图')
plt.show()
# 4.计算测试集的每个句子的长度;
dev_data['sentence_length'] = list(map(lambda x:len(x),dev_data['sentence']))
# #图1:计数柱状图
sns.countplot(x='sentence_length',data=dev_data)
plt.title('测试集句子长度分布_计数柱状图')
plt.xticks()
plt.show()
# 图2:密度曲线图.
sns.histplot(x='sentence_length',data=dev_data,kde=True)
plt.title('测试集句子长度分布_密度曲线图')
plt.show()
# todo3.定义函数,实现:训练集和测试集的 正负样本长度散点分布。
def dm03_sns_stripplot():
# 1.读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
# 2.获取(训练集)数据长度列
train_data['sentence_length'] = list(map(lambda x:len(x),train_data['sentence']))
# 3.获取(测试集)数据长度列
dev_data['sentence_length'] = list(map(lambda x:len(x),dev_data['sentence']))
# 4.绘制正负样本的 句子长度散点分布.
#训练集
sns.stripplot(x='label',y='sentence_length',data=train_data)
plt.title('训练集正负样本长度散点分布')
plt.show()
#测试集
sns.stripplot(x='label',y='sentence_length',data=dev_data)
plt.title('测试集正负样本长度散点分布')
plt.show()
#todo4.定义函数,获取:训练集和测试集的 词汇总数(去重后的).
def dm04_get_vocab_count():
#1.读取训练集和测试集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
dev_data= pd.read_csv('./data/dev.tsv',sep = 't')
#2.统计训练集的词汇总数(去重后的)
train_vocab = set(chain(*map(lambda x:jieba.lcut(x),train_data['sentence'])))
print(f'训练集共包含不同词汇数为:{len(train_vocab)}')
#3.统计测试集的词汇总数(去重后的)
dev_vocab = set(chain(*map(lambda x:jieba.lcut(x),dev_data['sentence'])))
print(f'测试集共包含不同词汇数为:{len(dev_vocab)}')
#todo5.定义函数,实现:训练集和测试集的高频形容词词云.
# todo 5.1 定义函数,获取文本中的形容词列表。
def get_a_list(text):
# 1.定义空列表,用于存储:文本中的形容词.
a_list = []
# 2.使用jieba的词性标注功能,切分文本,并遍历获取到每个词.
for value in pesg.lcut(text):
# print(f'value:{value}') #词+词性
# print(f'value.word:{value.word}') #词
# print(f'value.flag:{value.flag}')# 词性
# 3.判断词性,是否是形容词,如果是,就添加到列表中。
if value.flag == 'a':
a_list.append(value.word)
return a_list
# todo 5.2 定义函数,根据词列表 产生 词云图。
def get_word_cloud(keywords_list):
# 1.实例化词云生成器,设置字体路径,最大显示数,背景色...
wordcloud = WordCloud(
font_path='./data/SimHei.ttf',
max_words = 100,
background_color='white',
)
# 2.将关键词列表 →转换为空格分割的字符串,适配:词云输入格式.
keywords_str = ' '.join(keywords_list)
# 3.根据关键词字符串,生成:词云.
wordcloud.generate(keywords_str)
# 4。配置并显示词云图像.
# 4.1 创建新的绘图窗口.
plt.figure()
#4.2 生成词云(绘制图像)
# 参1:生成词云图像的数据,参2:设置图像插值方法为:双线性插值
plt.imshow(wordcloud,interpolation='bilinear')
# 4.3 关闭坐标轴.
plt.axis('off')
plt.show()
# todo 5.3 定义函数,实现:训练集和测试集的 高频形容词词云。
def dm05_word_cloud():
#场景1:处理训练集
# 1.读取训练集
train_data = pd.read_csv('./data/train.tsv',sep = 't')
#2.获取训练集的 正样本
p_train_data = train_data[train_data['label']==1]['sentence']
# print(p_train_data)
# 2.2 对每个正样本句子,提取形容词列表,并合并为1个完整的形容词列表.
p_a_train_vocab = chain(*map(lambda x:get_a_list(x),p_train_data))
print(p_a_train_vocab)
get_word_cloud(p_a_train_vocab)
print('-'*30)
#场景2:处理测试集
dev_data = pd.read_csv('./data/ dev.tsv',sep = 't')
# 2.获取负样本
p_dev_data = dev_data[dev_data['label']==0]['sentence']
# 2.2 对每个正样本句子,提取形容词列表,并合并为1个完整的形容词列表.
p_a_dev_vocab = chain(*map(lambda x:get_a_list(x),p_dev_data))
get_word_cloud(p_a_dev_vocab)
print('-'*30)
#todo n.测试
if __name__ == '__main__':
# dm01_label_sns_countplot()
# dm02_len_sns_histplot()
# dm03_sns_stripplot()
# dm04_get_vocab_count()
dm05_word_cloud()
输出:
训练集:

测试集:

文本特征处理
· 概念 ·语料添加具有普适性的文本特征,让模型更有效的处理数据,提高模型性能指标 · 常用方法 ·添加n-gram特征(两个单词总是相邻并共现,可以认为是一个特征) ·规范文本长度规范(文本的长度是多少,也可以认为是一个特征)
n-gram代码
# todo 1。定义遍历,记录:n的值,一般 n-gram中的n取 2 或者 3,这里以 2 举例
ngram_range = 2
# todo 2.定义函数,生成 n-gram 特征。
def create_ngram(input_list):
# 1. 通过滑动窗口,获取 n-gram特征.
sliced_lists = [input_list[i:] for i in range(ngram_range)]
ngram_tuples = zip(*sliced_lists)
return set(ngram_tuples)
if __name__ == '__main__':
input_list = [1,3,2,1,5,3]
result = create_ngram(input_list)
print(result)
输出:

扩展——如何计算两段文本的相似性
