NER -- 词向量与标注预处理阶段

版权声明:转载请声明转自Juanlyjack https://blog.csdn.net/m0_38088359/article/details/83622453

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
展开阅读全文

没有更多推荐了,返回首页