用 Python 挖掘事故报告中的死亡人数

今天用 Python 写一个函数,用来识别土木行业事故报告中的死亡人数。我的设计思路如下:

  1. 经过观察,80% 的事故报告中有关死亡人数的记录是有规律的,即“XX人死亡”,其中XX可能是汉语数字也可能是阿拉伯数字。
  2. 于是我设计出一个正则表达式,`pattern_death = r’([\d\w]+)(人死亡|名工人死亡)’ 用以识别出这种模式。
  3. 对安徽省的几分调查报告的测试中,我发现这种识别模式会将“XX人死亡”之前的文字也提取出来,比如“该工程有5人死亡”,直到遇到标点符号,因为 ([\d\w]+) 的含义是提取任意数量的汉字或数字。
  4. 于是我有设计出第二个正则表达式,pattern_death_num = r'(\d+|[零一二两三四五六七八九十百千万]+)(人死亡|名工人死亡)' ,用以识别出上一种模式识别出的句子中的数字(无论是中文还是阿拉伯的)。
  5. 之后我又下载一个第三方库 cn2an ,将中文数字转换为数学数字。
  6. 将识别到的数字存放到字典中,没有识别到数字但文本中识别出“死亡”的做标记“待确认”。

虽然我在这里描述的似乎很轻松,但是你无法知道的是,我从最开始的起点走到这个目的地用了多久,以及为了识别条件、避免报错、存放识别出的数据等而为函数设计的逻辑化了多久时间。

在报了许多次错误、迭代了多次之后,这个程序基本上能运行起来了,这个思路已经可以从 393 个事故报告中提取 393-56 份 死亡人数了。

你可能会好奇,图上显示的分明是 57 份文件“待确认”,那么已提取到数据的数量不应该是 383-57 吗?

没错,这缺少的一份就是今天我要谈论的主角。

一字之差的工作量

这一份数据一直在报错,我不得不在每个省份的文件之间依次测试,找出有问题的文件。

我发现出错的原因是:程序的确识别出了“X人死亡”,并且将“X”提取了出来,但报错的那份文件用的不是“二人死亡”,而是是“两人死亡”。cn2an 这个专门将表示数字的中文转化为阿拉伯数字的库,它只能识别“二”,无法识别“两”

于是我又要设计出一个新的逻辑语句,如果识别出了“两”,就将它改为“二”,然后再用 cn2an 将其转化为阿拉伯数字。

我找到这个导致错误的原因并写出解决问题的语句,花了近半个小时。仅仅是一个字的偏差,为了使程序能够适应这种情况,却需要大量的测试。

我并非一个计算机专业的学生,我比较好奇的是,也许“大量时间花费在解决报错上”就是软件开发的常态?

言归正传,这是我们提取数据中很简单的一步,为了适配所有可能性,它的工作量并不小。

如果是从文本中提取“事故性质”这样的数据,也许描述“事故性质”的方式有多种多样(暂时我们不确定),不过它一定比数字要复杂,并且上下文可能没有特殊的格式,如果真是这样,单凭正则表达式可能已经无法完成目的了。

如果正则表达式无法解决这个问题,根据我目前掌握的信息来看,我们就需要复杂的 NLP 技术去识别出命名实体的词语、语义逻辑关系等,让机器理解句子,再将事故原因做分类。而这套规则,需要预设已知的数据库使代码能够理解。

如果我们真的使用 NLP 技术去提取所有事故报告中的“事故原因”,那么为了做出一个适配所有情况的程序,其工作量一定非常大。

为什么这么费劲

我们之所以在提取数据时这么费劲,是什么原因呢?

答案显而易见,事故报告中大部分信息的记录方式都没有统一的格式,如果格式能够统一,如果每个事故报告中都有一个统一的清单,那么每一种数据只需要一个正则表达式就能够提取出来了,并且对所有文件适配。

只可惜,在事故报告的格式上,没有像秦始皇统一六国的伟大节点。

现在 ChatGPT-4 应该可以自动提取出你所需的数据,只是需要充钱。而我们老师想让我们做一个自动识别的程序,只能说有点难,哈哈。

秦始皇统一六国

秦始皇建立了中国历史上第一个统一的中央集权的封建国家,他不仅仅同意了中国,更重要的是他使书同文、车同轨、行同轮,统一文字、货币。

这些统一,不仅有利于信息的传递、规格的统一,也有助于我们中华文化的传承和发扬。

今天在写代码中遇到了这个“两”字引起的报错,以及对提取“事故性质”的工作量的思考,是否可以说明——统一的标准能在无形中解决许多问题呢?

我认为答案是肯定的。