实战美年健康 AI 大赛之一 _ 自然语言处理

1. 说明

  一直想找个自然语言处理(NLP)相关的比赛.起始看到"美年健康 AI 大赛"的时候,觉得和之前糖尿病比赛很相似,还是 GBDT 调参大赛.解包一看几百兆数据,觉得自己机器可能跑不动(后来确实加了一条内存),都没打开看数据就放弃了.

  后来两个朋友都推荐做这个比赛,说是 NLP 的,打开数据一看,欸~还挺有意思的.数据量大的好处是稳定,我线上线下基本是同增同减(只提交过三次,目前为止是同增同减),就是看那病情诊断看得心惊肉跳的,腿都软了.

2. 比赛介绍

  言归正传,介绍一下比赛内容,比赛提供了涉及 5 万多人的 800 多万条各项体验数据,有数据型的,也有字符型的.体验项目名称经过了脱敏处理,检查结果的文字内容未脱敏,目标是预测:收缩压、舒张压、甘油三酯、高密度脂蛋白胆固醇和低密度脂蛋白胆固醇这五项指标,预测具体的值,是一个回归问题.简单说就是分析哪些指标与高血压/高血脂相关.

  我使用的是 lightgbm 模型,简单调参,对字符串只做了一些简单的处理,过滤出一些我认为重要的文字特征,当前最好成绩是 0.03002(今天中午).NLP 建构正在进行中.

  估计最后大多数人还是使用 GBDT 类算法,对于模型调参和基本的特征工程就不再重复,详见之前的"糖尿病比赛".

  本文主要说说自然语言处理,此处的目的是把文字转换成数值,枚举,或者布尔类型,以方便代入模型.数据里面包含了很多文本,粗算也有上百万条,其中涉及至少几百种类型的检查,眼科,牙科,心脏,B超等等,不可能为每种检查写一套正则表达式,下面来看看如何使用 NLP 的方法简化工作.

3. 专业领域的自然语言处理

  一开始做的时候首先想到用一些现成的工具,比如 snowNLP 或者 jieba 把文字分成短句,词组,取其中的关键词等等.然后发现,医疗报告相对于普通文章有很大不同.普通文章可能有各种句式,各种结构,篇幅可能很长,其中可能有些和主题无关的信息等等.体验结果中的文字,结构相对比较简单.

  先来看看提供的 txt 数据,它包括:用户 id,体项项目名称,体验结果.体验结果可以分成四种情况:

  第一种:纯数值型,无需处理.

  第二种:枚举型及其变种,如:"阴性","未见异常"等等,简单处理即可转成数值.

  第三种:简单混合型,如:">100 次/分,窦性心动过速",此类型以数值为主.

  第四种:复杂混合型,如:"甲状腺内见多个低回声结节,最大位于右叶约 14mm×8mm,结节周边有血管环绕".这种情况可能是纯文字,可能是文字和数值混合,相对比较复杂,也很有趣,它包含了第二和第三两种情况.

4. 预处理

  在处理文本之前,先要做些预测处理,比如:归一大小写,各种符号的全角半角,处理输入错误,多余的空格等等.

5. 枚举型及其变种

  常见的一些枚举有"正常","未见明显异常","阴性","阳性",以及加减号等等,相对来说比较容易判断.需要注意的是同一内容可能有几种不同的表达,此时需要判断它的关键词,尤其是注意其中的包含否定词.只要 unique() 少,就适合将其视为枚举处理.

6. 简单混合型

  文本中会有长句包含短句,括号内外等等情况,这里只考虑:以数值为核心的短句.这经常出现在一个字段中其它都是纯数字,而某几个值被写成"<30 次".如果一个短句含有数字,可以把它分解成三部分:前缀 + 数字 + 后缀.其中数字又包括:数值,符号,单位.我处理的方法是将其拆分后保存在结构中,借助 Python 灵活的结构,这一操作并不复杂.

  同时还要需要考虑包含多个数值的情况,比如:< 30(正常范围 30-50).分优先级处理,比如括号内的优先级更低,带大于小于和范围比具体数值优先级更低等等.如果不借助结构,直接用正则判断会非常复杂.

  数字部分除了 0-9 和小数点正负号外,还可能包含大于,范围,描述面积体积的乘号等等,也是有限的几种情况,可以分别用正则实现.

  后缀以单位为主:长度,体积,频率等等,可能性有限,可一一列举.

  前缀和其它后缀可能是一些描述性信息,其中也可提取出一些信息,比如:"左眼/右眼",可能涉及一个体验结果用多个字段描述,放在复杂混合型中讨论.

7. 复杂混合型

  复杂混合型是最难处理的一种情况,里面包含大量的医生诊断信息,很重要.这类特征大概有 100 种左右.在此也能尽量多地使用自然语言处理的方法.

  第一个技术是递归分组,文本中会有长句包含短句,括号内外等等情况,首先要分组,大组(段)包括中组,中组(句)包含小组(词),以及再小的组,有些数据分成足够小的组,就可以用枚举和简单型来处理了.

  第二个技术是词性,有一些现成的工具可以分词,给出词性,而名词一般是核心词,可以把一个短句看成三部分:1 什么东西,2 怎么了,3 具体数值.

  第三个技术是 TF/IDF,这与词频相关.举个例子:肝脏B超报告,人看一遍就能从报告中总结出以下特征:形状,血管,无回声区及其大小,大概五六种重要指标.这些描述指标会在文本中多次出现,这就需要查找出现次数多的词,另外还需要去掉一些每个特征都可能包括的关键字,比如"正常/大小/高/低".此时就可以对一个体验项目取出一组关键词,然后把这些关键词相关的属性(第二/三个技术)分别归入不同特征.

  另外还可以边提取边筛选,比如说:我们得到了新的 bool 型特征:肝上是否有囊肿,可以计算它的不同取值 (有/无) 时,目标值的统计数据是否发生变化,假设:高压均值为 120,如果在有囊肿的情况下高压均值为 125,则说明这个新特征有意义.

8. 其它

  首先,需要用经验手动做一些映射表,比如同一字段中出现的"S"与"敏感",未见异常的N种说法.

  另外,还有一些"后门",早晚有人说,现在说出来,总比最后一天才说强:文字信息会带一些"血压","血脂"相关的关键字,就是前面说的"关键文字特征".有的特征里直接就写"血压高".如果不想做复杂的 NLP,可以写正则只分析这些特征.相关的还有"血糖","肥胖"之类的关键字,举一反三吧.(感觉这么说有点搅局)

9. 总结

  综上,特征工程阶段使用了数值处理,自然语言处理,正则表达式.在结构上涉及层层包含的关系,自动生成判断逻辑(进行中…).我理解 NLP 并不只是分词,主谓宾定状补的解析,词间的相似度,它在各个层次上的抽象也很重要.尽量自动化处理.虽然目前不能避免人工干预,但是程序也确实在很大程度上减少了工作量.

  我觉得来回试榜效果不好.心里很浮躁,反正现在时间还早,不如在深度和结构上多花点时间.如果做下去再有一些新的思路,后续再加文档吧.