第一章 自然语言处理入门什么是NLPNLPNatural Language Process自然语言处理是人工智能领域的一个重要分支其核心目标是让程序能够理解并处理我们所说的语言文字。简单来说就是让计算机能够像人类一样理解、分析和生成自然语言文本。第二章 文本预处理文本预处理是NLP任务中最基础也是最关键的一步直接影响后续模型的效果。1. 分词器分词是将连续的文本切分成独立的词语或词汇单元的过程。# coding:utf-8 import jieba content 阿珍爱上了阿强,在一个没有星星的夜晚,爱情不是nothing! result0 jieba.cut(content) # generator object Tokenizer.cut at 0x00000234E0BF8270 result1 jieba.lcut(content) result2 jieba.lcut(content, cut_allTrue) result3 jieba.lcut_for_search(content) print(f精确模式分词result0--》{result0}) print(f精确模式分词result1--》{result1}) print(f全模式分词result2--》{result2}) print(f搜索引擎分词result3--》{result3})特点支持简体和繁体中文分词采用基于统计和规则的分词算法自定义词典当处理特定业务场景时通用分词可能无法满足需求需要引入自定义词典jieba.load_userdict(自定义词典路径.txt) result jieba.lcut(content) # 默认精确分词适用场景专业领域术语、公司内部产品名、特定人名等2. 命名实体识别NERNERNamed Entity Recognition用于识别文本中具有特殊含义的实体。常见的实体类型 人名如张三、李白 地名如北京、珠穆朗玛峰 机构名如清华大学、阿里巴巴️ 组织名如联合国、红十字会3. 词性标注POSPOSPart-of-Speech Tagging是对每个词语进行词性分类的过程。常见的词性类型名词n.动词v.形容词adj.副词adv.等等...import jieba.posseg as pseg content 我喜欢学习 res pseg.lcut(content) print(res) for word, flag in res: print(f{word}/{flag}) # [pair(我, r), pair(喜欢, v), pair(学习, v)] # 我/r # 喜欢/v # 学习/v文本张量的表示形式计算机无法直接理解文字需要将文本转换为数值形式张量。1. One-hot编码将每个词表示为一个长向量只有一个位置为1其余为0。优点✅ 实现简单容易理解✅ 直观明了缺点❌稀疏向量占用大量存储空间和计算资源❌语义割裂无法体现词与词之间的关系近义词无法关联割裂了词与词之间的联系(主要),如果n过大,会导致占用大量内存(维度爆炸)# 导入keras中的词汇映射器Tokenizer from tensorflow.keras.preprocessing.text import Tokenizer # 导入用于对象保存与加载的joblib import joblib vocanbs [喜羊羊, 懒懒, 灰灰, 小懒, 小灰, 小灰灰] my_tokenizer Tokenizer() my_tokenizer.fit_on_texts(vocanbs) print(my_tokenizer.word_index) print(my_tokenizer.index_word) for v in vocanbs: zero_ls [0] * len(vocanbs) index my_tokenizer.word_index[v] - 1 zero_ls[index] 1 print(f当前{v}的one-hot编码是{zero_ls}) # my_path ./mytokenizer # joblib.dump(my_tokenizer, my_path) # print(模型保存成功) # my_tokenizer joblib.load(mypath) token 小灰灰 zero_ls [0] * len(vocanbs) index my_tokenizer.word_index[token] - 1 zero_ls[index] 1 print(f当前{token}的one-hot编码是{zero_ls})2. Word2VecWord2Vec通过训练将词映射为稠密向量能够捕捉词语之间的语义关系。一种无监督(不用人为标注)的训练方法,本质上是训练一个模型,将模型的参数矩阵当作所有词汇的词向量表示.两种训练模式CBOW连续词袋模式原理用上下文预测中间词示意图将模型的权重参数当作词向量表示skip-gram跳词模式原理用中间词预测上下文示意图 如果不管是安装fasttext还是fasttext-wheel都失败那么原因是python版本过高。 操作步骤如下 1- 先进入对应的虚拟环境 2- 安装低版本的python解释器 conda install python3.10 3- 安装fasttext pip install fasttext-wheel -i https://mirrors.aliyun.com/pypi/simple/ import fasttext def demo01(): # 1- 使用无监督学习训练模型 为什么这里只能使用无监督学习 答因为数据中没有明确标记目标值。有监督学习对文件内容有严格要求有__label__ # model fasttext.train_unsupervised(data/fil9) model fasttext.train_unsupervised(../data/gz03ag) # 2- 保存训练好的模型 model.save_model(../model/word2vec.pkl) def demo02(): # 1- 加载训练好的模型 model fasttext.load_model(../model/word2vec.pkl) # 2- 获得某个词的词向量 word_vec model.get_word_vector(hello) print(word_vec) def demo03(): # 1- 加载训练好的模型 model fasttext.load_model(../model/word2vec.pkl) # 2- 获得相近的几个词 # 会从词形、词义方面进行查找。 # result_list model.get_nearest_neighbors(dog) result_list model.get_nearest_neighbors(cat) # 3- 输出 print(result_list) def demo04(): 参数解释 input训练集路径 modelword2vec的模式。默认是skipgram可以设置为cbow dim词向量的维度 epoch训练的轮次 lr初始学习率 thread训练的线程个数 model fasttext.train_unsupervised( inputdata/gz03ag, modelcbow, dim200, epoch1, lr0.1, thread10 ) model.save_model(../model/word2vec_better.pkl) if __name__ __main__: # 1- 训练并保存模型 # demo01() # 2- 获得词的词向量 # demo02() # 3- 获得相近的词 # demo03() # 4- 超参数调优设置【掌握】 demo04()3. Word Embedding词嵌入Word Embedding是将词语映射到低维稠密向量空间的技术是Word2Vec等方法的统称。它能保持词语之间的语义相似性是深度学习NLP任务的基础。import jieba from keras.src.legacy.preprocessing.text import Tokenizer import torch.nn as nn import torch from torch.utils.tensorboard import SummaryWriter if __name__ __main__: # 1- 准备文本内容 sentence1 阿珍爱上了阿强,再一个没有星星的夜晚 sentence2 我爱自然语言处理 sentence_list [sentence1,sentence2] # 2- 对每条句子进行分词 word_list [] for sen in sentence_list: word_list.append(jieba.lcut(sen)) # print(word_list) # 3- 训练得到词汇映射器 tokenizer Tokenizer() tokenizer.fit_on_texts(word_list) index_word tokenizer.index_word 排序过程如下 1- 默认按照词在句子中出现的顺序排序 2- 然后出现次数高词频的排在前面 3- 如果词频也相同再词在句子中出现的顺序排序 # print(type(index_word)) # print(index_word) # 4- 创建词嵌入层 word_nums len(index_word) 参数解释 num_embeddings词汇表中词的个数 embedding_dim词向量维度 ebd nn.Embedding(num_embeddingsword_nums,embedding_dim8) # 5- 遍历获得每个词的词向量 for key,value in index_word.items(): # 5.1- 通过【key词索引】获得词向量 # 注意key是词索引是从1开始的 word_vec ebd(torch.tensor(key-1)) # 5.2- 打印输出 print(f词{value}词向量{word_vec}) # 6- 【了解】可视化展示展示词和词之间的相似性 # 注意runs的父目录不能有中文名称 summary SummaryWriter(../../runs) summary.add_embedding(ebd.weight.data, index_word.values()) summary.close()文本数据分析文本数据分析也称为EDAExploratory Data Analysis探索性数据分析。1. 标签数量分布# 导入必备工具包 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() # 注意1sns.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(xlabel, data train_data) # 4 画图展示 plt.title() plt.show() plt.title(train_label) plt.show() # 验证集上标签的数量分布 # 3-2 sns.countplot() 统计label标签的0、1分组数量 sns.countplot(xlabel, data dev_data) # 4-2 画图展示 plt.title() plt.show() plt.title(dev_label) plt.show()2.句子长度分布# 思路分析 : 获取句子长度分布 -绘制句子长度分布-柱状图 句子长度分布-密度曲线图 # 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(xsentence_length, datatrain_data) # 画图展示 plt.xticks([]) plt.show() # 4-2 绘制数据长度分布图-曲线图 sns.displot(xsentence_length, datatrain_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(xsentence_length, datatrain_data) # sns.countplot(xtrain_data[sentence_length]) plt.xticks([]) # x轴上不要提示信息 # plt.title(sentence_length countplot) plt.show() # 5 绘制数据长度分布图-曲线图 sns.displot(xsentence_length, datatrain_data) # sns.displot(xtrain_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(xsentence_length, datadev_data) # sns.countplot(xdev_data[sentence_length]) plt.xticks([]) # x轴上不要提示信息 # plt.title(sentence_length countplot) plt.show() # 5 绘制数据长度分布图-曲线图 sns.displot(xsentence_length, datadev_data) # sns.displot(xdev_data[sentence_length]) plt.yticks([]) # y轴上不要提示信息 plt.show()3.正负样本长度散点分布# 获取正负样本长度散点分布也就是按照x正负样本进行分组 再按照y长度进行散点图 # train_data[sentence_length] list(map(lambda x: len(x), train_data[sentence])) # sns.stripplot(ysentence_length, xlabel, datatrain_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(ysentence_length, xlabel, datatrain_data) plt.show() sns.stripplot(ysentence_length, xlabel, datadev_data) plt.show()4.不同词汇总数统计# 导入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))5.数据集高频形容词词云# 使用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_words100, background_colorwhite) # 准备数据 keywords_string .join (keywords_list) # 分隔符是空格 # 产生词云 wordcloud.generate(keywords_string) # 画图 plt.figure() plt.imshow(wordcloud, interpolationbilinear) 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(list(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(list(n_a_train_vocab))文本特征处理1. N-gramN-gram是将相邻的N个词语组合成新特征的方法帮助模型更好地理解上下文信息。分类uni-gram1-gram单个词如我、爱、北京bi-gram2-gram相邻两个词如我爱、爱北京tri-gram3-gram相邻三个词如我爱北京def n_gram_fn(n_gram): # 1- 测试数据 word_list [aa,bb,cc,dd] # 2- 对相邻的词进行合并 2-gram [aa,bb,cc,dd] [bb,cc,dd] 3-gram [aa,bb,cc,dd] [bb,cc,dd] [cc,dd] lists [word_list[i:] for i in range(n_gram)] print(lists) print(list(zip(*lists))) if __name__ __main__: n_gram_fn(n_gram1) n_gram_fn(n_gram2) n_gram_fn(n_gram3) 结果: [[aa, bb, cc, dd]] [(aa,), (bb,), (cc,), (dd,)] [[aa, bb, cc, dd], [bb, cc, dd]] [(aa, bb), (bb, cc), (cc, dd)] [[aa, bb, cc, dd], [bb, cc, dd], [cc, dd]] [(aa, bb, cc), (bb, cc, dd)] 作用捕捉局部上下文信息增强模型对短语的理解能力2. 句子长度规范为了让模型能够并行处理数据需要将所有句子统一为相同的长度。常用方法截断超出长度的部分截断填充不足长度的部分用特殊标记填充from keras.preprocessing import sequence 句子长度规范的作用【掌握】 1- 数据加载器Dataloader(batch_size1)张量的形状不相同的时候只能设置为1。 因为里面是使用stack对张量进行拼接 stack的要求是张量形状完全相同 stack() 会改变维度数, 拼接张量. 所有的维度都必须保持一致. t1 torch.randn(2, 3) t2 torch.randn(2, 3) result torch.stack([t1, t2], dim0) # 结果形状: (2, 2, 3) 这里底层使用stack拼接一批样本的整体样本特征张量,特征数必须保持一致 2- 迁移学习中有现成的参数可以进行设置 # 1- 准备数据两条句子 sen_list [ [1, 23, 5, 32, 55, 63, 2, 21, 78, 32, 23, 1], [2, 32, 1, 23, 1] ] # 2- 对句子进行截断和填充 max_length 10 参数解释 sequences要处理的句子列表 maxlen最大长度限制 padding填充的方式。默认pre在句子前面填充post在句子后面填充 truncating截断的方式。默认pre在句子前面截断post在句子后面截断 value用来进行填充的值。一般不会修改该参数使用默认的0即可 # result sequence.pad_sequences(sequencessen_list,maxlenmax_length) result sequence.pad_sequences( sequencessen_list, maxlenmax_length, paddingpost, truncatingpost, value6666) print(result)手动实现 sen_list [ [1, 23, 5, 32, 55, 63, 2, 21, 78, 32, 23, 1], [2, 32, 1, 23, 1] ] def my_padding(sen_list ): alist [] for value in sen_list : if len(value) sequence_len: alist.append(value[:sequence_len]) else: value_ value [0]*(sequence_len - len(value)) alist.append(value_)总结与要点回顾模块核心内容重要性NLP定义让计算机理解处理语言文字⭐⭐⭐分词jieba分词、自定义词典⭐⭐⭐NER/POS实体识别、词性标注⭐⭐文本表示One-hot、Word2Vec、Word Embedding⭐⭐⭐数据分析EDA、分布分析⭐⭐特征处理N-gram、长度规范⭐⭐实战小贴士 分词阶段提前整理好领域词典可以大幅提升分词效果文本表示对于大部分任务预训练的Word Embedding比随机初始化效果更好数据分析不要跳过EDA它能帮你避免很多后续的坑N-gram选择通常使用bi-gram和tri-gram太大容易导致数据稀疏欢迎讨论交流如有错误请指正, 持续更新, 大家可关注等待#NLP #自然语言处理 #文本预处理 #机器学习 #深度学习 #AI入门
自然语言处理(NLP)文本预处理
第一章 自然语言处理入门什么是NLPNLPNatural Language Process自然语言处理是人工智能领域的一个重要分支其核心目标是让程序能够理解并处理我们所说的语言文字。简单来说就是让计算机能够像人类一样理解、分析和生成自然语言文本。第二章 文本预处理文本预处理是NLP任务中最基础也是最关键的一步直接影响后续模型的效果。1. 分词器分词是将连续的文本切分成独立的词语或词汇单元的过程。# coding:utf-8 import jieba content 阿珍爱上了阿强,在一个没有星星的夜晚,爱情不是nothing! result0 jieba.cut(content) # generator object Tokenizer.cut at 0x00000234E0BF8270 result1 jieba.lcut(content) result2 jieba.lcut(content, cut_allTrue) result3 jieba.lcut_for_search(content) print(f精确模式分词result0--》{result0}) print(f精确模式分词result1--》{result1}) print(f全模式分词result2--》{result2}) print(f搜索引擎分词result3--》{result3})特点支持简体和繁体中文分词采用基于统计和规则的分词算法自定义词典当处理特定业务场景时通用分词可能无法满足需求需要引入自定义词典jieba.load_userdict(自定义词典路径.txt) result jieba.lcut(content) # 默认精确分词适用场景专业领域术语、公司内部产品名、特定人名等2. 命名实体识别NERNERNamed Entity Recognition用于识别文本中具有特殊含义的实体。常见的实体类型 人名如张三、李白 地名如北京、珠穆朗玛峰 机构名如清华大学、阿里巴巴️ 组织名如联合国、红十字会3. 词性标注POSPOSPart-of-Speech Tagging是对每个词语进行词性分类的过程。常见的词性类型名词n.动词v.形容词adj.副词adv.等等...import jieba.posseg as pseg content 我喜欢学习 res pseg.lcut(content) print(res) for word, flag in res: print(f{word}/{flag}) # [pair(我, r), pair(喜欢, v), pair(学习, v)] # 我/r # 喜欢/v # 学习/v文本张量的表示形式计算机无法直接理解文字需要将文本转换为数值形式张量。1. One-hot编码将每个词表示为一个长向量只有一个位置为1其余为0。优点✅ 实现简单容易理解✅ 直观明了缺点❌稀疏向量占用大量存储空间和计算资源❌语义割裂无法体现词与词之间的关系近义词无法关联割裂了词与词之间的联系(主要),如果n过大,会导致占用大量内存(维度爆炸)# 导入keras中的词汇映射器Tokenizer from tensorflow.keras.preprocessing.text import Tokenizer # 导入用于对象保存与加载的joblib import joblib vocanbs [喜羊羊, 懒懒, 灰灰, 小懒, 小灰, 小灰灰] my_tokenizer Tokenizer() my_tokenizer.fit_on_texts(vocanbs) print(my_tokenizer.word_index) print(my_tokenizer.index_word) for v in vocanbs: zero_ls [0] * len(vocanbs) index my_tokenizer.word_index[v] - 1 zero_ls[index] 1 print(f当前{v}的one-hot编码是{zero_ls}) # my_path ./mytokenizer # joblib.dump(my_tokenizer, my_path) # print(模型保存成功) # my_tokenizer joblib.load(mypath) token 小灰灰 zero_ls [0] * len(vocanbs) index my_tokenizer.word_index[token] - 1 zero_ls[index] 1 print(f当前{token}的one-hot编码是{zero_ls})2. Word2VecWord2Vec通过训练将词映射为稠密向量能够捕捉词语之间的语义关系。一种无监督(不用人为标注)的训练方法,本质上是训练一个模型,将模型的参数矩阵当作所有词汇的词向量表示.两种训练模式CBOW连续词袋模式原理用上下文预测中间词示意图将模型的权重参数当作词向量表示skip-gram跳词模式原理用中间词预测上下文示意图 如果不管是安装fasttext还是fasttext-wheel都失败那么原因是python版本过高。 操作步骤如下 1- 先进入对应的虚拟环境 2- 安装低版本的python解释器 conda install python3.10 3- 安装fasttext pip install fasttext-wheel -i https://mirrors.aliyun.com/pypi/simple/ import fasttext def demo01(): # 1- 使用无监督学习训练模型 为什么这里只能使用无监督学习 答因为数据中没有明确标记目标值。有监督学习对文件内容有严格要求有__label__ # model fasttext.train_unsupervised(data/fil9) model fasttext.train_unsupervised(../data/gz03ag) # 2- 保存训练好的模型 model.save_model(../model/word2vec.pkl) def demo02(): # 1- 加载训练好的模型 model fasttext.load_model(../model/word2vec.pkl) # 2- 获得某个词的词向量 word_vec model.get_word_vector(hello) print(word_vec) def demo03(): # 1- 加载训练好的模型 model fasttext.load_model(../model/word2vec.pkl) # 2- 获得相近的几个词 # 会从词形、词义方面进行查找。 # result_list model.get_nearest_neighbors(dog) result_list model.get_nearest_neighbors(cat) # 3- 输出 print(result_list) def demo04(): 参数解释 input训练集路径 modelword2vec的模式。默认是skipgram可以设置为cbow dim词向量的维度 epoch训练的轮次 lr初始学习率 thread训练的线程个数 model fasttext.train_unsupervised( inputdata/gz03ag, modelcbow, dim200, epoch1, lr0.1, thread10 ) model.save_model(../model/word2vec_better.pkl) if __name__ __main__: # 1- 训练并保存模型 # demo01() # 2- 获得词的词向量 # demo02() # 3- 获得相近的词 # demo03() # 4- 超参数调优设置【掌握】 demo04()3. Word Embedding词嵌入Word Embedding是将词语映射到低维稠密向量空间的技术是Word2Vec等方法的统称。它能保持词语之间的语义相似性是深度学习NLP任务的基础。import jieba from keras.src.legacy.preprocessing.text import Tokenizer import torch.nn as nn import torch from torch.utils.tensorboard import SummaryWriter if __name__ __main__: # 1- 准备文本内容 sentence1 阿珍爱上了阿强,再一个没有星星的夜晚 sentence2 我爱自然语言处理 sentence_list [sentence1,sentence2] # 2- 对每条句子进行分词 word_list [] for sen in sentence_list: word_list.append(jieba.lcut(sen)) # print(word_list) # 3- 训练得到词汇映射器 tokenizer Tokenizer() tokenizer.fit_on_texts(word_list) index_word tokenizer.index_word 排序过程如下 1- 默认按照词在句子中出现的顺序排序 2- 然后出现次数高词频的排在前面 3- 如果词频也相同再词在句子中出现的顺序排序 # print(type(index_word)) # print(index_word) # 4- 创建词嵌入层 word_nums len(index_word) 参数解释 num_embeddings词汇表中词的个数 embedding_dim词向量维度 ebd nn.Embedding(num_embeddingsword_nums,embedding_dim8) # 5- 遍历获得每个词的词向量 for key,value in index_word.items(): # 5.1- 通过【key词索引】获得词向量 # 注意key是词索引是从1开始的 word_vec ebd(torch.tensor(key-1)) # 5.2- 打印输出 print(f词{value}词向量{word_vec}) # 6- 【了解】可视化展示展示词和词之间的相似性 # 注意runs的父目录不能有中文名称 summary SummaryWriter(../../runs) summary.add_embedding(ebd.weight.data, index_word.values()) summary.close()文本数据分析文本数据分析也称为EDAExploratory Data Analysis探索性数据分析。1. 标签数量分布# 导入必备工具包 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() # 注意1sns.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(xlabel, data train_data) # 4 画图展示 plt.title() plt.show() plt.title(train_label) plt.show() # 验证集上标签的数量分布 # 3-2 sns.countplot() 统计label标签的0、1分组数量 sns.countplot(xlabel, data dev_data) # 4-2 画图展示 plt.title() plt.show() plt.title(dev_label) plt.show()2.句子长度分布# 思路分析 : 获取句子长度分布 -绘制句子长度分布-柱状图 句子长度分布-密度曲线图 # 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(xsentence_length, datatrain_data) # 画图展示 plt.xticks([]) plt.show() # 4-2 绘制数据长度分布图-曲线图 sns.displot(xsentence_length, datatrain_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(xsentence_length, datatrain_data) # sns.countplot(xtrain_data[sentence_length]) plt.xticks([]) # x轴上不要提示信息 # plt.title(sentence_length countplot) plt.show() # 5 绘制数据长度分布图-曲线图 sns.displot(xsentence_length, datatrain_data) # sns.displot(xtrain_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(xsentence_length, datadev_data) # sns.countplot(xdev_data[sentence_length]) plt.xticks([]) # x轴上不要提示信息 # plt.title(sentence_length countplot) plt.show() # 5 绘制数据长度分布图-曲线图 sns.displot(xsentence_length, datadev_data) # sns.displot(xdev_data[sentence_length]) plt.yticks([]) # y轴上不要提示信息 plt.show()3.正负样本长度散点分布# 获取正负样本长度散点分布也就是按照x正负样本进行分组 再按照y长度进行散点图 # train_data[sentence_length] list(map(lambda x: len(x), train_data[sentence])) # sns.stripplot(ysentence_length, xlabel, datatrain_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(ysentence_length, xlabel, datatrain_data) plt.show() sns.stripplot(ysentence_length, xlabel, datadev_data) plt.show()4.不同词汇总数统计# 导入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))5.数据集高频形容词词云# 使用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_words100, background_colorwhite) # 准备数据 keywords_string .join (keywords_list) # 分隔符是空格 # 产生词云 wordcloud.generate(keywords_string) # 画图 plt.figure() plt.imshow(wordcloud, interpolationbilinear) 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(list(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(list(n_a_train_vocab))文本特征处理1. N-gramN-gram是将相邻的N个词语组合成新特征的方法帮助模型更好地理解上下文信息。分类uni-gram1-gram单个词如我、爱、北京bi-gram2-gram相邻两个词如我爱、爱北京tri-gram3-gram相邻三个词如我爱北京def n_gram_fn(n_gram): # 1- 测试数据 word_list [aa,bb,cc,dd] # 2- 对相邻的词进行合并 2-gram [aa,bb,cc,dd] [bb,cc,dd] 3-gram [aa,bb,cc,dd] [bb,cc,dd] [cc,dd] lists [word_list[i:] for i in range(n_gram)] print(lists) print(list(zip(*lists))) if __name__ __main__: n_gram_fn(n_gram1) n_gram_fn(n_gram2) n_gram_fn(n_gram3) 结果: [[aa, bb, cc, dd]] [(aa,), (bb,), (cc,), (dd,)] [[aa, bb, cc, dd], [bb, cc, dd]] [(aa, bb), (bb, cc), (cc, dd)] [[aa, bb, cc, dd], [bb, cc, dd], [cc, dd]] [(aa, bb, cc), (bb, cc, dd)] 作用捕捉局部上下文信息增强模型对短语的理解能力2. 句子长度规范为了让模型能够并行处理数据需要将所有句子统一为相同的长度。常用方法截断超出长度的部分截断填充不足长度的部分用特殊标记填充from keras.preprocessing import sequence 句子长度规范的作用【掌握】 1- 数据加载器Dataloader(batch_size1)张量的形状不相同的时候只能设置为1。 因为里面是使用stack对张量进行拼接 stack的要求是张量形状完全相同 stack() 会改变维度数, 拼接张量. 所有的维度都必须保持一致. t1 torch.randn(2, 3) t2 torch.randn(2, 3) result torch.stack([t1, t2], dim0) # 结果形状: (2, 2, 3) 这里底层使用stack拼接一批样本的整体样本特征张量,特征数必须保持一致 2- 迁移学习中有现成的参数可以进行设置 # 1- 准备数据两条句子 sen_list [ [1, 23, 5, 32, 55, 63, 2, 21, 78, 32, 23, 1], [2, 32, 1, 23, 1] ] # 2- 对句子进行截断和填充 max_length 10 参数解释 sequences要处理的句子列表 maxlen最大长度限制 padding填充的方式。默认pre在句子前面填充post在句子后面填充 truncating截断的方式。默认pre在句子前面截断post在句子后面截断 value用来进行填充的值。一般不会修改该参数使用默认的0即可 # result sequence.pad_sequences(sequencessen_list,maxlenmax_length) result sequence.pad_sequences( sequencessen_list, maxlenmax_length, paddingpost, truncatingpost, value6666) print(result)手动实现 sen_list [ [1, 23, 5, 32, 55, 63, 2, 21, 78, 32, 23, 1], [2, 32, 1, 23, 1] ] def my_padding(sen_list ): alist [] for value in sen_list : if len(value) sequence_len: alist.append(value[:sequence_len]) else: value_ value [0]*(sequence_len - len(value)) alist.append(value_)总结与要点回顾模块核心内容重要性NLP定义让计算机理解处理语言文字⭐⭐⭐分词jieba分词、自定义词典⭐⭐⭐NER/POS实体识别、词性标注⭐⭐文本表示One-hot、Word2Vec、Word Embedding⭐⭐⭐数据分析EDA、分布分析⭐⭐特征处理N-gram、长度规范⭐⭐实战小贴士 分词阶段提前整理好领域词典可以大幅提升分词效果文本表示对于大部分任务预训练的Word Embedding比随机初始化效果更好数据分析不要跳过EDA它能帮你避免很多后续的坑N-gram选择通常使用bi-gram和tri-gram太大容易导致数据稀疏欢迎讨论交流如有错误请指正, 持续更新, 大家可关注等待#NLP #自然语言处理 #文本预处理 #机器学习 #深度学习 #AI入门