当前位置:   article > 正文

自然语言处理(NLP)(一)文本预处理篇之分词、向量表示和特征处理_分词向量

分词向量


最近项目需要,终于要开始认认真真学习NLP了(之前就蛮感兴趣的)。这里主要是记录跟着B站黑马视频的笔记以及实际操作过程中遇到的问题。

NLP教程

一、文本处理

文本语料在输送给模型之前一般需要一系列的预处理工作,才能符合模型输入的要求,如:将文本转化成模型需要的张量。

1. 文本预处理的基本方法

1.1 jieba模块分词

首先安装jieba:

pip3 install jieba
  • 1
1.1.1 精确模式分词

精确模式分词:试图将句子最精确地切开,适合文本分析
使用方式:

import jieba
content = "工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作"
# 返回一个生成器对象
jieba.cut(content, cut_all=False) # cut_all默认为False,精确模式进行切割
# 若需要返回列表内容,使用jieba.lcut
jieba.lcut(content, cut_all=False)
# ["工信处", "女干事", "每月", "经过"......]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
1.1.2 全模式分词

全模式分词:把句子中所有的可以成词的词语都扫描出来,速度非常快,但是不能消除歧义。
使用方式:

jieba.cut(content, cut_all=False) 
# cut_all默认为False,精确模式进行切割
# True为全模式
jieba.lcut(content, cut_all=True)
# ['公信处', '处女', '女干事', '干事', '每月', '月经', '经过'......]
  • 1
  • 2
  • 3
  • 4
  • 5
1.1.3 搜索引擎模式分词

搜索引擎模式分词:在精确模式的基础上,对长词再次切分,提高召回率,适用于搜索引擎分词。
使用方式:

jieba.lcut_for_search(content)
# ['公信处', '干事', '女干事', '每月', '经过', '下属', ......]
  • 1
  • 2
1.1.4 中文繁体分词

中文繁体分词:针对香港台湾地区的繁体文本进行分词

jieba.lcut(fan_content) # 直接输入繁体内容即可
  • 1

使用用户自定义词典:添加自定义词典后,能够精确识别词典中出现的词汇,提升整体的识别准确率。词典格式:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。如:

云计算 5 n
李晓福 2 nr
easy_install 3 eng
......
  • 1
  • 2
  • 3
  • 4
1.1.5 自定义词典分词

利用自定义词典进行分词:

jieba.lcut(content)
jeiba.load_userdict("自定义词典路径")
jieba.lcut(content)
  • 1
  • 2
  • 3

1.2 hanlp模块

安装:

pip3 install hanlp
  • 1
1.2.1 中文分词

中文分词

import hanlp
# 加载CTB_CONVSEG预训练模型进行分词任务
tokenizer = hanlp.load('CTB6_CONVSEG')
tokenizer(content)
  • 1
  • 2
  • 3
  • 4
1.2.2 英文分词

英文分词

tokenizer = hanlp.utils.rules.tokenize_english
tokenizer(content)
  • 1
  • 2
1.2.3 命名实体识别

命名实体识别(Named Entity Recoginition):人名、地名、机构名等专有名词识别。
中文命名实体识别

# 加载中文命名实体预训练模型MSRA_NER_BERT_BASE_ZH
recognizer = hanlp.load(hanlp.pretrained.ner.MSRA_NER_BERT_BASE_ZH)
recognizer(list(content))
# 返回一个装有n个元组的列表,每个元组代表一个命名实体
  • 1
  • 2
  • 3
  • 4

英文命名实体识别

# 加载英文命名实体预训练模型CONLL03_NER_BERT_BASE_UNCASED_EN
recognizer = hanlp.load(hanlp.pretrained.ner.CONLL03_NER_BERT_BASE_UNCASED_EN)
recognizer(list(content))
  • 1
  • 2
  • 3
1.2.4 词性标注

中文词性标注

import jieba.posseg as pseg
pseg.lcut("我爱北京天安门")
# [pair('我', 'r'), pair('爱', 'v'), ......]
tagger = hanlp.load(hanlp.pretrained.pos.CTB5_POS_RNN_FASTTEXT_ZH)
trager(list(content))
# 返回对应的词性列表
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

英文词性标注

tagger = hanlp.load(hanlp.pretrained.pos.PTB_POS_RNN_FASTTEXT_EN)
trager(list(content))
  • 1
  • 2

2. 文本张量表示方法

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

2.1 one-hot词向量表示

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

from sklean.externals import joblib
from keras.preprocessing.text import Tokenizer
vocab = {"周杰伦","陈奕迅","王力宏","李宗盛","吴亦凡","鹿晗"}
t = Tokenizer(num_words=None,char_level=False)
t.fit_on_text(vocab)
for token in vocab:
	zero_list = [0]*len(vocab)
	token_index = t.texts_to_sequences([token])[0][0]-1
	zero_list[token_list] = 1
	print(token, "的one-hot编码为:", zero_list)
# 使用joblib工具保存映射器,以便之后使用
tokenizer_path = "。/Tokenizer"
joblib.dump(t, tokenizer_path)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

one-hot编码器的使用:

t = joblib.load(tokenizer_path)
token = "李宗盛"
token_index = t.texts_to_sequence([token])[0][0] - 1
zero_list = [0]*len(vpocab)
zero_list[token_index] = 1
print(token, "的one-hot编码为:", zero_list)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

优势:操作简单,容易理解
缺点:割裂了词语之间的联系,在大语料库的情况下,编码会过长。

2.2 word2vec

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

2.2.1 CBOW(Continuous bag of words)模式

给定一段用于训练的文本语料,再选定某段长度(窗口)作为研究对象,使用上下文词汇预测目标词汇,如:
在这里插入图片描述

理论部分:
在这里插入图片描述

在这里插入图片描述

2.2.2 skipgram模式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.2.3 使用fasttext工具实现word2vec
  1. 获取训练数据
    终端输入:
$ mkdir data
$ wget -c http://mattmahoney.net/dc/enwik9.zip -P data
$ unzip data/enwik9.zip -d data
# 查看原始数据前10行
$ head -10 data/enwik9
# 使用wikifil.pl文件清除脚本XML/HTML格式
# 脚本去教程那里看看有没有
$ perl wikifil.pl data/enwik9 > data/fil9
# 查看处理后的前80个字符
$ head -c 80 data/fil9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  1. 训练词向量
import fasttext
model = fasttext.train_unsupervised('data/fil9')
# 查看对应单词的词向量
model.get_word_vector("the")
  • 1
  • 2
  • 3
  • 4
  1. 模型超参数设定
# 默认skipgram,在利用子词方面比cbow好
# 词嵌入维度默认为100,随着语料库增大而增加
# lr默认0.05
# 线程默认为12
model = fasttext.train_unsupervised('data/fil9', 'cbow', dim=300, epoch=1, lr=0.1, thread=8)
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 模型效果检验
# 查看相近的词
model.get_nearest_neighbors('sports')
  • 1
  • 2
  1. 模型的保存与重新加载
model.save_model("fil9.bin")
model = fasttext.load_model("fil9.bin")
model.get_word_vector("the")
  • 1
  • 2
  • 3

2.3 word embedding(词嵌入)

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

通过tensorboard可视化嵌入的词向量:

import torch
import json
from torch.utils.tensorboard import SummaryWriter
# 实例化一个摘要写入对象
writer = SummaryWriter()
# 随机初始化一个100*5的矩阵,认为它是我们已经得到的词嵌入矩阵
# 代表100个词汇,每个词汇被表示成50维的向量
embedded = torch.randn(100, 50)

# 导入事先准备好的100个中文词汇文件,形成meta列表原始词汇
meta = list(map(lambda x:x.strip(), fileinput("./vocab100.csv")))
writer.add_embedding(embedded, metadata=meta)
wrtier.close()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在终端启动tensorboard服务:

$ tensorboard --logdir runs --host 0.0.0.0
# 通过http://0.0.0.0:6006访问浏览器可视化页面
  • 1
  • 2

3. 文本数据分析

文本数据分析能够有效帮助我们理解数据语料,快速检查出语料可能存在的问题,并指导之后超参数的选择。

3.1 标签数量分布

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("fivethirtyeight")
train_data = pd.read_csv(训练数据路径, sep='\t')
valid_data = pd.read_csv(验证数据路径, sep='\t')

# 获取训练集数据标签数量分布
sns.countplot('label', data=train_data)
plt.title('train_data')
plt.show()

# 获取验证集数据标签数量分布
sns.countplot('label', data=valid_data)
plt.title('valid_data')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

3.2 句子长度分布

tran_data['sentence_length'] = list(map(lambda x:len(x), train_data["sentence"])

# 绘制句子长度烈的数量分布图
sns.countplot("sentence_length", data=train_data)
plt.xticks([])
plt.show()

# 绘制dist长度分布图
sns.distplot(train_data["sentence_length"])
plt.yticks([])
plt.show()

valid_data['sentence_length'] = list(map(lambda x:len(x), valid_data["sentence"])

# 绘制句子长度烈的数量分布图
sns.countplot("sentence_length", data=valid_data)
plt.xticks([])
plt.show()

# 绘制dist长度分布图
sns.distplot(valid_data["sentence_length"])
plt.yticks([])
plt.show()

# 绘制训练集长度分布的散点图
sns.stripplot(y="sentence_length", x="label", data=train_data)
plt.show()
# 绘制验证集长度分布的散点图
sns.stripplot(y="sentence_length", x="label", data=valid_data)
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

3.3 词频统计与关键词词云

  1. 词频统计
import jieba
from itertools import chain
train_vocab = set(chain(*map(lambda x: jieba.lcut(x), train_data["sentence"])))
print("训练集共包含不同词汇总数为:", len(train_vocab))
  • 1
  • 2
  • 3
  • 4
  1. 关键词词云
import jieba.posseg as pseg
def get_a_list(text):
	r = []
	for g in pesg.lcut(text):
		if g.flag == 'a':
			r.append(g.word)
	return r

from wordcloud import WordCloud
def get_word_cloud(keywords_list):
	wordcloud = WordCloud(font_path="字体路径", 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()
# 获取训练集上的正样本
p_train_data = train_data[train_data["label"]==1]["sentence"]

# 对正样本的每个句子的形容词
train_p_a_vocab = chain(*(map(lambda x: get_a_list(x), p_train_data)))

get_word_cloud(train_p_a_vocab)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

4. 文本特征处理

文本特征处理是为语料库添加具有普适性的文本特征。

4.1 添加n-gram特征

给定一段文本序列,其中n个词或字的相邻共现特征即n-gram特征,常用的是bi-gram和tri-gram特征。
在这里插入图片描述

提取n-gram特征:

ngram_range = 2
def create_ngram_set(input_list):
	return set(zip(*[inputlist[i:] for i in rannge(ngram_range)]))
input_list = [1, 3, 2, 1, 5, 3]
res = create_ngram_set(input_list)
print(res)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4.2 文本长度规范

from keras.preprocessing import sequence
cutlen = 10
def padding(x_train):
	return sequence.pas_sequence(x_train, cutlen)
# 长度超过的切掉前面的,长度少的前部分补0
x_train = [[1, 22, 33, 21, 22, 3424, 3123, 31], [3133, 1, 22, 555, 44, 22, 32, 22]]
res = padding(x_train)
print(res)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5. 文本数据增强(回译)

回译数据增强:翻译成小语种,再翻译回来,就会在原始基础语料标签上增加新的语料(最多采用3次连翻)。

p_sample1 = '酒店设置非常不错'
p_sample2 = '这家价格很便宜'
n_sample1 = '拖鞋都发霉了,太差了'
n_sample1 = '电视不好用'

from googletrans import Translator
translator = Translator()
translations = translator.translate([p_sample1, p_sample2, n_sample1, n_sample2], dest='ko')
ko_res = list(map(lambda x: x.text, translations))
print("中间翻译结果:")
print(ko_res)
translations = translator.translate(ko_res, dest='zh-cn')
cn_res = list(map(lambda x: x.text, translations))
print("回译得到的增强数据:")
print(cn_res)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/195712
推荐阅读
相关标签
  

闽ICP备14008679号