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:

  1. Birth times (p): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)

  2. Death times (q): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)

  3. Midpoints ((p+q)/2): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)

  4. Lifespans (q-p): mean, std, median, IQR, range, percentiles (10th, 25th, 75th, 90th)

  5. Count: Total number of features

  6. Entropy: Information-theoretic measure defined as:

\[E_\mu = -\sum_{[p,q] \in B} \mu_{p,q} \cdot \left(\frac{q-p}{L_\mu}\right) \cdot \log\left(\frac{q-p}{L_\mu}\right)\]

where \(L_\mu\) is the weighted sum of all persistence values:

\[L_\mu = \sum_{[p,q] \in B} \mu_{p,q} \cdot (q-p)\]

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:

  1. Sample filtration values uniformly

  2. At each value, count features alive (birth ≤ value < death)

  3. 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:

\[\beta_\mu(t) = \sum_{[p,q] \in B} \mathbb{1}_{p \leq t < q} \cdot \mu_{p,q}\]

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:

  1. Transform barcode to (birth, persistence) coordinates

  2. Create 2D grid

  3. Place Gaussian kernel at each point

  4. Weight by persistence

  5. 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:

\[\rho^\mu_{f,\Psi}(x,y) = \sum_{[p,q] \in B} \mu_{p,q} \cdot f(p,q-p) \cdot \psi_{p,q}(x,y)\]

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:

  1. Create landscape functions from barcode

  2. Sample multiple landscape levels

  3. Sample each function at regular intervals

  4. 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:

\[\Delta([p,q], t) = \max(\min(t-p, q-t), 0)\]

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:

\[\Lambda^k_\mu(t) = k\text{-th largest value in } \{\mu_{p,q} \cdot \Delta([p,q],t) : [p,q] \in B\}\]

Alternative definition:

\[\Lambda^k_\mu(t) = \sup\left\{s \geq 0 : \left(\sum_{[p,q] \in B} \mathbb{1}_{[t-s,t+s] \subset [p,q]} \cdot \mu_{p,q}\right) \geq k\right\}\]

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:

  1. Compute landscape functions

  2. Weight by persistence

  3. Average across all features

  4. 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:

\[\phi^w_\mu(t) = \frac{\sum_{[p,q] \in B} w_{p,q} \cdot \mu_{p,q} \cdot \Delta([p,q],t)}{\sum_{[p,q] \in B} w_{p,q} \cdot \mu_{p,q}}\]

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:

  1. Normalize persistence values

  2. Treat as probability distribution

  3. Compute entropy and related measures

  4. 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:

\[L_\mu = \sum_{[p,q] \in B} \mu_{p,q} \cdot (q-p)\]

The entropy summary function \(S_\mu : \mathbb{R} \to \mathbb{R}\) is:

\[S_\mu(t) = -\sum_{[p,q] \in B} \mathbb{1}_{p \leq t < q} \cdot \mu_{p,q} \cdot \left(\frac{q-p}{L_\mu}\right) \cdot \log\left(\frac{q-p}{L_\mu}\right)\]

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:

  1. Extract all persistence values

  2. Create histogram with fixed bins

  3. 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:

  1. Convert barcode intervals to (birth, lifespan) representation

  2. Sort intervals by lifespan in descending order

  3. 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:

  1. Largest lifespan: \(F_1 = \lambda_1\)

  2. Sum of two largest: \(F_2 = \lambda_1 + \lambda_2\)

  3. Sum of three largest: \(F_3 = \lambda_1 + \lambda_2 + \lambda_3\)

  4. Sum of four largest: \(F_4 = \lambda_1 + \lambda_2 + \lambda_3 + \lambda_4\)

  5. Total lifespan sum: \(F_5 = \sum_i \lambda_i\)

  6. Birth-weighted sum: \(F_6 = \sum_i \min(r\lambda_i, p_i)\)

  7. 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