BIO格式NER数据集转换为json

摘要:

        参考该博主文章转化BIO命名实体识别(NER)数据格式,增加了实体类型统计的功能,在MSRA数据集上测试,与数据集描述中的各实体类型数量匹配。

功能:

        将BIO格式的NER数据集保存为json文件,并输出各类型实体的数量。

BIO格式数据如图:

转换之后的json如图:

MSRA数据集描述:

实体数量统计:

代码:

import json
import pandas as pd


def get_data(input_file):
    """
    将BIO格式数据转换为json格式
    Args:
        input_file: BIO格式数据存储位置

    Returns:result,字典列表形式的BIO数据

    """
    result = []

    with open(input_file, 'r', encoding='utf-8') as f:
        texts = f.read().rstrip()
        data = texts.split('\n\n')

        for i in range(len(data)):
            line = data[i].split('\n')
            start, end = -1, 0
            offsets = []  # 存储每个实体的起始下标位置和结束下标位置
            texts = []
            labels = []
            for idx, item in enumerate(line):
                item_split = item.split('\t')  # 实体和标签之间的分隔符
                if len(item_split) == 2:
                    word, label = item_split
                else:
                    print(item_split)
                texts.append(word)
                labels.append(label)

                # 处理空标签情况,当作O标签处理
                if not len(label) or label.isspace():
                    print("空标签:", item_split)
                    label = 'O'
                # 处理B标签
                if label[0] == 'B':
                    # 处理“BIIBI”,“BBI”类型
                    if len(labels) >= 2:
                        if labels[-2][0] == "I" or labels[-2][0] == "B":
                            end = idx
                            offsets.append((start, end))
                    start, end = idx, 0
                    continue
                # 处理I标签
                if label[0] == 'I':
                    # 一定得是B在I前面,否则数据错误
                    if start >= 0:
                        end = idx
                    else:
                        print("错误:I在B前:", labels, label)
                    continue
                # 处理O标签
                if label == 'O':
                    if start >= 0:
                        end = idx
                        offsets.append((start, end))
                        # 找到就恢复初始值,寻找下一个B标签
                        start, end = -1, 0
                    continue


            texts = ''.join(texts)
            ents = [
                (texts[start:end], labels[start][2:])
                for start, end in offsets
            ]

            # 处理以“BI"结尾的情况,前面用texts[start:end]取不到最后一个字符,因为是前闭后开区间
            if start >= 0 and end:
                # offsets.append((start, end))
                ents.append((texts[start:], labels[start][2:]))

            line_dict = {
                "text": texts,
                "entity": [
                    {'entity': entity, 'entity_type': entity_type}
                    for entity, entity_type in ents
                ]
            }

            result.append(line_dict)

    return result


def check_data(data):
    """
    获取句子数,实体总数目,各实体类型数量
    Args:
        data: 字典列表格式标注数据

    Returns:nums_dict,一个存储句子数,实体总数目,各实体类型数量的dict

    """

    nums_dict = {"sentence": len(data), "entity_all": 0, "LOC": 0, "ORG": 0, "PER": 0}

    for each_dict in data:

        if len(each_dict["entity"]):
            nums_dict["entity_all"] += len(each_dict["entity"])

            for each in each_dict["entity"]:
                if each["entity_type"] == "LOC":
                    nums_dict["LOC"] += 1
                if each["entity_type"] == "ORG":
                    nums_dict["ORG"] += 1
                if each["entity_type"] == "PER":
                    nums_dict["PER"] += 1

    return nums_dict


if __name__ == "__main__":

    # input_file = "data/Sighan2006NER/test.txt"
    # output_file = "data/Sighan2006NER/test.json"

    # input_file = "data/CLUE Fine-Grain NER/train.json"
    # output_file = "data/CLUE Fine-Grain NER/train.json"

    # input_file = "data/MSRA/msra_test_bio.txt"
    # output_file = "data/MSRA/msra_test_bio.json"

    input_file = "data/MSRA/msra_train_bio.txt"
    output_file = "data/MSRA/msra_train_bio.json"

    # 将BIO格式数据转换为json格式
    result = get_data(input_file)

    # 检查数据
    nums_dict = check_data(result)
    nums_df = pd.DataFrame(nums_dict, index=[0])
    print("*" * 30)
    print("数量统计结果:\n", nums_df)
    print("*" * 30)

    # 存储数据
    with open(output_file, 'w', encoding='utf-8') as f:
        for item in result:
            f.write(json.dumps(item, ensure_ascii=False) + '\n')

参考:

 转化BIO命名实体识别(NER)数据格式

 MSRA数据集

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用NER标记output.txt文件里json格式的数据的流程如下: 1. 读取output.txt文件中的json数据,可以使用Python内置的json库。 ```python import json with open('output.txt', 'r', encoding='utf-8') as f: for line in f: data = json.loads(line.strip()) # 对每个json数据进行处理 # ... ``` 2. 对每个json数据进行处理,首先需要获取文本内容和实体标签。假设json数据的格式如下: ```json { "status": 0, "message": "success", "result": { "words": [ { "word": "张三", "location": { "left": 123, "top": 45, "width": 67, "height": 89 }, "text_type": "name" }, { "word": "李四", "location": { "left": 234, "top": 56, "width": 78, "height": 90 }, "text_type": "name" }, { "word": "北京市海淀区中关村", "location": { "left": 345, "top": 67, "width": 89, "height": 123 }, "text_type": "address" } ] } } ``` 可以通过以下代码获取文本内容和实体标签: ```python words = data['result']['words'] text = ''.join([word['word'] for word in words]) tags = ['O'] * len(text) # 初始化标签,O表示非实体 for word in words: start = word['location']['left'] end = start + word['location']['width'] tag = 'B-' + word['text_type'] # 实体的开始标签 for i in range(start, end): if i == start: tags[i] = tag else: tags[i] = 'I-' + word['text_type'] # 实体的内部标签 ``` 这里假设实体类型包括name和address,因此实体的标签可以分别为B-name、I-name、B-address和I-address。该代码将文本内容和实体标签保存在text和tags变量中。 3. 对获取到的文本内容和实体标签进行NER标记。可以使用常见的NER模型如CRF、BiLSTM和BERT等进行训练和预测。这里以CRF为例,使用Python库sklearn-crfsuite实现。 ```python from sklearn_crfsuite import CRF from sklearn.model_selection import cross_val_predict from sklearn.metrics import classification_report # 特征提取函数,可以根据实际情况进行修改 def word2features(text, i): features = { 'bias': 1.0, 'word.lower()': text[i].lower(), 'word[-3:]': text[i][-3:], 'word[-2:]': text[i][-2:], 'word.isupper()': text[i].isupper(), 'word.istitle()': text[i].istitle(), 'word.isdigit()': text[i].isdigit() } if i > 0: features.update({ 'prev_word.lower()': text[i-1].lower(), 'prev_word.istitle()': text[i-1].istitle(), 'prev_word.isupper()': text[i-1].isupper() }) else: features['BOS'] = True # 开始位置 if i < len(text) - 1: features.update({ 'next_word.lower()': text[i+1].lower(), 'next_word.istitle()': text[i+1].istitle(), 'next_word.isupper()': text[i+1].isupper() }) else: features['EOS'] = True # 结束位置 return features # 特征集提取函数 def extract_features(text, tags): return [word2features(text, i) for i in range(len(text))], tags # 定义CRF模型 crf = CRF(algorithm='lbfgs', c1=0.1, c2=0.1, max_iterations=100, all_possible_transitions=True) # 特征集提取和标签预测 X, y = [], [] with open('output.txt', 'r', encoding='utf-8') as f: for line in f: data = json.loads(line.strip()) words = data['result']['words'] text = ''.join([word['word'] for word in words]) tags = ['O'] * len(text) # 初始化标签,O表示非实体 for word in words: start = word['location']['left'] end = start + word['location']['width'] tag = 'B-' + word['text_type'] # 实体的开始标签 for i in range(start, end): if i == start: tags[i] = tag else: tags[i] = 'I-' + word['text_type'] # 实体的内部标签 X_i, y_i = extract_features(text, tags) X.append(X_i) y.append(y_i) # 训练CRF模型并进行交叉验证 y_pred = cross_val_predict(crf, X, y, cv=5) # 输出分类报告 print(classification_report(y, y_pred)) ``` 该代码首先定义了一个特征提取函数`word2features()`,用于将每个词转换为一组特征。然后定义了一个特征集提取函数`extract_features()`,用于将文本和实体标签转换为特征集。接着定义了一个CRF模型,并使用交叉验证进行训练和预测。最后输出分类报告,包括精度、召回率和F1得分等指标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值