医疗文本预处理:Python+LangChain最佳实践

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

医疗文本预处理:Python+LangChain最佳实践

引言

在医疗健康领域,文本数据(如电子病历、医学文献、患者反馈等)包含大量有价值的信息。但这类数据往往存在格式不统一、专业术语多、隐私信息混杂等问题,直接分析效果不佳。本文将介绍如何使用Python和LangChain库对医疗文本进行高效预处理,为后续的NLP任务打下良好基础。

准备工作

环境要求

  • Python 3.8+
  • pip包管理工具
  • 推荐使用Jupyter Notebook进行实验

安装依赖

代码片段
pip install langchain python-dotenv pydantic spacy pandas tqdm
python -m spacy download en_core_web_sm  # 英文模型

医疗文本预处理全流程

1. 加载示例医疗文本

我们首先创建一个模拟的医疗记录数据集:

代码片段
import pandas as pd

medical_records = [
    {"patient_id": "P001", "text": "Patient presents with persistent cough and fever of 101°F for 3 days. No known allergies. Rx: Amoxicillin 500mg tid x7d."},
    {"patient_id": "P002", "text": "45yo male c/o chest pain radiating to left arm. BP 150/95, HR 88. ECG shows ST elevation. Admitted for MI rule out."},
    {"patient_id": "P003", "text": "Follow-up: Diabetes mellitus type II. HbA1c 7.2%. Continue metformin 1000mg BID, add glipizide 5mg QAM."}
]

df = pd.DataFrame(medical_records)
print(df.head())

2. 隐私信息脱敏处理

医疗文本常包含敏感信息,需先进行脱敏:

代码片段
from langchain.text_splitter import CharacterTextSplitter
from langchain.docstore.document import Document

def anonymize_text(text):
    # 简单示例:替换身份证号、电话号码等模式(实际项目应使用更复杂的正则)
    import re
    text = re.sub(r'\b\d{3}-\d{2}-\d{4}\b', '[SSN]', text)  # SSN格式
    text = re.sub(r'\b\d{10}\b', '[PHONE]', text)          # 电话号码
    text = re.sub(r'\b[A-Z]\d{4}\b', '[ID]', text)         # ID格式如A1234
    return text

# 应用到整个数据集
df['anonymized_text'] = df['text'].apply(anonymize_text)

3. 文本分块处理

长文档需要分块以便后续处理:

代码片段
text_splitter = CharacterTextSplitter(
    separator="\n",
    chunk_size=500,
    chunk_overlap=50,
    length_function=len,
)

docs = [Document(page_content=text) for text in df['anonymized_text']]
split_docs = text_splitter.split_documents(docs)
print(f"原始文档数: {len(docs)}, 分块后: {len(split_docs)}")

4. 医学实体识别与标准化

使用LangChain结合医学词典识别关键实体:

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

# 注意:实际使用时请替换为您的OpenAI API key
import os
os.environ["OPENAI_API_KEY"] = "your-api-key"

prompt = PromptTemplate(
    input_variables=["text"],
    template="""
    请从以下医疗文本中提取医学实体并标准化:
    1. 症状/体征(标记为SYMPTOM)
    2. 药物(标记为DRUG)
    3. 检查/检验(标记为TEST)
    4.诊断(标记为DIAGNOSIS)

    文本:{text}

    返回JSON格式:
    {{
        "symptoms": [],
        "drugs": [],
        "tests": [],
        "diagnoses": []
    }}
    """
)

llm = OpenAI(temperature=0)
ner_chain = LLMChain(llm=llm, prompt=prompt)

# 对第一条记录做示例处理
sample_result = ner_chain.run(df['anonymized_text'][0])
print(sample_result)

5. ICD编码映射(可选进阶步骤)

将诊断术语映射到标准ICD编码:

代码片段
from langchain.chains import TransformChain

def icd_mapping(inputs):
    text = inputs["text"]

    # TODO:这里应该连接真实的ICD编码数据库或API

    return {"icd_mapped_text": f"{text} [ICD-10 placeholder]"}

icd_chain = TransformChain(
    input_variables=["text"],
    output_variables=["icd_mapped_text"],
    transform=icd_mapping,
)

processed_text = icd_chain({"text": "Diabetes mellitus type II"})
print(processed_text)

LangChain预处理流水线

将上述步骤组合成完整流水线:

代码片段
from langchain.chains import SimpleSequentialChain

overall_chain = SimpleSequentialChain(
    chains=[ner_chain, icd_chain],
    verbose=True,
)

final_result = overall_chain.run(df['anonymized_text'][0])
print("\n最终处理结果:")
print(final_result)

实践经验与注意事项

  1. 隐私保护

    • HIPAA合规是硬性要求,确保所有PHI(受保护健康信息)被正确处理
    • Consider using specialized libraries like presidio for better anonymization
  2. 性能优化

    代码片段
    # LangChain支持批量处理提升效率 
    from langchain.chains import LLMRequestsChain 
    
    def batch_process(texts, chain, batch_size=5):
        results = []
        for i in range(0, len(texts), batch_size):
            batch = texts[i:i + batch_size]
            results.extend(chain.apply(batch))
        return results 
    
  3. 错误处理

    代码片段
    from tenacity import retry, stop_after_attempt 
    
    @retry(stop=stop_after_attempt(3)) 
    def safe_llm_call(text): 
        try:
            return ner_chain.run(text) 
        except Exception as e:
            print(f"Error processing: {e}")
            return None 
    
  4. 本地化考量

    • Chinese medical texts may need different handling:
      代码片段
      python -m spacy download zh_core_web_sm <br>
      

FAQ常见问题解决

Q1: LangChain处理速度慢怎么办?
A: Try:
– Using smaller chunk sizes (200-300 characters)
– Switching to faster LLMs like GPT-3.5-turbo

Q2: How to handle rare medical terms?
A: Build a custom dictionary:

代码片段
custom_dict = {
    "q.d.": "once daily",
    "BID": "twice daily"
}

Q3: Memory issues with large datasets?
A: Process incrementally:

代码片段
chunk_size = len(df) //10  
for i in range(0, len(df), chunk_size):
process_batch(df.iloc[i:i+chunk_size])  

Conclusion总结

本文介绍了使用Python和LangChain进行医疗文本预处理的完整流程:

  1. ✅ Privacy-preserving anonymization (隐私保护脱敏)
  2. ✅ Context-aware chunking (上下文感知分块)
  3. ✅ Medical NER with LLMs (基于LLM的医学实体识别)
  4. ✅ Standardization pipelines (标准化处理流水线)

关键优势:通过LangChain可以轻松构建可扩展的预处理流水线,特别适合需要多步骤处理的医疗文本场景。

下一步建议:将预处理后的数据接入向量数据库(如ChromaDB)构建医疗问答系统。

原创 高质量