使用 Spacy 创建自定义命名实体识别

630 阅读5分钟

考虑这样一种情况,您拥有居住在一个特定地理位置的人口的完全非结构化数据,这些数据具有各种属性,如姓名、出生日期、资产、地址和任何医疗状况。

现在你的任务是从这些文件中提取信息,如姓名和医疗疾病,以推断哪个名字在该地区最常见,以及人们在这些地方遭受的所有医疗状况,以采取预防措施。现在,一种方法可以手动执行此操作,另一种方法可以对所有可能的姓名和医疗条件进行硬编码,但总是有可能遗漏很多人名或医疗条件。

图片中出现了命名实体识别。命名实体识别 (NER) 是属于信息提取 (IE) 的自然语言处理 (NLP) 工作。(自然语言处理)。它是将非结构化文本中已识别的实体定位和分类到预定组中的过程,例如人名、地名和组织等。NER 在各种 NLP 应用程序中起着至关重要的作用,例如问答、文本摘要、情感分析等。在本文中,我将逐步解释如何在大型数据集上使用 SpaCy 包创建自己的自定义 NER,实体名称为列名。

首先,确保您的系统中安装了 Spacy。要安装类型,在 cmd 中:

pip 安装 spacy

然后为了在分类数据的情况下将实体名称作为列名称,首先从要训练自定义 NER 的分类列创建一个字典,如下所示:

import pandas as pd 
import datetime 
import re 

#lower casing 
def  all_lower ( my_list ): 
    return [x.lower() for x in my_list] 

# removing \n 
def  removing_char ( lst ): 
    temp = [] 
    for x in lst: 
        temp。 append(x.strip()) 
    return temp 

#separating into strings 并创建标签
def  single_value ( lst ): 
    z = '' 
    forlst中的行:
        z = z + ',' + line 
    temp = z.split( ',' ) 
    tag_list = [] 
    for x in temp: 
        tag_list.append(x.strip()) 
    return  set (tag_list) 

data_frame = pd .read_csv( "your dataset path" ) 
d={} 

for col in data_frame[ '要为其创建自定义 NER 的分类列的名称' ]: 
    d[col]=pd.unique(data_frame[col].dropna( )) 
 
del data_frame 

entity_labels={} 

for key, value ind.items(): 
  entity_labels[key] = single_value(removing_char(all_lower(value)) 
del d 

# 这里的 entity_labels 是你想要训练 NER 的分类字典

准备训练数据:

现在从 spacy 导入 spacy 模块和小批量和复合(小批量用于批量训练,复合告诉批量预处理的大小和增量)。

之后,我们将导入要在其上创建自定义 NER 的数据集。然后遍历熊猫数据框的每一行df,并为字典中指定的每个实体提取文本和标签entity_labels。同时检查当前列中的值是否不为空。如果它不为空,它会创建一个包含文本及其相应实体标签的元组并将其附加到列表中train_data

如果你的数据包含一列,比如用','分隔值的标签,如'ml,dl,ai',那么你也可以添加下面的解释和代码。

如果该列是Tags,它会用逗号分隔值,创建包含每个标记的开始和结束索引的元组列表,并将其附加到列表中train_data。如果该列不是Tags,它只是创建一个包含整个文本的开始和结束索引的元组,并将其附加到列表中train_data

import spacy 
from spacy.util import minibatch, compounding 


# 读取 CSV 文件
df = pd.read_csv( "training_data_for_ner.csv" ) 

# 这里我们准备训练数据
train_data = [] 

# 遍历 CSV 文件中的每一行以
获得索引, row in df.iterrows(): 
    # 提取每个实体的文本和标签
    for column, label in entity_labels.items(): 
        # 检查当前列中的值是否不为空
        if row[column]: 
            if column = = '标签':
                尝试:
                    
                    start_end_index = [] 
                    start = 0 
                    for i, word in  enumerate (row[column].split( "," )): 
                        end = start + len (word) 
                        start_end_index.append((start, end,column))
                        开始 = 结束+ 1

                     train_data.append((row[column],{ "entities" :start_end_index})) 
                except : 
                    pass 
            # 将文本、开始索引、结束索引和标签添加到训练数据中
            else : 
                try : 

                    train_data.append((行列], {“实体”:[(0,len(行[列]),列)]}))
                除了:
                    通过

在训练前定义变量。首先设置batch_size,然后设置要跟随的迭代。现在检查“ner”是否在管道中,如果不在,则将“ner”添加到管道中,如下所示:

# 定义迭代次数和批量大小
n_iter = 100
 batch_size = 32 
# 加载预训练模型
nlp = spacy.load( "en_core_web_lg" ) 

# 在模型中创建一个新的实体类型
ner = nlp.create_pipe( "ner" ) 
nlp.add_pipe(ner, last= True ) 
# 获取空白模型中管道的名称 pipe_names
 = [pipe_name for pipe_name in nlp.pipe_names] 

# 如果实体识别器不存在则将其添加到空白模型中
if  " ner" 不在pipe_names 中:
    # ner = nlp.create_pipe("ner")
    ner = nlp.add_pipe( "ner" ) 
    # nlp.add_pipe(ner, last=True) 
else : 
    ner = nlp.get_pipe( "ner" ) 

# 添加实体标签到实体识别器

之后我们就可以开始训练了。

nlp我们首先禁用对象中除 NER 组件之外的所有其他管道组件。

接下来,我们为模型定义一个优化器并初始化损失字典,然后使用循环训练模型进行指定次数的迭代。

在每次迭代中,代码对训练数据进行混洗并使用函数创建数据批次minibatch,该函数使用复合函数创建大小不断增加的批次。批次的大小由batch_size参数指定,最大批次大小由指定max_batch_size

然后我们遍历批次并使用该nlp.update()方法更新模型。此方法接收一批文本及其相应的注释,并相应地更新模型的权重。

texts为了将每个批次中的和转换为可用于更新模型的annotationsspaCy对象,我们为每个文本创建一个对象,然后使用该方法创建一个对象。Example``doc``nlp.make_doc()``Example``Example.from_dict()


# 禁用管道中的其他管道 other_pipes
 = [pipe for pipe in nlp.pipe_names if pipe != "ner" ] 
with nlp.disable_pipes(*other_pipes): 
    # 定义优化器并获取损失
    optimizer = nlp.begin_training() 
    losses = {} 

    # 训练模型进行指定的迭代次数
    for i in  range (n_iter): 
        # 打乱训练数据
        random.shuffle(train_data) 
        # 创建训练数据的批次
        # batches = minibatch(train_data, size=compounding (batch_size, max_batch_size=128))
        batches = minibatch(train_data, size=compounding(start= 2 , stop =batch_size,compound= 2 )) 
        # 遍历批次并分批更新模型:
        texts ,             annotations = zip (*batch) # nlp.update (texts, annotations, sgd=optimizer, losses=losses)             example = [] # 通过迭代每个文本更新模型for i in range ( len (texts)):                 doc = nlp.make_doc(texts[i])                 example.append (Example.from_dict(doc, annotations[i]))

            

    
             


            nlp.update(example, sgd=optimizer, losses=losses) 

# 将模型保存到磁盘
nlp.to_disk( "custom_ner_model" )

为了测试实体识别,我们可以使用如下代码:

doc = nlp( "write your query to test your entity recognition here" ) 
for ent in doc.ents: 
    print (ent.text,ent.label_) 

ents = [ent.text for ent in doc.ents]
打印(ents)

这就是您可以创建自定义命名实体识别并在您的项目中使用它的方法。