时间:2026-03-03 06:58
人气:
作者:admin

在医疗信息化进程中,非结构化的文本数据占据了医疗信息的很大比重——从电子病历的病程记录、出院小结,到医学文献、临床指南,乃至患者的在线咨询记录。如何从这些海量文本中高效、准确地提取关键信息,是医疗AI面临的重要挑战。朴素贝叶斯(Naïve Bayes)算法以其简单、高效、对高维稀疏数据适应性强的特点,成为医学文本分类任务中的经典利器。本章将从算法原理出发,深入解析朴素贝叶斯在医疗场景中的应用,并通过实战案例展示从文本预处理、特征提取到模型训练与评估的完整流程。
朴素贝叶斯是一系列基于贝叶斯定理的分类算法,其核心是“朴素”的条件独立性假设——在给定类别的情况下,各个特征之间相互独立。尽管这一假设在现实中很少完全成立,但朴素贝叶斯在众多实际任务中仍表现出色,尤其是在文本分类领域。
贝叶斯定理描述了在已知某些条件下,事件发生的概率如何更新。对于分类问题,我们希望计算给定样本 (x) 的条件下,其属于类别 (C_k) 的概率,即后验概率 (P(C_k | x))。根据贝叶斯定理:
[
P(C_k | x) = \frac{P(x | C_k) P(C_k)}{P(x)} = \frac{P(x | C_k) P(C_k)}{\sum_j P(x | C_j) P(C_j)}
]
其中:
设样本 (x = (x_1, x_2, …, x_p)) 包含 (p) 个特征。朴素贝叶斯假设在给定类别 (C_k) 的条件下,各个特征之间相互独立,即:
[
P(x | C_k) = \prod_{i=1}^{p} P(x_i | C_k)
]
这一假设极大地简化了计算,因为原本需要估计联合概率分布,现在只需要估计每个特征的条件概率。尽管独立性假设通常不成立,但研究表明,在许多分类任务中,朴素贝叶斯依然能取得良好的性能,尤其是在特征之间相关性不强或数据集足够大的情况下。
根据特征的不同分布假设,朴素贝叶斯有以下三种常见变体:
适用于连续数值型特征,假设特征在给定类别下服从正态分布:
[
P(x_i | C_k) = \frac{1}{\sqrt{2\pi\sigma_{ik}^2}} \exp\left(-\frac{(x_i - \mu_{ik})2}{2\sigma_{ik}2}\right)
]
其中 (\mu_{ik}) 和 (\sigma_{ik}^2) 是类别 (C_k) 中第 (i) 个特征的均值和方差,从训练数据中估计。
适用于离散特征,特别是文本分类中的词频或 TF-IDF 值。假设特征向量 (x) 由计数组成(如单词出现次数),则条件概率为:
[
P(x | C_k) = \frac{(\sum_i x_i)!}{\prod_i x_i!} \prod_i \theta_{ki}^{x_i}
]
其中 (\theta_{ki}) 是类别 (C_k) 中特征 (i) 出现的概率,可用平滑技术(如拉普拉斯平滑)估计:
[
\hat{\theta}{ki} = \frac{N{ki} + \alpha}{N_k + \alpha n}
]
这里 (N_{ki}) 是类别 (C_k) 中特征 (i) 的总计数,(N_k) 是类别 (C_k) 中所有特征的总计数,(n) 是特征总数,(\alpha) 是平滑参数(通常取 1)。
适用于二元特征(如单词是否出现)。假设特征 (x_i) 取值为 0 或 1,则条件概率为:
[
P(x | C_k) = \prod_{i=1}^{p} \theta_{ki}^{x_i} (1 - \theta_{ki})^{1-x_i}
]
其中 (\theta_{ki} = P(x_i = 1 | C_k)),可用平滑估计。
在医学文本分类中,多项式朴素贝叶斯和伯努利朴素贝叶斯最为常用,因为文本数据通常表示为词频或词出现与否。
在估计条件概率时,如果某个特征在训练集中未出现,其概率会为零,导致整个乘积为零。为避免这一问题,通常引入拉普拉斯平滑(加一平滑):
[
P(x_i | C_k) = \frac{\text{计数}(x_i, C_k) + \alpha}{\text{总计数}(C_k) + \alpha \cdot n}
]
其中 (\alpha \geq 0) 是平滑参数,通常取 1。
由于多个概率相乘可能导致数值下溢,实际计算中通常取对数,将乘法转化为加法:
[
\log P(C_k | x) \propto \log P(C_k) + \sum_{i=1}^{p} \log P(x_i | C_k)
]
由于对数函数单调递增,分类时只需比较不同类别的对数后验概率大小即可。
朴素贝叶斯的训练和预测流程如下:
训练阶段:
预测阶段:
朴素贝叶斯在医疗领域的应用主要集中在文本分类任务,同时也适用于部分非文本分类场景。
电子病历中包含大量自由文本,如病程记录、出院小结、影像报告等。朴素贝叶斯可用于:
医学文献数据库(如 PubMed)包含海量文献,朴素贝叶斯可用于:
在医学问答系统中,朴素贝叶斯可用于:
从社交媒体、药物评论、电子病历中自动识别药物不良反应:
从急诊记录、网络搜索记录中早期识别传染病暴发:
在医学教育中,朴素贝叶斯可用于:
尽管朴素贝叶斯在文本分类中表现突出,它也可用于其他医疗任务:
病理报告是癌症诊断的金标准,其中包含对肿瘤类型、分级、分期等的详细描述。自动对病理报告进行分类,可辅助肿瘤登记、科研数据提取和临床决策支持。本节将使用一个模拟的病理报告数据集,演示如何利用朴素贝叶斯进行多类别文本分类。
我们模拟一个包含 2000 份病理报告的数据集,每份报告为一段英文文本,涉及三种主要癌症类型:
文本中包含了肿瘤部位、组织学类型、分级、免疫组化等信息。目标是构建一个分类器,能够根据报告文本自动判断癌症类型。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score
from sklearn.pipeline import Pipeline
import re
import nltk
from nltk.corpus import stopwords
nltk.download('stopwords')
stop_words = stopwords.words('english')
# 加载数据(假设已有csv文件)
df = pd.read_csv('pathology_reports.csv')
print(df.head())
print(df['cancer_type'].value_counts())
输出示例:
report_id text cancer_type
0 1 "Invasive ductal carcinoma, grade 2, ER+..." Breast
1 2 "Adenocarcinoma of the lung, T2N1M0, EGFR..." Lung
2 3 "Moderately differentiated adenocarcinoma..." Colorectal
3 4 "Lobular carcinoma, grade 1, ER+/PR+..." Breast
4 5 "Squamous cell carcinoma of the lung, pT3..." Lung
cancer_type
Breast 800
Lung 700
Colorectal 500
文本分类的关键步骤是将原始文本转换为数值特征向量。常用方法包括:
我们使用 scikit-learn 的 CountVectorizer 或 TfidfVectorizer,它们内置了清洗、分词、去除停用词等功能。
# 定义预处理函数(可选,可集成到向量器中)
def preprocess_text(text):
# 转为小写
text = text.lower()
# 去除标点和数字
text = re.sub(r'[^a-zA-Z\s]', '', text)
return text
df['clean_text'] = df['text'].apply(preprocess_text)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
df['clean_text'], df['cancer_type'], test_size=0.2, random_state=42, stratify=df['cancer_type']
)
我们使用管道将向量化器和分类器组合,便于调参和交叉验证。
from sklearn.pipeline import Pipeline
from sklearn.feature_extraction.text import TfidfVectorizer
# 使用 TF-IDF 向量化 + 多项式朴素贝叶斯
pipeline = Pipeline([
('tfidf', TfidfVectorizer(stop_words='english', max_features=5000)),
('clf', MultinomialNB()