← 返回文章列表

文本预处理

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)

输出:

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