生境分割
本节介绍如何使用 HABIT 进行生境分割,这是 HABIT 的核心功能。
概述
生境分割是将肿瘤分割为多个具有相似特征的区域(生境)的过程。HABIT 提供了三种聚类策略,支持灵活的特征提取和自定义扩展。
生境分析的核心思想:
肿瘤异质性: 肿瘤不是均匀的组织,而是由多个具有不同特征的亚区域组成
功能分区: 不同的生境可能对应不同的生物学过程(如血管生成、坏死、炎症等)
临床意义: 生境特征可以提供比整体肿瘤特征更丰富的诊断信息
三种聚类策略:
One-Step 策略: 个体级别聚类,每个肿瘤独立进行体素到生境的聚类。
Two-Step 策略(推荐): 两步聚类,先体素到超像素(个体级),再超像素到生境(群体级)。
Direct Pooling 策略: 直接池化策略。该策略将所有受试者的所有体素特征一次性拼接(Pooling)到一个巨大的特征矩阵中进行聚类。这种方法能够发现群体中最具代表性的组织模式,且由于生境发现过程通常是无监督的,在特征空间进行的 Pooling 操作并不一定意味着标签信息的泄露。
结果解读指南
运行 get-habitat 后,您会得到一系列结果文件。以下是如何解读这些结果的临床指南。
1. 生境地图 (*_habitats.nrrd)
这是最直观的结果。您可以使用 ITK-SNAP 或 3D Slicer 打开原始 MRI 图像,然后将此文件拖入作为 Segmentation(或 Overlay)。
五颜六色的区域是什么? 每一个颜色代表一个“生境”(Habitat)。例如,红色可能代表 Cluster 1,蓝色代表 Cluster 2。
如何赋予临床意义? 您需要结合原始影像的信号特征来解读。 * 如果 Cluster 1 在 T1 增强序列上信号很高,在 ADC 图上信号很低,它可能代表 活性肿瘤区。 * 如果 Cluster 2 在 T2 序列上信号高,无强化,可能代表 坏死区 或 水肿区。
2. 聚类验证图 (visualizations/optimal_clusters/)
该图用于自动选择聚类数的场景(主要用于 One-Step)。
横轴:尝试的聚类数量(k=2, 3, 4...)。
纵轴:聚类评价指标(如 Inertia 或 Silhouette Score)。
如何看?
Kneedle:对 Inertia 曲线归一化后,选与对角线最大偏离点。
轮廓系数 (Silhouette):看哪个 k 的分数最高。
3. 聚类可视化图 (visualizations/*_clustering/)
聚类可视化通常包括:
one_step_clustering/:One-Step 的生境聚类可视化
supervoxel_clustering/:Two-Step 的超像素聚类可视化
habitat_clustering/:Two-Step/Direct Pooling 的生境聚类可视化
生境分析中的特征处理
在生境分析中,特征处理的目的是消除不同扫描设备或个体差异带来的噪声,同时保留具有生物学意义的组织差异。
- 1. 个体级别处理 (Subject-level)
目的:消除个体内的异常值(如 Winsorize 去极值)和进行初步的标准化(如 Min-Max 归一化)。
意义:确保每个受试者的影像特征在进入群体分析前具有可比的数值量级,避免某个病例因为信号强度极高而主导聚类结果。
- 2. 群体级别处理 (Group-level)
目的:在所有受试者的特征池化后进行进一步处理(如 Binning 离散化)。
意义:通过离散化减少微小噪声的影响,使聚类算法更容易捕捉到稳定的组织模式(如“高强化区” vs “低强化区”),从而提高生境发现的鲁棒性。
CLI 使用方法
基本语法:
habit get-habitat --config <config_file> [--mode <mode>] [--pipeline <pipeline_path>] [--debug]
参数说明:
--config, -c: 配置文件路径(必需)
--mode, -m: 运行模式(train 或 predict),覆盖配置文件中的设置
--pipeline: Pipeline 文件路径,用于 predict 模式,覆盖配置文件中的设置
--debug: 启用调试模式
使用示例:
# 训练模式
habit get-habitat --config ./config_habitat_train.yaml --mode train
# 预测模式
habit get-habitat --config ./config_habitat.yaml --mode predict
# 使用指定的 Pipeline 文件
habit get-habitat --config ./config_habitat.yaml --mode predict --pipeline ./custom_pipeline.pkl
# 启用调试模式
habit get-habitat --config ./config_habitat.yaml --debug
输出:
生境图将保存在配置文件中指定的输出目录。
Python API 使用方法
基本用法:
from habit.core.common.service_configurator import ServiceConfigurator
from habit.core.habitat_analysis.config_schemas import HabitatAnalysisConfig
# 加载配置
config = HabitatAnalysisConfig.from_file('./config_habitat.yaml')
# 创建配置器
configurator = ServiceConfigurator(config=config)
# 创建生境分析对象
habitat_analysis = configurator.create_habitat_analysis()
# 运行生境分析
habitat_analysis.run()
详细示例:
import logging
from habit.core.common.service_configurator import ServiceConfigurator
from habit.core.habitat_analysis.config_schemas import HabitatAnalysisConfig
from habit.utils.log_utils import setup_logger
from pathlib import Path
# 设置日志
output_dir = Path('./results/habitat')
output_dir.mkdir(parents=True, exist_ok=True)
logger = setup_logger(
name='habitat_analysis',
output_dir=output_dir,
log_filename='habitat_analysis.log',
level=logging.INFO
)
# 加载配置
config = HabitatAnalysisConfig.from_file('./config_habitat.yaml')
# 创建配置器
configurator = ServiceConfigurator(config=config, logger=logger, output_dir=str(output_dir))
# 创建生境分析对象
habitat_analysis = configurator.create_habitat_analysis()
# 运行生境分析
logger.info("开始生境分析")
habitat_analysis.run(save_results_csv=True)
logger.info("生境分析完成!")
YAML 配置详解
配置文件结构:
# 运行模式和 Pipeline 设置(首先检查这些!)
run_mode: predict # train(如果要训练新模型,设置为 train)或 predict(如果要使用预训练模型,设置为 predict)
pipeline_path: ./results/habitat_pipeline.pkl # predict 模式的 Pipeline 路径(predict 模式必需)
# 数据路径
data_dir: ./file_habitat.yaml
out_dir: ./results/habitat/predict
# 特征提取设置(仅在 train 模式需要)
FeatureConstruction:
voxel_level:
method: concat(raw(delay2), raw(delay3), raw(delay5))
params: {}
supervoxel_level:
supervoxel_file_keyword: '*_supervoxel.nrrd'
method: mean_voxel_features()
params:
params_file: {}
preprocessing_for_subject_level:
methods:
- method: winsorize
winsor_limits: [0.05, 0.05]
global_normalize: true
- method: minmax
global_normalize: true
preprocessing_for_group_level:
methods:
- method: binning
n_bins: 10
bin_strategy: uniform
global_normalize: false
# 生境分割设置(仅在 train 模式需要)
HabitatsSegmention:
# 聚类策略:"one_step"、"two_step" 或 "direct_pooling"
clustering_mode: two_step
# 超像素聚类设置(第一步:个体级别聚类)
supervoxel:
algorithm: kmeans
n_clusters: 50 # two_step 模式使用,或 one_step 模式的最大值
random_state: 42
max_iter: 300
n_init: 10
# one_step 模式设置:每个肿瘤的自动聚类数选择
one_step_settings:
min_clusters: 2 # 要测试的最小聚类数
max_clusters: 10 # 要测试的最大聚类数
selection_method: inertia # 确定最佳聚类数的方法:silhouette、calinski_harabasz、davies_bouldin、inertia、kneedle
plot_validation_curves: true # 为每个肿瘤绘制验证曲线
# 生境聚类设置(第二步:群体级别聚类,仅在 two_step 模式使用)
habitat:
algorithm: kmeans # kmeans 或 gmm
max_clusters: 10
# - 'silhouette'、'calinski_harabasz': 选择最大分数(越高越好)
# - 'inertia'、'kneedle': 使用 Kneedle 在 inertia 曲线上选拐点
# - 'aic'、'bic': 选择最小分数(越低越好)
habitat_cluster_selection_method:
- inertia
# - silhouette
# - calinski_harabasz
# - aic
# - bic
# - davies_bouldin
fixed_n_clusters: # 固定的聚类数(设置为 null 则自动选择)
random_state: 42
max_iter: 300
n_init: 10
# 通用设置
processes: 2 # 并行进程数
plot_curves: true # 是否生成和保存图表
save_results_csv: true # 是否将结果保存为 CSV 文件
random_state: 42 # 可重复性的随机种子
debug: false # 启用详细日志的调试模式
字段说明:
run_mode: 运行模式
train: 训练新模型
predict: 使用预训练模型进行预测
pipeline_path: Pipeline 文件路径
predict 模式必需
指定训练好的 Pipeline 文件路径
data_dir: 数据目录路径
可以是文件夹或 YAML 配置文件
参考 数据结构说明 了解数据结构
out_dir: 输出目录路径
生境图和结果将保存在此目录
FeatureConstruction: 特征提取设置
voxel_level: 体素级特征提取
supervoxel_level: 超像素级特征提取
preprocessing_for_subject_level: 个体级别预处理
preprocessing_for_group_level: 群体级别预处理
HabitatsSegmention: 生境分割设置
clustering_mode: 聚类策略(one_step、two_step、direct_pooling)
supervoxel: 超像素聚类设置
habitat: 生境聚类设置
聚类策略详解
One-Step 策略
描述:
对每个肿瘤独立进行体素到生境的聚类。
适用场景: - 样本量较小 - 希望保留每个肿瘤的独特特征 - 不需要跨患者的泛化
优点: - 简单直接 - 每个肿瘤独立分析 - 计算复杂度较低
缺点: - 可能难以发现跨患者的共同模式 - 泛化能力较弱
配置示例:
HabitatsSegmention:
clustering_mode: one_step
supervoxel:
algorithm: kmeans
n_clusters: 10 # 最大聚类数
random_state: 42
one_step_settings:
min_clusters: 2
max_clusters: 10
selection_method: silhouette
plot_validation_curves: true
Two-Step 策略(推荐)
描述:
两步聚类: - 第一步:体素到超像素(个体级别) - 第二步:超像素到生境(群体级别)
适用场景: - 样本量较大 - 希望发现跨患者的共同生境模式 - 需要更好的泛化能力
优点: - 可以发现跨患者的共同生境模式 - 提高泛化能力 - 减少计算复杂度
缺点: - 计算复杂度较高 - 需要更多的参数调优
配置示例:
HabitatsSegmention:
clustering_mode: two_step
supervoxel:
algorithm: kmeans
n_clusters: 50
random_state: 42
habitat:
algorithm: kmeans
max_clusters: 10
habitat_cluster_selection_method:
- inertia
- silhouette
fixed_n_clusters: null # 自动选择
random_state: 42
3. Direct Pooling 策略
描述:
将所有受试者的所有体素池化后一次性聚类。
适用场景: - 数据量较小 - 希望快速获得结果 - 不需要个体差异
优点: - 计算速度快 - 实现简单 - 能够捕捉群体中最显著的组织模式
缺点: - 可能忽略个体差异 - 对内存要求较高(因为一次性处理所有体素)
关于数据泄露的说明: 虽然该策略使用了所有受试者的数据进行聚类,但由于生境发现本质上是一个**无监督学习**过程(不涉及预测标签),在特征空间进行的 Pooling 操作通常不被视为传统意义上的“标签泄露”。它更像是一种群体水平的特征表示学习。
配置示例:
HabitatsSegmention:
clustering_mode: direct_pooling
habitat:
algorithm: kmeans
max_clusters: 10
habitat_cluster_selection_method:
- inertia
fixed_n_clusters: null
random_state: 42
Pipeline 机制
连通域后处理(减少碎块)
为了减少生境图中“破碎小块”,HABIT 支持在 ROI 内执行连通域后处理。当前实现采用 SimpleITK 快路径:
按标签识别并临时移除小连通域(体素数小于
min_component_size)。使用最近的大连通域种子标签对被移除体素进行回填。
该流程的关键目标是:减少碎块,同时保持 ROI 内体素不丢失。
可配置入口:
HabitatsSegmention.postprocess_supervoxel:超体素层后处理(主要用于 two_step 的 voxel->supervoxel 结果)HabitatsSegmention.postprocess_habitat:生境层后处理(适用于 one_step/two_step/direct_pooling 的最终生境图)
参数说明:
enabled: 是否启用后处理min_component_size: 连通域最小体素数阈值,小于阈值的组件会被临时移除并回填connectivity: 连通性设置。当前实现中1为面邻接优先;2/3在快路径中均表现为全连接行为debug_postprocess: 是否输出后处理详细日志(按标签/阶段)reassign_method: 兼容字段,当前快路径中已忽略max_iterations: 兼容字段,当前快路径中已忽略
配置示例:
HabitatsSegmention:
postprocess_supervoxel:
enabled: false
min_component_size: 30
connectivity: 1
debug_postprocess: false
reassign_method: neighbor_vote # deprecated/ignored
max_iterations: 3 # deprecated/ignored
postprocess_habitat:
enabled: true
min_component_size: 30
connectivity: 1
debug_postprocess: false
reassign_method: neighbor_vote # deprecated/ignored
max_iterations: 3 # deprecated/ignored
说明:
后处理仅作用于 ROI 内标签,ROI 外保持 0。
当前快路径会保证 ROI 内体素保持有标签(不会永久删除 ROI 体素)。
建议先从
min_component_size=30、connectivity=1开始调参。
HABIT 继承了 scikit-learn 的 Pipeline 机制,这是避免数据泄露的关键设计。
什么是数据泄露?
数据泄露是指在模型训练过程中,测试集的信息意外地泄露到训练集中,导致模型性能被高估。
Pipeline 如何避免数据泄露?
训练阶段: 在训练集上训练 Pipeline,包括特征提取、聚类等步骤
预测阶段: 加载训练好的 Pipeline,应用于测试集,确保使用相同的处理流程
严格分离: 训练集和测试集完全分离,避免测试集信息泄露
生境分析中的 Pipeline:
from habit.core.common.service_configurator import ServiceConfigurator
from habit.core.habitat_analysis.config_schemas import HabitatAnalysisConfig
# 加载配置
config = HabitatAnalysisConfig.from_file('./config_habitat.yaml')
# 创建配置器
configurator = ServiceConfigurator(config=config)
# 创建生境分析对象
habitat_analysis = configurator.create_habitat_analysis()
# 运行生境分析
habitat_analysis.run()
关键要点:
训练和预测必须使用相同的 Pipeline
不要在整个数据集上进行聚类
使用交叉验证时,每个 fold 的训练和预测必须严格分离
特征提取详解
体素级特征提取
描述:
对每个体素提取特征。
适用场景: - 需要精细的空间分析 - 研究体素级别的异质性
配置示例:
FeatureConstruction:
voxel_level:
method: concat(raw(delay2), raw(delay3), raw(delay5))
params: {}
内置特征提取器:
raw: 原始图像强度
kinetic: 动力学特征
local_entropy: 局部熵
mean_voxel_features: 平均体素特征
supervoxel_radiomics: 超像素影像组学特征
超像素级特征提取
描述:
对超像素区域提取特征。
适用场景: - 需要区域级别的分析 - 减少计算复杂度
配置示例:
FeatureConstruction:
supervoxel_level:
supervoxel_file_keyword: '*_supervoxel.nrrd'
method: mean_voxel_features()
params:
params_file: {}
预处理方法
个体级别预处理:
preprocessing_for_subject_level:
methods:
- method: winsorize
winsor_limits: [0.05, 0.05]
global_normalize: true
- method: minmax
global_normalize: true
- method: log
global_normalize: true
群体级别预处理:
preprocessing_for_group_level:
methods:
- method: binning
n_bins: 10
bin_strategy: uniform
global_normalize: false
无监督特征筛选放置原则
在聚类任务中,variance_filter 和 correlation_filter 这类“删列型”方法会改变特征维度。
为避免跨受试者特征列不一致,建议按聚类策略放置:
two_step: - 个体级别(
preprocessing_for_subject_level)不要使用删列型方法 - 推荐在群体级别(preprocessing_for_group_level)执行删列型方法one_step: - 可在个体级别使用删列型方法(每个受试者独立聚类) - 若需要跨受试者可比性,仍建议把删列放在群体级别
direct_pooling: - 推荐在群体级别执行删列型方法,以保证列空间一致
推荐的无监督筛选方法:
variance_filter: 删除低方差特征correlation_filter: 删除高相关冗余特征
自定义特征提取器
HABIT 支持自定义特征提取器,您可以添加自己的特征提取方法。
步骤 1: 创建自定义特征提取器
from habit.core.habit_analysis.extractors.base_extractor import BaseClusteringExtractor
from habit.core.habit_analysis.extractors.base_extractor import register_feature_extractor
@register_feature_extractor('my_feature_extractor')
class MyFeatureExtractor(BaseClusteringExtractor):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.feature_names = ['feature1', 'feature2', 'feature3']
def extract_features(self, image_data, **kwargs):
# 实现特征提取逻辑
n_samples = image_data.shape[0]
features = np.random.random((n_samples, 3))
return features
步骤 2: 在配置文件中使用
FeatureConstruction:
voxel_level:
# 注意:多图像输入时,每个图像名称必须包裹在 raw() 中
method: my_feature_extractor(raw(delay2), raw(delay3))
params:
param1: value1
步骤 3: 运行生境分析
habit get-habitat --config config_with_custom_extractor.yaml
实际示例
示例 1: 训练模式
run_mode: train
data_dir: ./file_habitat.yaml
out_dir: ./results/habitat/train
FeatureConstruction:
voxel_level:
method: concat(raw(delay2), raw(delay3), raw(delay5))
params: {}
supervoxel_level:
supervoxel_file_keyword: '*_supervoxel.nrrd'
method: mean_voxel_features()
params:
params_file: {}
preprocessing_for_group_level:
methods:
- method: binning
n_bins: 10
bin_strategy: uniform
HabitatsSegmention:
clustering_mode: two_step
supervoxel:
algorithm: kmeans
n_clusters: 50
random_state: 42
habitat:
algorithm: kmeans
max_clusters: 10
habitat_cluster_selection_method:
- inertia
- silhouette
random_state: 42
processes: 2
plot_curves: true
save_results_csv: true
random_state: 42
示例 2: 预测模式
run_mode: predict
pipeline_path: ./results/habitat/train/habitat_pipeline.pkl
data_dir: ./file_habitat.yaml
out_dir: ./results/habitat/predict
processes: 2
random_state: 42
输出结构
生境分析的输出结构(具体文件取决于策略与是否开启可视化):
results/habitat/
├── train/ # 训练模式输出
│ ├── habitat_pipeline.pkl # 训练好的 Pipeline
│ ├── habitats.csv # 生境结果表(如启用保存)
│ ├── subj001_habitats.nrrd # 生境图(One-Step/Direct Pooling)
│ ├── subj001_supervoxel.nrrd # 超像素图(Two-Step)
│ ├── visualizations/ # 可视化图表
│ │ ├── optimal_clusters/ # One-Step 聚类验证曲线
│ │ ├── one_step_clustering/
│ │ ├── supervoxel_clustering/
│ │ └── habitat_clustering/
│ └── habitat_analysis.log # 日志文件
└── predict/ # 预测模式输出
├── habitats.csv
├── subj001_habitats.nrrd
├── subj001_supervoxel.nrrd
├── visualizations/
│ └── ...
└── habitat_analysis.log
常见问题
Q1: 如何选择聚类策略?
A: 根据您的研究需求选择:
研究型项目: 推荐使用 Two-Step 策略,平衡了群体一致性和个体差异。
快速原型: 可以使用 Direct Pooling 策略,适合初步探索群体模式。
小样本研究: 可以考虑 One-Step 策略,关注每个病例的独特性。
Q2: 如何确定最佳聚类数?
A: HABIT 提供了多种自动化评估方法:
inertia: 使用 Kneedle 方法在 inertia 曲线上选拐点。
kneedle: 直接使用 Kneedle 方法(对 inertia 曲线归一化后选最大偏离点)。
silhouette: 使用轮廓系数。
calinski_harabasz: 使用 Calinski-Harabasz 指数。
davies_bouldin: 使用 Davies-Bouldin 指数。
Q3: 训练和预测模式有什么区别?
A: - 训练模式: 在训练集上训练新的 Pipeline(包括特征预处理、聚类模型等),并保存为 .pkl 文件。 - 预测模式: 加载已保存的 Pipeline,将其直接应用于新数据,确保新数据的处理逻辑与训练集完全一致。
Q4: 如何避免数据泄露?
A: 遵循以下原则:
始终使用 Pipeline 机制进行预测。
在机器学习建模前,确保生境发现过程不包含任何标签信息。
如果使用 Direct Pooling,请明确其无监督属性。
Q5: 生境分割失败怎么办?
A: 检查以下几点:
配置文件中的 data_dir 是否指向了正确的 YAML 或文件夹。
图像和 ROI Mask 的空间几何信息(Origin, Spacing, Direction)是否完全一致。
查看输出目录下的 habitat_analysis.log 文件,寻找具体的 Python 报错堆栈。
下一步
生境分割完成后,您可以: