摘要
合集:AI案例-NLP-医疗
赛题:科大讯飞2022非标准化疾病诉求的简单分诊挑战赛2.0
AI问题:文本分类
数据集:好大夫在线的真实问诊数据,包括22,800条训练数据和7,600条测试数据。
数据集发布方:好大夫
数据集价值:优化医疗资源配置,找到合适的方向,进行分级诊疗。
解决方案:chinese-roberta-wwm-ext模型
一、赛题描述
背景
人民对于医疗健康的需求在不断增长,但社会现阶段医疗资源紧缺,往往排队一上午看病十分钟,时间和精神成本巨大。如何更好地优化医疗资源配置,找到合适的方向,进行分级诊疗,是当前社会的重要课题。大众自觉身体状态异常,有时不能准确判断自己是否患有疾病,需要寻求有专业知识的人进行判断,但是主诉者一般进行口语化表述,不容易进行精准高效的指引。
任务
进行简单分诊需要一定的数据和经验知识进行支撑。本次比赛提供了部分好大夫在线的真实问诊数据,经过严格脱敏,提供给参赛者进行单分类任务。具体为:通过处理文字诉求,给出20个常见的就诊方向之一和61个疾病方向之一。
二、数据集描述
数据说明
比赛共提供约22,800条训练数据,约7,600条测试数据。数据字段信息包括:
- 年龄段:age
- 主要诉求:diseaseName
- 标题:title
- 希望获得的帮助:hopeHelp
- 其他描述字段文本conditionDesc
- 就诊方向标签:label_i 取值范围 [0,19]
- 疾病方向标签:label_j 取值范围 [0,60] (训练数据中疾病方向标签存在缺失,以-1标记,测试数据中没有)。
就诊方向
label_i | 就诊方向 |
---|---|
0 | 乳腺外科 |
1 | 产前检查 |
2 | 内科 |
3 | 呼吸内科 |
4 | 咽喉疾病 |
5 | 妇产科 |
6 | 小儿保健 |
7 | 小儿呼吸系统疾病 |
8 | 小儿消化疾病 |
9 | 小儿耳鼻喉 |
10 | 心内科 |
11 | 消化内科 |
12 | 甲状腺疾病 |
13 | 皮肤科 |
14 | 直肠肛管疾病 |
15 | 眼科 |
16 | 神经内科 |
17 | 脊柱退行性变 |
18 | 运动医学 |
19 | 骨科 |
疾病方向
label_j | 疾病方向 | label_j | 疾病方向 | label_j | 疾病方向 |
---|---|---|---|---|---|
0 | 乳房囊肿 | 21 | 小儿支气管肺炎 | 42 | 皮肤瘙痒 |
1 | 乳腺增生 | 22 | 小儿消化不良 | 43 | 皮肤科其他 |
2 | 乳腺疾病 | 23 | 小儿消化疾病 | 44 | 直肠肛管疾病 |
3 | 乳腺肿瘤 | 24 | 小儿耳鼻喉其他 | 45 | 眼部疾病 |
4 | 产前检查 | 25 | 小儿肺炎 | 46 | 神经内科其他 |
5 | 儿童保健 | 26 | 心内科其他 | 47 | 微量元素缺乏 |
6 | 先兆流产 | 27 | 心脏病 | 48 | 羊水异常 |
7 | 内科其他 | 28 | 扁桃体炎 | 49 | 肺部疾病 |
8 | 剖腹产 | 29 | 早孕反应 | 50 | 胃病 |
9 | 发育迟缓 | 30 | 月经失调 | 51 | 脊柱退行性变 |
10 | 呼吸内科其他 | 31 | 桥本甲状腺炎 | 52 | 腰椎间盘突出 |
11 | 咽喉疾病 | 32 | 消化不良 | 53 | 腹泻 |
12 | 喉疾病 | 33 | 消化内科其他 | 54 | 腹痛 |
13 | 围产保健 | 34 | 消化道出血 | 55 | 膝关节半月板损伤 |
14 | 外阴疾病 | 35 | 甲减 | 56 | 膝关节损伤 |
15 | 妇科病 | 36 | 甲状腺功能异常 | 57 | 膝关节韧带损伤 |
16 | 宫腔镜 | 37 | 甲状腺疾病 | 58 | 运动医学 |
17 | 小儿呼吸系统疾病 | 38 | 甲状腺瘤 | 59 | 韧带损伤 |
18 | 小儿咳嗽 | 39 | 甲状腺结节 | 60 | 骨科其他 |
19 | 小儿感冒 | 40 | 痔疮 | ||
20 | 小儿支气管炎 | 41 | 皮肤病 |
训练数据data_train.xlsx
id | age | diseaseName | conditionDesc | title | hopeHelp | label_i | label_j |
---|---|---|---|---|---|---|---|
1 | 30+ | 小红点是什么? | 四肢上部张图片中这样的小红疙瘩是怎么回事呢?特别痒。 | 小红点是什么? | 请医生给我一些治疗上的建议 | 13 | 42 |
2 | 30+ | 乳腺结节 | 体检发现左侧乳腺有结节,13mm×8mm,自己没有任何症状 | 左侧乳腺结节 | 请医生给我一些治疗上的建议,目前病情是否需要手术? | 0 | 1 |
3 | 20+ | 身体麻 身体坐左半面肢体有麻木感 | 年初患有带状疱疹 在左腿脚踝上方 之后疱疹好了 但是左脚开始麻 随后左手麻 然后左腿和左胳膊陆续开始麻 直到左边脸也略有麻木感 同时右脚也麻 | 左侧身体麻木 | 什么原因导致的麻木以及如何治疗 | 16 | 47 |
4 | 10+ | 生长缓慢,想再增长10厘米 | 今年8月满15岁,身高165厘米,近半年生长缓慢,能否打生长激素再增高10厘米。 | 想增高10厘米 | 是否可打生长激素 | 6 | 9 |
5 | 30+ | 眼睛看东西突然变小,变远 | 从小记事时就有此病,发病时看任何东西都变小,距离也判断不太好了,没有就过医。 | 眼睛看东西突然变小,从小就有 | 希望医生诊断这是什么病?需要就医吗?有什么注意事项?谢谢。 | 15 | 46 |
6 | 20+ | 甲状腺 | 嗓子疼,说话感觉里面有回音,先是由感冒引起,后来大量运动后天气变化着凉,疼痛加剧 | 甲状腺肿大 | 如何控制病情,是否还需做下一步检查 | 12 | 36 |
7 | 0+ | 晚上磨牙,缺钙 | 女,5岁4个月。骨密度测试部缺钙,验血又显示缺钙,不知道到底怎么回事 | 孩子是否缺钙? | 希望医生解答一下孩子是否缺钙 | 6 | 48 |
8 | 50+ | 手指麻木 | 一月前出现十个手指指尖麻木,现症状加重。 | 手指麻木 | 会是什么病?需要做什么检查? | 16 | 47 |
9 | 20+ | 便血,鲜红色的 | 便血,鲜红色的,大便时还有点疼,就持续两天 | 要不要做检查 | 要不要做检查 | 11 | 34 |
测试数据data_test.xlsx
id | age | diseaseName | conditionDesc | title | hopeHelp |
---|---|---|---|---|---|
0 | 30+ | 胳膊内测浅白色印记 | 男,30岁。胳膊内测有几处浅白色印记,绿豆大小,不痛不痒。不仔细看看不出来,不是很明显。印记处皮肤外表光滑。无皮屑。 | 是不是白癜风 | 希望医生给看一下是不是白癜风 |
1 | 50+ | 心慌气短心里难受眉骨疼。口渴,不停打哈欠 | 口干,身上没劲,心慌气短,眉骨疼,不想挣眼,想睡觉,平躺感觉舒服,饥饿后出现的上述症状,发病一周,吃护心丸 | 那方面的病情?明天去医院具体挂什么科室? | 那方面的病情?明天去医院具体挂什么科室? |
2 | 30+ | 头痛失眠、手脚发麻 | 大夫您好、感觉心慌失眠、手脚发麻请问是什么原因? | 给点意见、如何缓解症状 | 给点意见、如何缓解症状 |
3 | 30+ | 乳房内有一个硬块 | 硬块已经发现有一个多月了,不疼,请问一下,这是什么样的症状啊! | 硬块要如何解决? | 你这一般会是什么情况想得到咨询。 |
4 | 0+ | 五个月宝宝体重增长缓慢 | 宝宝现在五个月,纯母乳,从四个月开始不好好吃奶,三个月到四个月长了一斤,四个月到五个月长了不到一斤,宝宝现在这情况是在经历厌奶期吗,需不需要采取什么措施,五个月可以加米粉了吗?五个月奶量一次120左右,少不少? | 五个月宝宝生长缓慢 | 宝宝厌奶期生长缓慢需要采取什么措施 |
另提供14,000条相关知识文本,每条包含主体/(属性)/客体,供选手随意选用。
数据集版权许可协议
BY-NC-SA 4.0
https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh-hans
三、解决方案样例
工作原理介绍
解决方案采用TF-IDF(Term Frequency-Inverse Document Frequency)传统机器学习的建模方式和Chinese-ROBERTa-wwm-ext 大语言模型为基础的建模方式,并进行比较。TF-IDF是一种广泛应用于自然语言处理(NLP)和信息检索的技术,用于评估一个词语在文档集合或语料库中的重要性。TF-IDF建模方案存在的主要问题是无法支持文本中的语法和语义的学习问题,而大语言模型则能较好解决该问题。
TF-IDF(Term Frequency-Inverse Document Frequency)
一种广泛应用于自然语言处理(NLP)和信息检索的技术,用于评估一个词语在文档集合或语料库中的重要性。
TF(Term Frequency,词频)
- 定义:某个词在文档中出现的次数。
- 公式:TF(t,d)=文档 d 中的总词数词 t 在文档 d 中出现的次数
- 作用:衡量词语在单篇文档中的常见程度。例如,在文档“苹果香蕉苹果”中,“苹果”的TF值为 32。
IDF(Inverse Document Frequency,逆文档频率)
- 定义:衡量词语在文档集合中的稀有程度。罕见词具有更高的IDF值。
- 公式:IDF(t)=log(包含词 t 的文档数总文档数)
- 作用:降低常见词的权重,突出重要词汇。例如,若“的”出现在所有文档中,则其IDF值趋近于0。
Chinese-ROBERTa-wwm-ext
一个针对中文的预训练语言模型,基于 RoBERTa 架构,并针对中文特性进行了多项优化。其中,wwm 表示 Whole Word Masked Modeling(全词掩码建模),而 ext 通常指扩展版本(可能包含更长的上下文窗口、更大的模型规模或额外的训练策略)。
Chinese-ROBERTa 的改进
- 分词适配:使用 WordPiece 或 BPE 分词,并针对中文设计词典。
- 全词掩码(WWMM):将整个词作为掩码单位,而非单个字符,保留语义完整性。
运行环境
外部库名称 | 版本号 |
---|---|
python | 3.12.3 |
sklearn-compat | 0.1.3 |
torch | 2.5.1 |
transformers | 4.49.0 |
seaborn | 0.13.2 |
源码结构
1. 数据读取
train_df = pd.read_excel('./data/data_train.xlsx')
test_df = pd.read_excel('./data/data_test.xlsx')
test_submit = pd.read_csv('./data/提交示例.csv')
2. 数据分析
train_df['label_i'].value_counts().plot(kind='barh')
train_df['label_j'].value_counts().plot(kind='barh')
3. TF-IDF 模型
tfidf = TfidfVectorizer().fit(train_text)
train_tfidf = tfidf.fit_transform(train_text)
test_tfidf = tfidf.transform(test_text)
clf_i = LogisticRegression()
clf_i.fit(train_tfidf, train_df['label_i'])
clf_j = LogisticRegression()
clf_j.fit(train_tfidf, train_df['label_j'])
4. 基于chinese-roberta-wwm-ext模型进行训练
以下是这段 PyTorch 训练代码的解析:
- 训练模式初始化
model.train()
:将模型切换到训练模式(启用 Dropout/BatchNorm 等训练专用层)。iter_num
:记录当前迭代次数。total_iter
:总批次数(train_loader
的长度)。
- 数据批次遍历
train_loader
:数据加载器,按批次(batch)提供数据。- 条件打印:每 10 个批次打印一次进度(但跳过每 100 的倍数,避免冗余)。
- 梯度清零与数据准备
- 正向传播
- 损失计算
- 反向传播与梯度裁剪
- 参数更新
- 定期日志输出 每 100 次迭代打印:
- 当前损失值:
loss.item()
。 - 训练进度:已完成迭代的百分比。
- 双任务准确率:
pred_i
对label_i
的准确率。pred_j
对label_j
的准确率(仅计算有效样本)。
def train():
model.train()
iter_num = 0
total_iter = len(train_loader)
for batch_idx, batch_data in enumerate(train_loader):
if (batch_idx % 10 == 0 and batch_idx % 100 != 0):
print("Training batch number: %d, total: %d" % (batch_idx, total_iter))
# 正向传播
optim.zero_grad()
input_ids = batch_data['input_ids'].to(device)
attention_mask = batch_data['attention_mask'].to(device)
label_i = batch_data['label_i'].to(device)
label_j = batch_data['label_j'].to(device)
pred_i, pred_j = model(
input_ids,
attention_mask
)
valid = label_j != -1
loss = loss_fn(pred_i, label_i) + loss_fn(pred_j[valid], label_j[valid])
# 反向梯度信息
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
# 参数更新
optim.step()
iter_num += 1
if (iter_num % 100 == 0):
print("Iterating Number: %d, Loss: %.4f, Progress: %.2f%%, Accuracy: %.4f / %.4f" % (
iter_num, loss.item(), iter_num/total_iter*100,
(pred_i.argmax(1) == label_i).float().data.cpu().numpy().mean(),
(pred_j[valid].argmax(1) == label_j[valid]).float().data.cpu().numpy().mean()
))
运行结果
1、模型1-TF-DIF
输出数据样例:tfidf_submit.csv。其他label_i为就诊方向,label_j为疾病方向。
id | label_i | label_j |
---|---|---|
0 | 13 | -1 |
1 | 10 | -1 |
2 | 16 | 46 |
3 | 0 | -1 |
4 | 6 | 9 |
5 | 3 | -1 |
6 | 2 | -1 |
7 | 12 | 39 |
8 | 7 | 25 |
2、模型1-Bert
训练和预测过程:
Epoch number: 0
Training batch number: 10, total: 1367
Training batch number: 20, total: 1367
...
Prediction batch number: 0, total: 475
Prediction batch number: 10, total: 475
Prediction batch number: 20, total: 475
Prediction batch number: 30, total: 475
...
输出数据样例:bert_submit.csv
id | label_i | label_j |
---|---|---|
0 | 13 | 41 |
1 | 10 | 26 |
2 | 16 | 46 |
3 | 0 | 2 |
4 | 6 | 9 |
5 | 3 | 10 |
6 | 13 | 41 |
7 | 12 | 39 |
8 | 7 | 25 |
9 | 14 | 44 |
源码开源协议
GPL-v3