第 4 章 ripser 核心 API 本章系统梳理 函数 与 类 的参数、返回值、典型调用模式,并说明一次完整计算的生命周期。 4.1 两种接口怎么选 场景 | 推荐 脚本、一次性实验 | 函数 sklearn Pipeline、反复对同类数据变换 | 类 需要保存上次 cocycles、距离矩阵 | (属性 、 等) 两者底层调用同一 C++ 引擎,结果一致(相同参数下)。 4.
本章系统梳理
ripser()函数 与Rips类 的参数、返回值、典型调用模式,并说明一次完整计算的生命周期。
| 场景 | 推荐 |
|---|---|
| 脚本、一次性实验 | ripser() 函数 |
| sklearn Pipeline、反复对同类数据变换 | Rips 类 |
| 需要保存上次 cocycles、距离矩阵 | Rips(属性 cocycles_、dperm2all_ 等) |
两者底层调用同一 C++ 引擎,结果一致(相同参数下)。
ripser() 函数签名result = ripser( X, maxdim=1, thresh=np.inf, coeff=2, distance_matrix=False, do_cocycles=False, metric='euclidean', n_perm=None, )
| 参数 | 类型 | 默认 | 含义 |
|---|---|---|---|
X |
ndarray 或 sparse | — | 点云 (n, d) 或距离矩阵 (n, n) |
maxdim |
int | 1 | 最高同调维(会算 0…maxdim) |
thresh |
float | inf | 过滤最大尺度 |
coeff |
素数 int | 2 | 系数域 Z/pZ,p=coeff |
distance_matrix |
bool | False | True 时 X 视为距离矩阵 |
do_cocycles |
bool | False | 是否计算代表上循环 |
metric |
str 或 callable | euclidean | 点云距离(非 distance_matrix 时) |
n_perm |
int 或 None | None | 贪心置换子采样点数 |
| 键 | 类型 | 说明 |
|---|---|---|
dgms |
list of (n,2) arrays | dgms[d] 为 H_d 持久图 |
cocycles |
list of lists | 与 dgms 平行;需 do_cocycles=True |
num_edges |
int | 加入的边数 |
dperm2all |
ndarray | 使用的距离(或子采样距离) |
idx_perm |
ndarray | 子采样点在原点云中的索引 |
r_cover |
float | 子采样覆盖半径 |
输入 X │ ├─ distance_matrix=False ──► pairwise_distances(X, metric) ──► D │ ├─ n_perm 指定 ──► 贪心置换 ──► 子集 D_sub (n_perm × n) │ ├─ 稀疏 D ──► 稀疏过滤路径 │ └─ 稠密 D ──► C++ doRipsFiltrationDM │ ▼ 持久图 + 可选 cocycles │ ▼ 封装为 Python dict 返回
Rips 类from ripser import Rips rips = Rips( maxdim=1, thresh=np.inf, coeff=2, do_cocycles=False, n_perm=None, verbose=True, ) diagrams = rips.fit_transform(X, distance_matrix=False, metric='euclidean') # 等价于 rips.fit(X); diagrams = rips.transform(X) rips.plot(diagrams) # 依赖 persim
| 构造参数 | transform 参数 |
|---|---|
| maxdim, thresh, coeff, do_cocycles, n_perm | X, distance_matrix, metric |
| 属性 | 对应 dict 键 |
|---|---|
dgm_ |
dgms |
cocycles_ |
cocycles |
dperm2all_ |
dperm2all |
idx_perm |
idx_perm |
num_edges |
num_edges |
metric_ |
实际使用的度量 |
import numpy as np from ripser import ripser def my_dist(a, b): # 仅示例:加权 L1 w = np.array([1.0, 2.0]) return np.sum(w * np.abs(a - b)) data = np.random.randn(50, 2) result = ripser(data, metric=my_dist, maxdim=1) # result['dperm2all'] 保存了计算用的距离矩阵
callable 会对 X 的每一对行调用一次——大数据时先自行算 D 再 distance_matrix=True 更高效。
from sklearn.metrics import pairwise_distances from ripser import ripser D = pairwise_distances(data, metric='precomputed') # 或 D = ... 地理距离、图最短路径等 result = ripser(D, distance_matrix=True, maxdim=1)
⚠️ 方阵警告:若传入方阵但未设
distance_matrix=True,Ripser 会警告并仍当点云处理——维数错误会导致荒谬结果。方阵 + 对称 + 零对角线 → 应设 True。
dgms 的代码模板import numpy as np def summarize_diagrams(dgms): for dim, dgm in enumerate(dgms): if len(dgm) == 0: print(f"H{dim}: empty") continue pers = dgm[:, 1] - dgm[:, 0] finite = pers[np.isfinite(pers)] print(f"H{dim}: {len(dgm)} features, " f"max persistence = {finite.max():.4f}") result = ripser(data, maxdim=2) summarize_diagrams(result['dgms'])
| 情况 | 行为 |
|---|---|
| 距离矩阵非方阵 | ValueError |
n_perm + 稀疏矩阵 |
ValueError(不支持组合) |
n_perm > n |
ValueError |
n_perm ≤ 0 |
ValueError |
| 方阵未设 distance_matrix | UserWarning |
排查详见附录 C。
dgms[d][k, 0] = birth = 特征在过滤参数空间中出现的位置dgms[d][k, 1] = death = 消失或 infthresh = 第 3 章 VR 半径上界maxdim = 最高计算的 H_dripser() 与 Rips().fit_transform(),断言 dgms 一致。do_cocycles=True,检查 cocycles 与 dgms[1] 长度是否一致。distance_matrix,观察警告;修正后对比结果。metric='cosine' 对高维随机向量实验,与 euclidean 比较 H0 分量数。ripser(X, maxdim, thresh, ...) 返回含 dgms 的字典,是核心入口。Rips 适合 Pipeline;transform 后可通过属性访问上次结果。distance_matrix=True;自定义 metric 可函数或预计算 D。do_cocycles、n_perm、coeff 在第 6、8 章展开。「返回字典逐字段解读」示例会逐个键打印类型、shape、前几行,是把抽象的字典描述对应到具体数值的最佳起点。下面是完整脚本:
"""ripser() 返回字典逐字段解读完整示例。 对圆环点云开启 cocycles,逐字段打印返回字典的每个键: dgms / cocycles / num_edges / dperm2all / idx_perm / r_cover 依赖:pip install ripser numpy """ import numpy as np from ripser import ripser def sample_circle(n=80, noise=0.05, seed=1): rng = np.random.default_rng(seed) theta = np.linspace(0, 2 * np.pi, n, endpoint=False) pts = np.column_stack([np.cos(theta), np.sin(theta)]) return pts + rng.standard_normal(pts.shape) * noise def main(): data = sample_circle() # 开启 cocycles 才能在返回里看到代表上循环 result = ripser(data, maxdim=1, do_cocycles=True) print("=== ripser() 返回字典的键 ===") for k in result.keys(): v = result[k] if isinstance(v, list): print(f" {k:12s}: list, len={len(v)}") elif isinstance(v, np.ndarray): print(f" {k:12s}: ndarray, shape={v.shape}") else: print(f" {k:12s}: {type(v).__name__} = {v}") # dgms:持久图列表 dgms = result['dgms'] print("\n=== dgms(持久图列表)===") for d, dgm in enumerate(dgms): print(f" H{d}: shape={dgm.shape}, 前 3 行:") for row in dgm[:3]: print(f" birth={row[0]:.3f} death={row[1]}") # cocycles:与 dgms 一一对应 print("\n=== cocycles(与 dgms 一一对应)===") for d, cycs in enumerate(result['cocycles']): print(f" H{d}: {len(cycs)} 个 cocycle") # num_edges:过滤复杂度指标 print(f"\nnum_edges(过滤中加入的边数)= {result['num_edges']}") if __name__ == "__main__": main()
💡 「sklearn 风格接口与 thresh 调参」示例则演示 Rips 类的 fit / transform / transform 用法,以及 thresh 对速度与边数的影响——适合已经熟悉 sklearn Pipeline 的读者。
下一章:持久图解读与可视化——用 persim 看图、比图、向量化。