0、前言
本文旨在对自己命名实体识别中词向量与标注预处理阶段的总结。此处假设给定大量文本,以及部分对应的标注(此处使用的是IOB标注方案),但是文本与标注是分开存储的。
在我们进行NER的预测任务之前,我们需要做以下工作:
(1)对每个文本进行分词(当然这里分词也要注意用什么标准进行分词,此处不解释),然后用空格(join)连接每个词,同时对部分文本进行打标注,分开存储成两个文件。
(2)对分好词的文本进行(split)汇总得到总语料,把语料放进去定义好的word2vec模型(调参min_count和size)里面进行训练,得到每个词对应的词向量。
(3)对每篇分词好的文本进行截断处理,然后做词向量拼接。所谓拼接,依据每个词对应的词向量按照顺序依次拼接起来,如果不足句子长度,则padding补0。补0的长度注意要对应上word2vec自定义的词向量长度m,并且少n个词就要补n*m个0。
(4)对标注文件进行截断得到标注列表,列表长度与截断后的文本长度一致。当然可能存在长度不足的情况,直接补0到长度一致即可。然后用LabelEncoder对标注列表进行onehot(提示:先对所有的标注列表展平,转为array再onehot,onehot好之后再reshape回去)。
1、代码如下
将标注的文件夹和存放文本的文件夹进行数据合并,文本合并到一起,标注合并到一起
#source_folder与target_folder分别文本文件夹和标注文件夹
import os
def get_train_list(source_folder, target_folder):
source_string = []
target_string = []
for filename in os.listdir(source_folder):
target_file_name = "targetH_" + "_".join(filename.split("_")[1:])
if os.path.exists(os.path.join(target_folder, target_file_name)):
with open(os.path.join(source_folder, filename), 'r', encoding="utf-8") as source:
with open(os.path.join(target_folder, target_file_name), 'r', encoding="utf-8") as target:
for source_line, target_line in zip(source.readlines(), target.readlines()):
s_line = source_line.split()
t_line = target_line.split()
if len(s_line) == len(t_line):
#如果长度对应不上就不要添加进去了
#所以此处做成的source_string可能与corpus语料库长度不同
source_string.append(s_line)
target_string.append(t_line)
#要导入logging模块
#logger.info('源数据读取完毕,共' + str(len(source_string)) + '行')
print('源数据读取完毕,共' + str(len(source_string)) + '行')
return source_string, target_string
制作语料库,list里面的每个list放一个句子,之前句子先用split去掉空格,所以语料库中每个list长度不一
def read_file_to_corpus(folder):
corpus = []
for filename in os.listdir(folder):
with open(os.path.join(folder, filename), encoding="utf-8") as f:
for line in f:
corpus.append(line.split())
return corpus
进行词向量训练,喂进去的词必须是分好了的词的corpus,但是每个句子可以分开在不同的list里面,不用flatten
from gensim.models import Word2Vec
NER_FOLDER = "C:\\Users\\1\\Desktop\\project&learning\\jinrongzhishitupu\\9.18\\data"
def get_vec_from_corpus(corpus, size=128, min_count=2, save_path=os.path.join(NER_FOLDER, "ner_word2vec_model")):
vec_model = Word2Vec(corpus, size, min_count)
vec_model.save(save_path)
return vec_model
对列表中的句子进行向量拼接,维度为128,不足就补零,不存在word2vec模型里面的词也进行补零
def get_train_feature(source_string, vec_model, embedding_size=128, max_sequence=10):
#注意要获得Word2Vec里面的词一定要调用.wv.index2word属性
index2word_set = set(vec_model.wv.index2word)
row_vector_list = []
for source_line in source_string:
i = 0
row_vector = []
for source_word in source_line:
if i < max_sequence:
if source_word in index2word_set:
#注意此处用的是np.append(),为了避免list和array转换不对应
#np.append()是直接将array里面的元素叠加,而不是[[...],[...],[...]]形式
row_vector= np.append(row_vector, vec_model[source_word])
else:
row_vector = np.append(row_vector, np.zeros(embedding_size, dtype='float32'))
i += 1
if len(source_line) < max_sequence:
row_vector = np.append(row_vector,
np.zeros((embedding_size * (max_sequence - len(source_line)),),
dtype='float32'))
row_vector_list.append(row_vector)
return np.matrix(row_vector_list,dtype='float32')
将target进行LabelEncode
from sklearn.preprocessing import LabelEncoder
class OneHot(object):
def __init__(self):
self.__label_encoder = LabelEncoder()
def encode_label(self, target_list):
integer_encoded = self.__label_encoder.fit_transform(np.array(target_list))
return integer_encoded
def decode(self, encoder_list):
return self.__label_encoder.inverse_transform([np.argmax(np.array(encoder_list), axis=1)])
def get_target_label(target_string,max_sequence=10):
onehot_model = OneHot()
for i in range(0, len(target_string)):
if len(target_string[i]) < max_sequence:
target_string[i] = target_string[i].extend(["O"]*(max_sequence - len(target_string[i])))
if target_string[i] is None:
target_string[i] = ["O"]*max_sequence
else:
if target_string[i] is None:
target_string[i] = ["O"]*max_sequence
else:
target_string[i] = target_string[i][0:max_sequence]
#print(np.array(target_string).shape)
num_rows = len(target_string)
#先将那些标注进行合并展平,统一进行label_encode
flat_list = [item for sublist in target_string for item in sublist]
target_vector = onehot_model.encode_label(flat_list)
target_vector = target_vector.reshape(-1, max_sequence)
return target_vector, onehot_model