Difflib扩展工具解决病句标注伪数据标记问题

项目代码在我的GitHub

1 问题引入

1.1 病句标注问题

病句纠错是自然语言分析领域中的一个常见问题。神经网络的纠错模型往往需要较大的数据量。但由于语病是一个小概率事件,真实生活中的病句数据量往往难以满足模型训练的需要,所以制造伪数据成为必要。使用模型自动产生的伪数据中不含有具体错误的位置和类型的标签,无法直接输入模型。所以我们需要一种方法,在给出病句和正确句子的前提下,在病句上标注出错误的类型和位置,或者说,使得依据标注能够正确地将病句改正。

修改操作有以下四种:

  • 插入:在病句中插入一个单词,操作为insert,标签为M
  • 删除:删除病句中的某个单词,操作为delete,标签为R
  • 替换:将病句中某个单词替换成另一个单词,操作为replace,标签为S
  • 换序:将病句中某两个相邻短语交换顺序,操作为disorder,标签为W

其中,由于标签是打在字上的,所以插入标签会打在插入缝隙的下一个字上(这也是病句标注有待解决的难题),在句尾加入一个特殊字作为padding来避免插入时索引溢出。

1.2 有关difflib

difflib作为python的标准库模块,无需安装,作用是比对文本之间的差异,且支持输出可读性比较强的HTML文档,与Linux下的diff命令相似。可以使用该模块比对代码和配置文件的差异,在版本控制方面非常有用。Python2.3以后的版本默认自带difflib模块,无需额外安装。

利用diff.SequenceMatcher(_, source_list, target_list).get_opcodes()可以得到序列化的字符串输入source修改为target需要的操作以及操作的位置下标范围。但是,这个工具生成的操作的可选空间为:equal, insert, delete, replace。我们不需要equal,而需要额外的disorder。考虑这个问题以及以下诸多问题,我们编写了这个DiffExtend类的脚本,作为difflib在病句标注上的扩展。

主要方法是在difflib的修改操作序列的基础上,依据jieba的分词和词性特征对操作进行修正。分情况讨论时只预见了下一个操作,从这个角度讲,该工具可以看做DiffExtend(k),当前k=1

主要考虑的问题:

1 考虑插入操作是否存在以下情况,与前后组成单词:
eg1 生效果 >> 产生效果; 原始:插入产; 修正:生替换为产生
eg2 癌症导致死 >> 癌症导致死亡; 原始:插入亡; 修正:死替换为死亡
排除以下情况:
eg1 一微笑 >> 一个微笑; 正确:插入个; 修正:一替换为一个
eg2 个微笑 >> 一个微笑: 正确:插入一; 修正:个替换为一个

2 如果当前操作为替换,且替换的不是整个单词,且替换位置的单词不为数量词,则替换整个词
eg 生产 >> 生活; 原始:产替换为活; 修正:生产替换为生活
判断词性是为了避免以下情况:
eg 一个 >> 一种; 正确:个替换为种; 修正:一个替换为一种

3 如果替换的目标短语不是一个单词,则添加一步插入
eg 生活 >> 生产劳动; 原始:生活替换为生产劳动; 修正:生活替换为生产,插入劳动

4 diff工具原理为子序列的最大匹配,若句中有多个匹配会导致混乱
使用逗号分割得到短句后再将短句的match进行归并,默认短句不存在多个匹配

5 归并短句的操作以得到整句的操作,注意更新操作起止下标

6 去除equal操作

7 如果是一个插入接着一个删除
如果插入与删除在同一单词内,认定为替换

8 如果是一个插入接着一个删除
如果插入与删除隔了若干单词,且插入与删除的内容相同,认定为换序

9 如果是一个删除接着一个插入
如果删除和插入是相邻单词,认定为替换

10 如果是一个删除接着一个插入
如果删除和插入隔了若干单词,且插入与删除的内容相同,认定为换序

11 如果是一个插入接着一个替换
如果插入和替换在同一单词且插入的词与被替换的词相同,认定为替换后插入
eg 产生在工作 >> 生产队在工作
eg 原始:在产前插入生,将生替换为产队
eg 修正:产生换序,插入队

12 如果是一个插入接着一个替换
如果插入和替换的单词相邻且插入的词与被替换的词相同,认定为换序后插入
eg 工具好的解决问题 >> 好的工具能解决问题
eg 原始:在好前插入工具,将好的替换为工具能
eg 修正:工具好的换序,插入能

13 如果是一个替换接着一个删除
如果替换和删除在同一单词且替换的目标词与被删除的词相同,认定为删除后替换
eg 好产生队在工作 >> 生产队在工作
eg 原始:将好替换为生,删除生
eg 修正:删除好,将产生替换为生产

14 如果是一个替换接着一个删除
如果替换和删除的单词相邻且替换的目标词与被删除的词相同,认定为删除后换序
eg 还工具好的能解决问题 >> 好的工具能解决问题
eg 原始:将还替换为好的,删除好的
eg 修正:删除还,将工具与好的换序

2 运行方式

2.1 环境要求

依赖版本
Python3.4
difflibauto
reauto
jieba0.39

2.2 具体步骤

代码中使用2016和2017年的CGED_TrainingSet作为数据集,分别在文件2016_CGED_TrainingSet.txttrain.release.xml中,格式为xml格式,使用前对数据进行过简单清洗和修复。

# 运行测试的方法
python test.py  # 使用文件输入做测试,可以修改文件中的xml_file_name指定数据集
python evaluate.py  # 使用数据集给出的正确标签评估DiffExtend工具的准确率
python compare_tool.py  # 可选项,输出DiffExtend工具与真实标签不同的句对

# 使用的方法
from DiffExtend import DiffExtend
source = "ABC"
target = "XYZ"
operations = DiffExtend.label(source, target)
# 每一个operation是一个三元组,(操作,操作在source上的起始下标,操作在source上的结束下标)

3 成果与不足

2016年CGED_TrainingSet的Difflib结果

总句子数:9593 判错完全正确的句子数:4711 0.4910872511206088
类型S判断正确5044 类型S验证10400 0.4850000000000000
类型R判断正确4444 类型R验证5271 0.8431037753746917
类型M判断正确5544 类型M验证6195 0.8949152542372881
类型W判断正确0 类型W验证1620 0.0000000000000000

2016年CGED_TrainingSetDiffExtend结果

总句子数:9593 判错完全正确的句子数:6194 0.645679141040342
类型S判断正确7371 类型S验证10400 0.70875
类型R判断正确4609 类型R验证5271 0.8744071333712768
类型M判断正确5089 类型M验证6195 0.8214689265536723
类型W判断正确1031 类型W验证1620 0.6364197530864197

2017年CGED_TrainingSetDiffExtend结果

总句子数:10449 判错完全正确的句子数:6791 0.6499186525026318
类型S判断正确8367 类型S验证11584 0.722289364640884
类型R判断正确5165 类型R验证5848 0.8832079343365253
类型M判断正确5843 类型M验证7008 0.8337614155251142
类型W判断正确1538 类型W验证1993 0.7717009533366783

从结果上看,相对于单纯的difflib结果,DiffExtend的准确率有了很大提升,并且能够标注出换序错误,有一定的实用价值。但这其中也存在着一些问题:

  • 在修正删除操作成为替换操作时,提升了替换的准确率,但牺牲了一部分删除的准确率
  • 在考虑多词换序(注意上文写的是短语不是单词)时,如果考虑序列过短,会漏掉一些错误,考虑序列过长也会产生负面影响
  • 只预见了下一个操作,只能处理较为简单的情况
  • 给出的数据集中存在一定的差错,如标记错误,标点错误等
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值