基于Python和LangChain的医疗文本分类

云信安装大师
90
AI 质量分
4 5 月, 2025
3 分钟阅读
0 阅读

基于Python和LangChain的医疗文本分类实战指南

引言

在医疗领域,文本数据(如病历、医学文献、患者咨询等)的处理和分析至关重要。本文将带你使用Python和LangChain构建一个医疗文本分类系统,能够自动将医疗文本归类到预定义的类别中。这种方法可以大大提高医疗数据处理效率,辅助医生诊断和研究。

准备工作

环境要求

  • Python 3.8+
  • pip包管理工具
  • 推荐使用Jupyter Notebook或VS Code作为开发环境

安装依赖包

代码片段
pip install langchain openai pandas scikit-learn tiktoken

API密钥准备

如果你使用OpenAI的模型,需要准备好API密钥:

代码片段
import os
os.environ["OPENAI_API_KEY"] = "你的OpenAI_API_KEY"

项目结构概述

我们的医疗文本分类器将包含以下步骤:
1. 数据准备与预处理
2. LangChain模型选择与配置
3. 分类提示工程(Prompt Engineering)
4. 结果评估与优化

第一步:数据准备

示例数据集

我们创建一个简单的医疗文本数据集用于演示:

代码片段
import pandas as pd

# 创建示例医疗文本数据
data = {
    "text": [
        "患者主诉持续头痛三天,伴随轻度恶心",
        "体检报告显示血糖水平偏高",
        "X光片显示右腿胫骨骨折",
        "血液检查显示白细胞计数升高",
        "患者描述胸口疼痛并放射至左臂"
    ],
    "label": [
        "神经系统",
        "内分泌系统",
        "骨科",
        "血液系统",
        "心血管系统"
    ]
}

df = pd.DataFrame(data)
print(df)

数据预处理

代码片段
from langchain.text_splitter import CharacterTextSplitter

# 初始化文本分割器
text_splitter = CharacterTextSplitter(
    separator="\n",
    chunk_size=1000,
    chunk_overlap=200,
    length_function=len,
)

# 对长文本进行分割处理(示例)
sample_text = """
患者病历记录:
主诉:持续性头痛3天,伴有轻度恶心,无呕吐。
既往史:高血压病史5年,规律服药。
体格检查:血压145/90mmHg,神经系统检查未见明显异常。
初步诊断:偏头痛可能性大,建议进一步做头部CT检查排除其他病因。
"""

texts = text_splitter.create_documents([sample_text])
print(f"分割后的文本块数: {len(texts)}")

第二步:构建LangChain分类器

初始化LangChain分类链

代码片段
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

# 定义分类提示模板
classification_template = """
请将以下医疗文本分类到最合适的类别中:
可选的类别有: {classes}

医疗文本: {text}

请只返回最相关的类别名称,不要包含其他内容。
"""

prompt = PromptTemplate(
    template=classification_template,
    input_variables=["text", "classes"]
)

# 初始化LLM链
llm = OpenAI(temperature=0)  # temperature=0使输出更确定
classification_chain = LLMChain(llm=llm, prompt=prompt)

定义医疗类别

代码片段
medical_classes = [
    "心血管系统", 
    "呼吸系统", 
    "消化系统", 
    "神经系统", 
    "内分泌系统", 
    "骨科", 
    "血液系统"
]

第三步:执行分类任务

单个文本分类示例

代码片段
sample_text = "患者主诉持续头痛三天,伴随轻度恶心"

result = classification_chain.run({
    "text": sample_text,
    "classes": ", ".join(medical_classes)
})

print(f"分类结果: {result}")

批量分类处理

代码片段
def batch_classify(texts, classes):
    results = []
    for text in texts:
        result = classification_chain.run({
            "text": text,
            "classes": ", ".join(classes)
        })
        results.append(result.strip())  # strip()移除可能的空格或换行符

    return results

# 使用我们的示例数据进行测试
texts_to_classify = df["text"].tolist()
predicted_labels = batch_classify(texts_to_classify, medical_classes)

# 添加预测结果到DataFrame
df["predicted"] = predicted_labels
print(df)

第四步:评估与优化

计算准确率

代码片段
from sklearn.metrics import accuracy_score

accuracy = accuracy_score(df["label"], df["predicted"])
print(f"分类准确率: {accuracy:.2f}")

常见问题与优化建议

  1. 类别不平衡问题

    • 如果某些类别的样本过少,模型可能会偏向多数类。解决方案包括收集更多数据或对少数类进行过采样。
  2. 模糊边界问题

    • 有些症状可能涉及多个系统(如糖尿病可能影响心血管和内分泌系统),可以修改提示模板要求模型返回主要类别。
  3. 性能优化

    • LangChain支持异步调用,对于大批量数据可以提高处理速度:
代码片段
import asyncio

async def async_classify(text, classes):
    result = await classification_chain.arun({
        "text": text,
        "classes": ", ".join(classes)
    })
    return result.strip()

async def batch_async_classify(texts, classes):
    tasks = [async_classify(text, classes) for text in texts]
    return await asyncio.gather(*tasks)

# 使用示例 (在Jupyter notebook中可以直接await)
# predicted_labels = await batch_async_classify(texts_to_classify, medical_classes)
  1. 提示工程改进
    • 更详细的提示往往能得到更好的结果。例如:
代码片段
enhanced_template = """
您是一位经验丰富的医学专家。请将以下患者描述的症状归类到最相关的医学专科。

可选专科列表: {classes}

请按照以下步骤进行分析:
1. 识别症状涉及的主要身体系统或器官
2.考虑症状的严重程度和持续时间的影响因素 
3.选择最合适的专科类别 

患者描述: {text}

请只返回最相关的专科名称,不需要解释原因。
"""

LangChain的高级应用

Few-shot Learning示例

通过提供少量示例帮助模型更好地理解任务:

代码片段
few_shot_template = """
以下是几个医疗文本分类的例子:

输入: '患者咳嗽、咳痰伴发热3天'
输出: '呼吸系统'

输入: '胃痛、反酸两个月'
输出: '消化系统'

输入: '膝关节疼痛肿胀'
输出: '骨科'

现在请对以下新输入进行分类:
输入: '{text}'
输出:
"""

few_shot_prompt = PromptTemplate(
    template=few_shot_template,
    input_variables=["text"]
)

few_shot_chain = LLMChain(llm=llm, prompt=few_shot_prompt)

test_text = '心悸、胸闷一周'
result = few_shot_chain.run({"text": test_text})
print(result)  

Ensemble方法结合多个LLM判断

代码片段
from langchain.chains import SimpleSequentialChain

# 创建两个不同提示的链进行验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验证分析验...
prompt1 = PromptTemplate(
template="""作为初级医生,您认为以下症状最可能属于哪个专科?{classes}\n\n症状:{text}\n回答:""",
input_variables=["text","classes"]
)

prompt2=PromptTemplate(
template="""作为资深专家,您认为以下症状最可能属于哪个专科?{classes}\n\n症状:{text}\n回答:""",
input_variables=["text","classes"]
)

chain1=LLMChain(llm=llm,prompt=prompt1)
chain2=LLMChain(llm=llm,prompt=prompt2)

overall_chain=SimpleSequentialChain(chains=[chain1, chain2], verbose=True)

final_result=overall_chain.run({
"text":"头晕目眩伴随耳鸣",
"classes":",".join(medical_classes)
})

print("\n最终会诊结果:",final_result)

部署为应用程序(Flask示例)

将你的分类器部署为Web服务:

python from flask import Flask, request, jsonify app=Flask(__name__) @app.route('/classify', methods=['POST']) def classify(): data=request.json text=data.get('text') if not text: return jsonify({"error":"No text provided"}),400 try: result=classification_chain.run({ “text”: text,“classes”:“,”.join(medical_classes) }) return jsonify({“result”: result}) except Exception as e: return jsonify({“error”: str(e)}),500 if __name__==‘__main__’: app.run(host='0.0.0.0', port=5000)

启动服务后可以通过POST请求获取分类结果:

代码片段
curl -X POST http://localhost:5000/classify \
-H “Content-Type: application/json” \
-d ‘{“text”:“患者主诉持续头痛三天”}’

总结与扩展方向本文介绍了如何使用Python和LangChain构建医疗文本分类系统的完整流程。关键点包括:

1.LangChain提供了便捷的接口与大语言模型交互2.精心设计的提示模板对分类准确性至关重要3.Few-shot learning可以显著提升小样本场景下的表现4.Ensembe方法能整合不同视角的判断结果5可以轻松部署为Web服务供其他系统调用进一步扩展的方向包括:

集成更多专业医学知识库实现多标签分类(一个文本可能属于多个类别)加入实体识别提取关键医学术语开发可视化界面方便医护人员使用希望本教程能帮助你快速上手基于LLM的医疗文本处理!

原创 高质量