第 1 章 环境准备与首次跑通 本章目标:5 分钟内安装依赖、跑通最小示例、理解返回字典里每个键的含义。 1.1 环境要求 项目 | 建议 Python | 3.8+(推荐 3.10 或 3.11) 操作系统 | Windows / macOS / Linux 均支持 wheel 安装 内存 | 小规模点云(n < 5000)8 GB 足够;大规模需配合 / 可选 | Jupyter Notebook 便于交互实验 1.2 安装依赖 方式一:PyPI 一键安装(推荐) Ripser.py 的 wheel 已捆绑 C++ 核心,通常无需本地编译。
本章目标:5 分钟内安装依赖、跑通最小示例、理解返回字典里每个键的含义。
| 项目 | 建议 |
|---|---|
| Python | 3.8+(推荐 3.10 或 3.11) |
| 操作系统 | Windows / macOS / Linux 均支持 wheel 安装 |
| 内存 | 小规模点云(n < 5000)8 GB 足够;大规模需配合 thresh / n_perm |
| 可选 | Jupyter Notebook 便于交互实验 |
pip install ripser persim numpy scipy scikit-learn matplotlib
Ripser.py 的 wheel 已捆绑 C++ 核心,通常无需本地编译。
conda install -c conda-forge ripser persim
| 包 | 用途 |
|---|---|
| ripser | 持久同调计算 |
| persim | 持久图可视化、瓶颈距离 |
| numpy | 点云与数组 |
| scipy | 稀疏距离矩阵 |
| scikit-learn | 距离度量、Rips 继承 Transformer 接口 |
| matplotlib | persim 绑图后端 |
⚠️ Windows 本地编译:若 wheel 安装失败需从源码编译,可能需要 MinGW 等 C++ 工具链。优先尝试升级 pip 后重装 wheel。
import ripser import persim import numpy as np print("ripser OK", ripser.__version__ if hasattr(ripser, '__version__') else "") print("numpy", np.__version__)
无报错即环境就绪。
为什么用圆环:圆环在 H1(一维同调)上有一个显著的「洞」——持久图中应出现远离对角线的点。这是 TDA 教程的「Hello World」。
import numpy as np from ripser import ripser from persim import plot_diagrams # 构造带噪声的圆环点云 (n, 2) n = 120 theta = np.linspace(0, 2 * np.pi, n, endpoint=False) data = np.column_stack([np.cos(theta), np.sin(theta)]) data += 0.08 * np.random.randn(n, 2) # 计算 H0 与 H1(maxdim=1 会算 dim 0 和 1) result = ripser(data, maxdim=1) # 持久图列表:result['dgms'][0] 是 H0,result['dgms'][1] 是 H1 plot_diagrams(result['dgms'], show=True)
| 维度 | 持久图上的典型形态 |
|---|---|
| H0(dim 0) | 多个点靠近对角线;一个远离对角线的长条(最后几个分量合并) |
| H1(dim 1) | 一个明显远离对角线的点(圆环的洞) |
💡 H0 的长条:每个连通分量在 birth=0 出现,随半径增大逐渐合并;最后只剩一个连通分量时 death 很大。
ripser() 返回一个字典,核心键如下:
result = ripser(X, ...) │ ├── 'dgms' ──► 持久图,list[maxdim+1],每项 shape (n_pairs, 2) ├── 'cocycles' ──► 代表上循环(需 do_cocycles=True) ├── 'num_edges' ──► 过滤中加入的边数(复杂度指标) ├── 'dperm2all' ──► 实际使用的距离矩阵 ├── 'idx_perm' ──► 贪心置换索引(n_perm 非空时) └── 'r_cover' ──► 子采样覆盖半径
持久图 dgms[d] 的每一行 [birth, death]:
birth:该拓扑特征在第 d 维同调中出现时的过滤参数(VR 情形下通常是边长/半径)death:该特征消失时的参数;inf 表示直到过滤结束仍存在若你更习惯 fit_transform 模式:
import numpy as np from ripser import Rips data = np.random.randn(80, 3) rips = Rips(maxdim=1, thresh=2.0) diagrams = rips.fit_transform(data) # diagrams 与 result['dgms'] 结构相同 rips.plot(diagrams)
Rips 在构造时固定 maxdim、thresh、coeff 等;transform 时传入不同点云。详见第 4 章。
# 只考虑距离 <= 1.5 的边,加速并聚焦局部结构 result = ripser(data, maxdim=1, thresh=1.5) print("边数:", result['num_edges'])
thresh 越小,复形越小、越快,但可能截断本该长寿的拓扑特征。第 3、9 章详述取舍。
maxdim 改为 0,观察 H1 消失——确认维数参数的含义。0.08 调到 0.3,看 H1 显著点是否靠近对角线——理解噪声对持久性的影响。result['dgms'][1],找出 persistence 最大的 H1 特征:death - birth。np.random.rand(100, 2) 均匀随机点重复实验,与圆环对比。pip install ripser persim 即可在主流平台跑通。ripser(data, maxdim=1)['dgms'] 是核心调用;dgms[0] 为 H0,dgms[1] 为 H1。thresh 可截断过滤规模,是首个性能杠杆。下一章:持久同调核心概念——搞懂 birth/death 背后的数学。