Vectorization Methods
Introduction
Why Vectorization?
Persistence barcodes are variable-length representations - different images produce different numbers of topological features. However, most machine learning algorithms require fixed-length feature vectors.
Vectorization converts variable-length barcodes into fixed-length vectors suitable for:
Classification
Regression
Clustering
Statistical analysis
Note
The mathematical definitions and theoretical foundations presented in this section are based on the comprehensive survey by Ali et al. [Ali2023], which provides detailed comparisons and benchmarks of vectorization methods for persistent homology barcodes.
The Challenge
Given a barcode with n features:
barcode = [[b₁, d₁],
[b₂, d₂],
...,
[bₙ, dₙ]]
We need a function that produces a fixed-length vector regardless of n:
vectorize: ℝⁿˣ² → ℝᵐ
where m is fixed.
Vectorization Strategies
MedTDA provides 8 different vectorization methods, each with different properties and use cases.
1. Persistence Statistics
Idea: Compute statistical summaries of persistence values.
Features Extracted (38 total):
Birth times
Death times
Midpoints
Lifespans
Count
Entropy
Output Size: 38 features
Mathematical Definition:
For a barcode B with intervals [p, q] and multiplicity function \(\mu:B \to \mathbb{Z}_+\), the persistence statistics vector consists of:
Statistical measures of:
Birth times (p): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)
Death times (q): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)
Midpoints ((p+q)/2): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)
Lifespans (q-p): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)
Count: Total number of features
Entropy: Information-theoretic measure defined as:
where \(L_\mu\) is the weighted sum of all persistence values:
This vectorization was independently introduced and used in multiple works, providing a simple yet effective baseline for classification tasks.
Example:
from medtda.vectorizers import persistence_stats
stats = persistence_stats(barcode)
# Returns array of length ~13 with interpretable values
2. Betti Curves
Idea: Count features alive at each filtration value.
Process:
Sample filtration values uniformly
At each value, count features alive (birth ≤ value < death)
Result is a curve: filtration value → count
Output Size: Configurable (default: 100)
Mathematical Definition:
The Betti curve \(\beta_\mu : \mathbb{R} \to \mathbb{R}\) for a barcode with multiplicity function \(\mu:B \to \mathbb{Z}_+\) is defined as:
where \(\mathbb{1}\) is the indicator function that equals 1 when the condition is true and 0 otherwise.
Interpretation: At each filtration value t, the Betti curve counts how many features are “alive” - i.e., features that have already been born (p ≤ t) but not yet died (t < q).
Vectorization: The curve is sampled at regular intervals \(t_1, t_2, \ldots, t_m\) to produce a fixed-length feature vector of dimension m.
Example:
from medtda.vectorizers import betti_curve
curve = betti_curve(barcode, resolution=100)
# Returns array of length 100
3. Persistence Images
Idea: Create a 2D histogram of (birth, persistence) weighted by persistence.
Process:
Transform barcode to (birth, persistence) coordinates
Create 2D grid
Place Gaussian kernel at each point
Weight by persistence
Flatten to 1D vector
Output Size: resolution² (default: 20² = 400)
Mathematical Definition:
Persistence images transform each barcode interval [p,q] into the birth-persistence coordinate (p, q-p), then create a smoothed 2D representation.
Persistence Surface: Given a weighting function \(f:\mathbb{R}^2 \to \mathbb{R}_{\geq 0}\) and probability distributions \(\psi_{p,q}\) (typically Gaussian) centered at each (p, q-p), the persistence surface is:
Typical choices:
Weighting: \(f(x,y) = y/\lambda_{\text{max}}\) for \(0 < y < \lambda_{\text{max}}\) (longer persistence → higher weight)
Gaussian kernel: \(\psi_{p,q}(x,y) = (1/2\pi\sigma^2) \exp(-(x-p)^2 + (y-(q-p))^2)/(2\sigma^2))\)
where \(\lambda_{\text{max}}\) is the maximum persistence in the barcode.
Vectorization: The surface is discretized on a regular grid and flattened into a 1D vector. For a resolution of \(m \times m\), this produces a feature vector of dimension \(m^2\).
Example:
from medtda.vectorizers import persistence_image
pi = persistence_image(barcode, bandwidth=0.2, resolution=20)
# Returns 20×20 array, flatten for ML: pi.flatten()
4. Persistence Landscapes
Idea: Functional representation using piecewise linear functions.
Process:
Create landscape functions from barcode
Sample multiple landscape levels
Sample each function at regular intervals
Concatenate all samples
Output Size: num_landscapes × resolution (default: 5 × 100 = 500)
Mathematical Definition:
Persistence landscapes define a sequence of continuous functions. For each interval [p,q], define a “tent” function:
This creates a triangular function that:
Equals 0 for t < p or t > q
Increases linearly from p to (p+q)/2
Decreases linearly from (p+q)/2 to q
Has maximum value (q-p)/2 at the midpoint
The k-th landscape function \(\Lambda^k_\mu : \mathbb{R} \to \mathbb{R}\) is defined by taking, at each point t, the k-th largest value among all tent functions:
Alternative definition:
Stability: Persistence landscapes are stable with respect to the bottleneck distance, making them theoretically well-founded for statistical analysis.
Example:
from medtda.vectorizers import persistence_landscape
landscape = persistence_landscape(barcode, resolution=100, num_landscapes=5)
# Returns 5×100 array, flatten for ML: landscape.flatten()
5. Persistence Silhouettes
Idea: Average persistence landscape weighted by persistence.
Process:
Compute landscape functions
Weight by persistence
Average across all features
Sample at regular intervals
Output Size: Configurable (default: 100)
Mathematical Definition:
The persistence silhouette is a weighted average of landscape-like functions. Given a weight function \(w:B \to \mathbb{R}_+\) (typically \(w_{p,q} = (q-p)^\alpha\) for some \(\alpha \geq 0\)), the silhouette is:
where \(\Delta([p,q],t) = \max(\min(t-p, q-t), 0)\) is the tent function.
Weighting choices:
\(\alpha = 0\): All features weighted equally
\(\alpha = 1\): Features weighted by persistence (longer bars → more influence)
\(\alpha = 2\): Quadratic weighting emphasizes long-lived features
Example:
from medtda.vectorizers import persistence_silhouette
silhouette = persistence_silhouette(barcode, resolution=100)
# Returns array of length 100
6. Entropy Summary
Idea: Information-theoretic features from persistence distribution.
Process:
Normalize persistence values
Treat as probability distribution
Compute entropy and related measures
Sample distribution at intervals
Output Size: Configurable (default: 100)
Mathematical Definition:
The entropy summary function represents the contribution to total entropy at each filtration value. Let \(L_\mu\) be the total weighted persistence:
The entropy summary function \(S_\mu : \mathbb{R} \to \mathbb{R}\) is:
where \(\mathbb{1}_{p \leq t < q}\) is the indicator function (equals 1 if feature is alive at time t).
Interpretation:
Piecewise constant function
At each t, sums entropy contributions from all alive features
Normalized by total weighted persistence \(L_\mu\)
Also called the “life entropy curve” in literature
Example:
from medtda.vectorizers import entropy_summary
entropy = entropy_summary(barcode, resolution=100)
# Returns array of length 100
7. Persistence Lifespan
Idea: Histogram of persistence values.
Process:
Extract all persistence values
Create histogram with fixed bins
Normalize to probability distribution
Output Size: Configurable (default: 100 bins)
Example:
from medtda.vectorizers import persistence_lifespan
lifespan = persistence_lifespan(barcode, resolution=100)
# Returns array of length 100
8. Tropical Coordinates
Idea: Fixed-size encoding using symmetric tropical polynomial invariants of the barcode.
Process:
Convert barcode intervals to (birth, lifespan) representation
Sort intervals by lifespan in descending order
Evaluate 7 fixed symmetric tropical polynomial functions
Output Size: 7 features (fixed, independent of barcode size)
Mathematical Definition:
Tropical coordinates use tropical algebra, where standard operations (+, ×) are replaced by (max, +).
Given a barcode B with intervals sorted by lifespan \(\lambda_i = q_i - p_i\) in descending order (so \(\lambda_1 \geq \lambda_2 \geq \cdots \geq \lambda_n\)):
The 7 tropical coordinate features are:
Largest lifespan: \(F_1 = \lambda_1\)
Sum of two largest: \(F_2 = \lambda_1 + \lambda_2\)
Sum of three largest: \(F_3 = \lambda_1 + \lambda_2 + \lambda_3\)
Sum of four largest: \(F_4 = \lambda_1 + \lambda_2 + \lambda_3 + \lambda_4\)
Total lifespan sum: \(F_5 = \sum_i \lambda_i\)
Birth-weighted sum: \(F_6 = \sum_i \min(r\lambda_i, p_i)\)
Complementary spread: \(F_7 = \sum_i \left(M - \min(r\lambda_i, p_i) - \lambda_i\right)\)
where \(r\) is a scalar parameter (default 28) and \(M = \max_i \left(\min(r\lambda_i, p_i) + \lambda_i\right)\).
Features F1–F4 are set to 0 when fewer bars are available than required (e.g. F4 = 0 if fewer than 4 bars exist).
Stability: Tropical coordinates are stable with respect to the bottleneck distance — small changes in the barcode produce bounded changes in coordinate values.
Example:
from medtda.vectorizers import persistence_tropical_coordinates
coords = persistence_tropical_coordinates(barcode, r=28)
# Returns array of length 7
Combining Methods
Use multiple vectorization methods together:
from medtda.vectorizers import (
persistence_stats,
betti_curve,
persistence_image
)
import numpy as np
# Extract using multiple methods
stats = persistence_stats(barcode)
curve = betti_curve(barcode, resolution=100)
image = persistence_image(barcode, resolution=20).flatten()
# Concatenate all features
combined = np.concatenate([stats, curve, image])
print(f"Combined feature vector size: {len(combined)}")
# Size: 13 + 100 + 400 = 513
Multi-Dimensional Barcodes
Vectorize each homology dimension separately:
from medtda import BarcodeExtractor
from medtda.vectorizers import persistence_image
import numpy as np
# Extract barcodes
extractor = BarcodeExtractor(max_dimension=2)
barcodes = extractor.execute(image_3d)
# Vectorize each dimension
features = {}
for dim in [0, 1, 2]:
if len(barcodes[f'H{dim}']) > 0:
pi = persistence_image(barcodes[f'H{dim}'], resolution=20)
features[f'H{dim}'] = pi.flatten()
else:
# Handle empty barcodes
features[f'H{dim}'] = np.zeros(400)
# Concatenate all dimensions
all_features = np.concatenate([
features['H0'],
features['H1'],
features['H2']
])
print(f"Total feature vector: {len(all_features)}") # 1200
See Also
Persistent Homology - Computing barcodes
Barcodes and Diagrams - Understanding barcodes
Vectorization - Vectorization user guide
Vectorizers - Vectorization API reference