第 9 章 工程实践要点 理论就绪后,本章汇总 参数选择、性能调优、可复现性、结果验证 的实战清单,帮助你在真实项目中稳定使用 Ripser.py。 9.1 端到端工作流 9.2 参数选择速查 参数 | 建议 | 默认 1;3D 表面空腔试 2; rarely 3+ | 从 k-NN 距离分位数扫;取 H1 稳定平台;不超过点云直径太多 | 欧氏默认;高维稀疏用 cosine;领域距离用预计算 D | 默认 2;需 torsion/定向再换奇素数 | n>5000 考虑;5002000 常见;对比全量瓶颈距离验误差 | 仅解释阶段开启 9.3 性能优化层次 监控指标 突然爆炸 → 降低 或稀疏化。 9.
理论就绪后,本章汇总 参数选择、性能调优、可复现性、结果验证 的实战清单,帮助你在真实项目中稳定使用 Ripser.py。
业务数据 │ ▼ 预处理(归一化、去离群、下采样) │ ▼ 选择过滤类型:VR 点云 / Lower-Star 图像时序 │ ▼ 设定 maxdim、thresh、metric、coeff │ ▼ 规模过大 ? ──► 稀疏 D 或 n_perm │ ▼ ripser / Rips 计算 │ ▼ 持久图 QC(显著点、稳定性扫描) │ ▼ 可视化 / 向量化 / 下游模型 │ ▼ 记录参数与版本(可复现)
| 参数 | 建议 |
|---|---|
maxdim |
默认 1;3D 表面空腔试 2; rarely 3+ |
thresh |
从 k-NN 距离分位数扫;取 H1 稳定平台;不超过点云直径太多 |
metric |
欧氏默认;高维稀疏用 cosine;领域距离用预计算 D |
coeff |
默认 2;需 torsion/定向再换奇素数 |
n_perm |
n>5000 考虑;500~2000 常见;对比全量瓶颈距离验误差 |
do_cocycles |
仅解释阶段开启 |
第 1 层:thresh 截断 ── 零成本,首选 第 2 层:稀疏 k-NN 图 ── 大 n、局部结构 第 3 层:n_perm 贪心置换 ── 超大 n,有界近似 第 4 层:降维/子采样点云 ── PCA、随机、分层 第 5 层:本地编译 + robin_hood ── 源码编译可快 ~30% 第 6 层:Ripser++(GPU) ── 见第 10 章
result = ripser(X, maxdim=1, thresh=t) print({ 'n_points': len(X), 'num_edges': result['num_edges'], 'H1_count': len(result['dgms'][1]), 'max_H1_pers': (result['dgms'][1][:,1] - result['dgms'][1][:,0]).max(), })
num_edges 突然爆炸 → 降低 thresh 或稀疏化。
| 检查 | 方法 |
|---|---|
| 实现是否正确 | 圆环、球面等玩具数据对照已知 H1/H2 |
| 参数敏感性 | 扫 thresh,显著特征应相对稳定 |
| 子采样误差 | n_perm vs 全量 bottleneck 距离 |
| 随机性 | 点云采样随机时,多次运行瓶颈距离应小 |
| 单位一致性 | 改变坐标尺度 → birth/death 同比缩放,持久性比例不变 |
import numpy as np SEED = 42 rng = np.random.default_rng(SEED) data = rng.random((100, 2)) # 记录实验元数据 meta = { 'maxdim': 1, 'thresh': 1.8, 'coeff': 2, 'metric': 'euclidean', 'n_perm': None, 'ripser_version': '...', # import ripser 查看 }
pip freeze | grep ripser| 错误 | 后果 |
|---|---|
| 不对不同类别用相同 thresh | 比较失真 |
| 高维小样本算 H2 | 空结果或噪声 |
| 忽略 H0 | 丢失聚类/连通信息 |
| 持久图点当作坐标 | 需向量化再进 ML |
| 过度解读单个 bar | 需统计/稳定性支撑 |
⚠️ TDA 不是万能:高噪声、低维差异小、样本极少时,持久图可能无判别力——应与传统特征并用。
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from ripser import Rips # 概念:Rips 作为 transformer,输出需自定义向量化步骤 pipeline = Pipeline([ ('scale', StandardScaler()), ('rips', Rips(maxdim=1, thresh=2.0)), # ('pi', PersistenceImager(...)) # 需自定义或 giotto-tda ])
Rips.transform 返回 list of diagrams,不是固定维向量——需后续 PersistenceImager 或统计函数。详见第 10 章。
| 环境 | 注意 |
|---|---|
| 服务端无 GUI | plot_diagrams(..., show=False) + 保存 png |
| Docker | 基于 manylinux wheel,一般无需编译链 |
| 内存受限 | 限制 maxdim、thresh、n_perm |
thresh 控规模,再稀疏化或 n_perm。「工程实践与可复现」示例把本章经验封装成四组演示:maxdim 对成本的影响、thresh 与边数的关系、可复现性检查、大数据三条路决策。下面给出可复现性检查与 thresh 扫描的完整脚本:
"""工程实践:可复现性与 thresh 扫描完整示例。 验证同种子同参数两次结果是否完全一致(科研复现底线), 并扫描 thresh 观察边数与耗时的关系。 依赖:pip install ripser numpy """ import time import numpy as np from ripser import ripser def sample_sphere(n=300, noise=0.03, seed=0): rng = np.random.default_rng(seed) pts = rng.standard_normal((n, 3)) pts /= np.linalg.norm(pts, axis=1, keepdims=True) return pts * (1.0 + rng.standard_normal(pts.shape) * noise) def reproducibility(): """同种子同参数两次结果是否完全一致。""" print("=== 可复现性检查 ===") cfg = dict(maxdim=1, thresh=1.5, coeff=2) for trial in range(2): data = sample_sphere(n=200, noise=0.05, seed=42) r = ripser(data, **cfg) pers = r['dgms'][1][:, 1] - r['dgms'][1][:, 0] pers = pers[np.isfinite(pers)] print(f" trial {trial}: H1 点数={len(r['dgms'][1])}, " f"max persistence={pers.max() if len(pers) else 0:.6f}") print(" 两次应完全一致(同种子 + 同参数)。") def thresh_scan(): """thresh 与 num_edges / 耗时的关系。""" print("\n=== thresh vs num_edges ===") data = sample_sphere(n=500, seed=1) print(f"{'thresh':>8s} {'time':>8s} {'edges':>10s} {'H1点数':>8s}") for thresh in [0.5, 1.0, 1.5, 2.0, 3.0]: t0 = time.perf_counter() r = ripser(data, maxdim=1, thresh=thresh) dt = time.perf_counter() - t0 print(f"{thresh:8.2f} {dt:8.2f}s {r['num_edges']:10d} " f"{len(r['dgms'][1]):8d}") def main(): reproducibility() thresh_scan() if __name__ == "__main__": main()
💡 可复现性检查看似简单,却是科研复现的底线——如果同种子两次结果不一致,说明环境有不确定性(如并行顺序),必须先解决再发表。
下一章:进阶拓展方向——ML 集成、Ripser++、与 GUDHI 等生态对比。