• 中文文本纠错(CSC)任务Benchmark数据集SIGHAN介绍与预处理


    1. SIGHAN数据集简介

    SIGNHAN是台湾学者(所以里面都是繁体字)公开的用于 中文文本纠错(CSC) 任务的数据集,其目前包含三个版本:

    SIGHAN Bake-off 2013: http://ir.itc.ntnu.edu.tw/lre/sighan7csc.html
    SIGHAN Bake-off 2014: http://ir.itc.ntnu.edu.tw/lre/clp14csc.html
    SIGHAN Bake-off 2015: http://ir.itc.ntnu.edu.tw/lre/sighan8csc.html

    百度网盘链接:https://pan.baidu.com/s/144wHXYHjp0Iwl8ABgV23vw?pwd=f9sd

    上述链接是官方提供的数据源文件,里面有许多错误,如果不想自己修改和预处理,可以直接跳到"第5章 预处理好的数据集",直接使用。

    其包含的训练集和测试集数量如下表:

    数据集句子数量句子平均长度错字数量
    SIGHAN13(训练集)70041.8343
    SIGHAN13(测试集)100074.31224
    SIGHAN14(训练集)343749.65122
    SIGHAN14(测试集)106250.0771
    SIGHAN15(训练集)233931.33037
    SIGHAN15(测试集)110030.6703

    上述数据的数据量每个论文还不太一样,可能是因为他们对于训练集的处理方式不太一样。

    整体来说,SIGHAN包含的训练数据集较少,所以通常人们都是先使用其他数据集对模型进行训练,再使用SIGHAN训练集对模型进行fine-tune。

    2. SIGHAN数据集文件内容

    以SIGHAN15为例,下载后的目录结构如下:

    └─sighan8csc_release1.0   # 文件根目录
        │  README  # 简要的说明文档
        │  SIGHAN8CSC_Overview.pdf  # SIGHAAN数据集介绍
        │
        ├─Dry   # 用于数据格式验证的预演数据集。没啥用
        │      SIGHAN15_CSC_DryInput.txt
        │      SIGHAN15_CSC_DryTruth.txt
        │
        ├─Test # 测试集
        │      SIGHAN15_CSC_TestInput.txt
        │      SIGHAN15_CSC_TestSummary.xlsx
        │      SIGHAN15_CSC_TestTruth.txt
        │
        ├─Tool # 官方提供的工具,用于验证你的结果 
        │      sighan15csc.jar  # 工具,Java编译好的jar包,需要有java环境
        │      SIGHAN15_Toy_Evaluation.txt  # 输出的结果
        │      SIGHAN15_Toy_Result.txt  # 你预测的结果
        │      SIGHAN15_Toy_Truth.txt  # Groud Truth,即真实值
        │
        └─Training  # 训练集,是sgml格式的,使用时需要处理
                SIGHAN15_CSC_A2_Training.sgml
                SIGHAN15_CSC_B2_Training.sgml
    

    3. 数据集预处理

    3.1 训练集预处理

    训练集使用的是sgml格式的数据,打开后为:

    
    <ESSAY title="不能參加朋友找到工作的慶祝會">  
    <TEXT>
    
    <PASSAGE id="A2-0003-1">但是我不能去參加,因為我有一點事情阿!PASSAGE>
    TEXT>
    
    <MISTAKE id="A2-0003-1" location="18">
    
    <WRONG>有一點事情阿WRONG>
    
    <CORRECTION>有一點事情啊CORRECTION>
    MISTAKE>
    ESSAY>
    
    <ESSAY title="不能參加朋友找到工作的慶祝會">
    <TEXT>
    <PASSAGE id="A2-0006-1">聽起來是一份很好的公司。又意思又很多錢。PASSAGE>
    TEXT>
    <MISTAKE id="A2-0006-1" location="13">
    <WRONG>又意思WRONG>
    <CORRECTION>有意思CORRECTION>
    MISTAKE>
    ESSAY>
    
    ...  
    

    这里我给出我的预处理方式:

    1. 不使用essay的title
    2. 如果一个句子包含多个错误,将其一起替换到正确句子中,而不是弄成多句。例如:我是练习时长两年半的蔡徐坤,训练集给出两种错误练习->联系蔡徐坤->菜虚鲲,我会直接将其替换到原句子变为我是联系时长两年半的菜虚鲲,而非分成两个句子我是联系时长两年半的蔡徐坤我是练习时长两年半的菜虚鲲

    代码如下:

    from bs4 import BeautifulSoup # BeautifulSoup版本为4.9.3
    
    def resolve_sighan_sgml(filename: str):
        with open(filename, mode='r', encoding='utf-8') as f:
            text = f.read()
    
        soup = BeautifulSoup(text)
    
        result_dict = {}
        for item in soup("essay"):
            passage_list = item("passage")
            # 一个essay中有多个句子
            for passage in passage_list:
                id = passage.get("id")
                result_dict[id] = {}
                result_dict[id]['src'] = passage.text
    
            mistake_list = item("mistake")
    
            if len(mistake_list) <= 0:
                print("存在部分数据无mistake标签")
    
            for mistake in mistake_list:
                id = mistake.get('id')
    
                wrong_list = mistake('wrong')
                correction_list = mistake('correction')
                if len(wrong_list) != len(correction_list) or len(wrong_list) > 1 or len(wrong_list) <= 0:
                    print("存在wrong标签数量不正确,请检查! id:", id)
                    continue
    
                result_dict[id]['tgt'] = result_dict[id]['src'].replace(wrong_list[0].text.strip(), correction_list[0].text.strip())
    
        # 转换一下格式,将result转换成list
        result_list = [{"id": key,
                        "src": result_dict[key]['src'],
                        "tgt": result_dict[key]['tgt'] if 'tgt' in result_dict[key] else result_dict[key]['src']}
                       for key in result_dict.keys()]
    
        # 简单验证一下
        for item in result_list:
            if len(item['src']) != len(item['tgt']):
                print("存在数据src与tgt长度不一致,请检查!id:", item['id'])
    
        return result_list
    
    resolve_sighan_sgml("sighan/SIGHAN15_CSC_A2_Training.sgml")
    

    输出为:

    [{'id': 'A2-0003-1',
      'src': '但是我不能去參加,因為我有一點事情阿!',
      'tgt': '但是我不能去參加,因為我有一點事情啊!'},
     {'id': 'A2-0006-1',
      'src': '聽起來是一份很好的公司。又意思又很多錢。',
      'tgt': '聽起來是一份很好的公司。有意思又很多錢。'},
      ....
    

    注意官方提供的文件中文件中有许多错误,包括编码问题、id对不上,标签有问题等,需要手动修复一下

    2013版的训练集sgml格式和2014/2015有点不一样,需要对应地方改一下

    由于原始数据是繁体字,还需要将其变成简体字,这里使用OpenCC工具进行转换:

    import opencc  # version=1.1.1
    
    converter = opencc.OpenCC('t2s.json')
    converter.convert('哎呦,你幹嘛')
    

    输出:

    '哎呦,你干嘛'
    

    3.2 测试集预处理

    测试集与训练集有所不同,其句子和label是分成文件。对于句子文件,数据结构如下:

    (pid=A2-0011-1)	你好!我是張愛文。
    (pid=A2-0023-1)	下個星期,我跟我朋唷打算去法國玩兒。
    (pid=A2-0023-2)	我聽說,你找到新工作,我很高興。
    ....
    

    而Label文件格式为:

    A2-0011-1, 0
    A2-0023-1, 10, 友
    A2-0023-2, 0
    ...
    

    我们最后验证时,需要按照上面的格式进行处理,然后使用数据集中的jar包进行验证。

    但为了方便大家使用python验证,这里也还处理成和训练集一样的格式,处理代码如下:

    def resolve_sighan_test(input_filename, truth_filename):
        with open(input_filename, mode='r', encoding='utf-8') as f:
            lines = f.readlines()
    
        result_dict = {}
        for line in lines:
            pid, text = line.split("\t")
            pid = pid.replace("(pid=", "").replace(")", "")
            result_dict[pid] = {}
            result_dict[pid]['src'] = text.strip()
    
        with open(truth_filename, mode='r', encoding='utf-8') as f:
            lines = f.readlines()
    
        for line in lines:
            items = line.split(',')
            pid = items[0]
            src = result_dict[pid]['src']
            if items[1].strip() == '0':
                result_dict[pid]['tgt'] = src
                continue
    
            i = 1
            while i < len(items):
                index = int(items[i]) - 1
                character = items[i+1].strip()
                src = src[:index] + character + src[index+1:]
                i += 2
    
            result_dict[pid]['tgt'] = src
    
        # 转换一下格式,将result转换成list
        result_list = [{"id": key,
                        "src": result_dict[key]['src'],
                        "tgt": result_dict[key]['tgt'] if 'tgt' in result_dict[key] else result_dict[key]['src']}
                       for key in result_dict.keys()]
    
        # 简单验证一下
        for item in result_list:
            if len(item['src']) != len(item['tgt']):
                print("存在数据src与tgt长度不一致,请检查!id:", item['id'])
    
        return result_list
    
    input_filename = 'sighan/SIGHAN15_CSC_TestInput.txt'
    truth_filename = 'sighan/SIGHAN15_CSC_TestTruth.txt'
    result = resolve_sighan_test(input_filename, truth_filename)
    print(result)
    

    输出为:

    [{'id': 'A2-0011-1', 'src': '你好!我是張愛文。', 'tgt': '你好!我是張愛文。'},
     {'id': 'A2-0023-1', 'src': '下個星期,我跟我朋唷打算去法國玩兒。', 'tgt': '下個星期,我跟我朋友打算去法國玩兒。'},
     {'id': 'A2-0023-2', 'src': '我聽說,你找到新工作,我很高興。', 'tgt': '我聽說,你找到新工作,我很高興。'},
     ...
    

    同样,对于sighan13要对上面的代码进行小小的修改

    4. 测试集验证工具

    官方提供了一个测试集验证工具,就在Tool目录下。你只需要安装java,然后运行如下命令即可:

    java -jar sighan15csc.jar -i SIGHAN15_Toy_Result.txt -t SIGHAN15_Toy_Truth.txt
    

    其中:

    • -i参数: 是你的预测结果,需要按照样例文件的格式进行处理
    • -t参数:是官方提供的真值txt,不要进行修改。例如,对于sighan15就是SIGHAN15_CSC_TestTruth.txt
    • -o参数(可选):将输出结果保存到文件。如果保存到文件,会有更详细的结果。

    执行之后,你会得到如下的结果:

    
    ==========================================================
    Part 1: Overall Performance
    ==========================================================
    
    False Positive Rate = 0.3333 (1/3)
    
    Detection Level
            Accuracy = 0.6 (6/10)
            Precision = 0.8 (4/5)
            Recall = 0.5714 (4/7)
            F1-Score = 0.6667 ((2*0.8*0.5714)/(0.8+0.5714))
    
    Correction Level
            Accuracy = 0.5 (5/10)
            Precision = 0.75 (3/4)
            Recall = 0.4286 (3/7)
            F1-Score = 0.5455 ((2*0.75*0.4286)/(0.75+0.4286))
    

    5. 预处理好的数据集

    官方提供的数据集有许多错误,包括部分字符存在编码问题,字数不对等,并且格式不利于用户使用,最重要的还是繁体字。这里我对其进行了处理,大家可以直接使用:

    数据集链接:百度网盘Google Drive

    处理好的文件目录结构如下:

    ├─Test   # 测试集
    │  │  sighan13_test_set_simplified.pkl  # sighan13测试集简体中文版
    │  │  sighan13_test_set_traditional.pkl # sighan13测试集繁体中文版
    │  │  sighan14_test_set_simplified.pkl
    │  │  sighan14_test_set_traditional.pkl
    │  │  sighan15_test_set_simplified.pkl
    │  │  sighan15_test_set_traditional.pkl
    │  │
    │  ├─sighan13  # 官方原数据集(修复错误后)
    │  │      FinalTest_SubTask2.txt
    │  │      FinalTest_SubTask2_Truth.txt
    │  │
    │  ├─sighan14
    │  │      CLP14_CSC_TestInput.txt
    │  │      CLP14_CSC_TestTruth.txt
    │  │
    │  └─sighan15
    │          SIGHAN15_CSC_TestInput.txt
    │          SIGHAN15_CSC_TestTruth.txt
    │
    └─Train
        │  sighan13_training_set_simplified.pkl
        │  sighan13_training_set_traditional.pkl
        │  sighan14_training_set_simplified.pkl
        │  sighan14_training_set_traditional.pkl
        │  sighan15_training_set_simplified.pkl
        │  sighan15_training_set_traditional.pkl
        │
        ├─sighan13
        │      Bakeoff2013_SampleSet_WithError_00001-00350.txt
        │      Bakeoff2013_SampleSet_WithoutError_10001-10350.txt
        │
        ├─sighan14
        │      B1_training.sgml
        │      C1_training.sgml
        │
        └─sighan15
                SIGHAN15_CSC_A2_Training.sgml
                SIGHAN15_CSC_B2_Training.sgml
    

    使用方式:

    import pickle
    
    with open("sighan/Train/sighan15_training_set_simplified.pkl", mode='rb') as f:
        data_list = pickle.load(f)
    print(data_list)
    

    输出:

    [{'id': 'A2-0003-1',
      'src': '但是我不能去参加,因为我有一点事情阿!',
      'tgt': '但是我不能去参加,因为我有一点事情啊!'},
     {'id': 'A2-0006-1',
      'src': '听起来是一份很好的公司。又意思又很多钱。',
      'tgt': '听起来是一份很好的公司。有意思又很多钱。'},
      ...
    

    6. Wang271K数据集

    大部分CSC论文使用的训练集都是Wang 2019这篇论文使用的数据集,一般简称为Wang271K,其包含271K个训练集。这里也将我处理好的分享出来,方便大家使用:

    百度云盘Google Drive

    使用方式:

    import pickle
    
    with open('Wang271K_processed.pkl', mode='rb') as f:
        wang271k = pickle.load(f)
    
    print(wang271k[:10])
    
    [{'src': '联合国紧急事务首席协调官艾蒽兰表示,这是全球有史以来首次子灾难发生候这么短一段时间内,就筹集到这么高的金额。',
      'tgt': '联合国紧急事务首席协调官艾基兰表示,这是全球有史以来首次在灾难发生后这么短一段时间内,就筹集到这么高的金额。'},
     {'src': '日本大藏省一名官员坚称,日本仍忠于全球自由贸易贞经神。', 'tgt': '日本大藏省一名官员坚称,日本仍忠于全球自由贸易的精神。'},
     {'src': '小泉承诺将革除始曰苯陷于十年经济衰退的弊病。', 'tgt': '小泉承诺将革除使日本陷于十年经济衰退的弊病。'},
     {'src': '澳洲首家母乳银行痔于明年开张莒业,一因应早产儿和高龄母亲越来越殷切的母乳需求。',
    ...
    





    参考资料

    SIGHAN Bake-off 2013: http://ir.itc.ntnu.edu.tw/lre/sighan7csc.html
    SIGHAN Bake-off 2014: http://ir.itc.ntnu.edu.tw/lre/clp14csc.html
    SIGHAN Bake-off 2015: http://ir.itc.ntnu.edu.tw/lre/sighan8csc.html

  • 相关阅读:
    c++标准库的错误代码
    TI单芯片毫米波雷达代码走读(二十七)—— 角度维(3D)处理之通道间幅相一致性补偿
    uniapp实现我的订单页面无感 - 删除数据
    torch-geometric(PYG) 环境配置
    三栏侧边栏的实现
    旋转框目标检测mmrotate v0.3.1 训练DOTA数据集(二)
    IT行业的革新力量:技术进步与未来展望
    递归算法JAVA实现
    python 娣卞害绁炵粡缃戠粶,python 缃戠粶鍒嗘瀽
    2022年QT初体验以及未来趋势发展以及前景概要
  • 原文地址:https://blog.csdn.net/zhaohongfei_358/article/details/127093838