Vectorization

Vectorization converts variable-length persistence barcodes into fixed-length feature vectors suitable for machine learning. This guide covers all 8 vectorization methods available in MedTDA.

Overview

Persistence barcodes are sets of (birth, death) pairs with varying sizes across images. Machine learning requires fixed-length feature vectors. Vectorization methods solve this problem by summarizing barcodes into consistent-length representations.

from medtda import FeatureExtractor

extractor = FeatureExtractor(
    normalize=True,
    vectorization_method='PersStats'
)
features = extractor.execute('image.nii.gz', 'mask.nii.gz')

# features is a dictionary with fixed-length vectors for each homology dimension

Available Methods

MedTDA provides 8 vectorization methods:

  1. Persistence Statistics (PersStats) - Statistical summaries

  2. Betti Curves (BettiCurve) - Betti numbers over filtration

  3. Persistence Images (PersImage) - 2D histogram representation

  4. Persistence Landscapes (PersLandscape) - Functional representation

  5. Persistence Silhouettes (PersSilhouette) - Average landscape

  6. Entropy Summary (EntropySummary) - Information-theoretic features

  7. Lifespan Curves (PersLifespan) - Distribution of lifespans

  8. Tropical Coordinates (PersTropicalCoordinates) - Tropical algebra

Method Comparison

Method

Speed

Features

Persistence Stats

Fast

38/dim (named dict)

Betti Curves

Medium

resolution/dim (default: 100)

Persistence Images

Medium

resolution²/dim (default: 400)

Persistence Landscapes

Medium

num_landscapes × resolution/dim (default: 500)

Persistence Silhouettes

Medium

resolution/dim (default: 100)

Entropy Summary

Fast

resolution/dim (default: 100)

Lifespan Curves

Medium

resolution/dim (default: 100)

Tropical Coordinates

Slow

7/dim

Persistence Statistics

Statistical summaries of persistence values, birth/death times, and midpoints.

Usage

extractor = FeatureExtractor(
    vectorization_method='PersStats'
)

features = extractor.execute(image, mask)

Features Extracted

For each homology dimension (H₀, H₁, H₂), computes 38 features:

Birth time statistics (8):
  • Mean, std, min, max, median, 25th percentile, 75th percentile, IQR

Death time statistics (8):
  • Mean, std, min, max, median, 25th percentile, 75th percentile, IQR

Lifespan statistics (8):
  • Mean, std, min, max, median, 25th percentile, 75th percentile, IQR

Midpoint statistics (8):
  • Mean, std, min, max, median, 25th percentile, 75th percentile, IQR

  • Midpoint = (birth + death) / 2

Count (1): Number of persistence pairs

Entropy (1): Persistent entropy

Additional statistics (4): Mean/std of 2nd birth and 2nd death

Example output:

{
    'PersStats_H0_mean': 0.523,
    'PersStats_H0_std': 0.142,
    'PersStats_H0_min': 0.001,
    'PersStats_H0_max': 0.987,
    # ... 24 more features for H0
    'PersStats_H1_mean': 0.234,
    # ... 28 features for H1
    # ... 28 features for H2 (if max_dimension=2)
}

Betti Curves

Betti number (count of features) as a function of filtration value.

Usage

extractor = FeatureExtractor(
    vectorization_method='BettiCurve'
)

# Configure resolution
extractor.set_vectorization_params(
    'BettiCurve',
    resolution=100  # Number of points (default=100)
)

features = extractor.execute(image, mask)

Features Extracted

For each homology dimension, creates a curve with resolution points.

  • 3 dimensions × 100 points = 300 features (default)

  • Captures how the number of topological features evolves

Example: With resolution=100:

{
    'BettiCurve_H0_f0': 0.0,
    'BettiCurve_H0_f1': 1.2,
    'BettiCurve_H0_f2': 2.5,
    # ... 97 more points for H0
    'BettiCurve_H1_f0': 0.0,
    # ... 100 points for H1
    # ... 100 points for H2
}

Parameters

extractor.set_vectorization_params(
    'BettiCurve',
    resolution=200  # More points for smoother curve
)

Persistence Images

2D histogram representation of persistence diagrams.

Usage

extractor = FeatureExtractor(
    vectorization_method='PersImage'
)

# Configure parameters
extractor.set_vectorization_params(
    'PersImage',
    resolution=20,        # Grid size (default)
    bandwidth=0.1         # Gaussian smoothing (default)
)

features = extractor.execute(image, mask)

Features Extracted

Each persistence diagram → 2D image → flattened vector.

  • Grid size 20×20 = 400 features per dimension (default)

  • 3 dimensions × 400 = 1200 total features

Parameters

# Higher resolution (more features)
extractor.set_vectorization_params(
    'PersImage',
    resolution=50,        # 2500 features/dim
    bandwidth=0.05        # Less smoothing
)

# Lower resolution (fewer features)
extractor.set_vectorization_params(
    'PersImage',
    resolution=10,        # 100 features/dim
    bandwidth=0.2         # More smoothing
)

Persistence Landscapes

Functional representation based on landscape functions.

Usage

extractor = FeatureExtractor(
    vectorization_method='PersLandscape'
)

# Configure parameters
extractor.set_vectorization_params(
    'PersLandscape',
    num_landscapes=5,     # Number of landscape functions (default)
    resolution=100        # Points per landscape (default)
)

features = extractor.execute(image, mask)

Features Extracted

Multiple landscape functions sampled at regular intervals.

  • 5 landscapes × 100 points = 500 features per dimension

  • 3 dimensions × 500 = 1500 total features

Parameters

# More landscapes (capture more detail)
extractor.set_vectorization_params(
    'PersLandscape',
    num_landscapes=10,
    resolution=100
)

# Fewer features
extractor.set_vectorization_params(
    'PersLandscape',
    num_landscapes=3,
    resolution=50
)

Persistence Silhouettes

Weighted average of persistence landscapes (simpler than full landscapes).

Usage

extractor = FeatureExtractor(
    vectorization_method='PersSilhouette'
)

# Configure resolution
extractor.set_vectorization_params(
    'PersSilhouette',
    resolution=100
)

features = extractor.execute(image, mask)

Features Extracted

Single silhouette function per dimension.

  • 100 features per dimension (default resolution)

  • 3 dimensions × 100 = 300 total features

Entropy Summary

Information-theoretic measures of barcode complexity.

Usage

extractor = FeatureExtractor(
    vectorization_method='EntropySummary'
)

features = extractor.execute(image, mask)

Features Extracted

For each homology dimension, computes resolution features (default: 100).

Small feature vector per dimension.

Lifespan Curves

Distribution of persistence values (lifespans).

Usage

extractor = FeatureExtractor(
    vectorization_method='PersLifespan'
)

extractor.set_vectorization_params(
    'PersLifespan',
    resolution=100
)

features = extractor.execute(image, mask)

Features Extracted

Histogram of persistence values.

  • 100 features per dimension (default resolution)

Tropical Coordinates

Tropical algebra representation (advanced).

Usage

extractor = FeatureExtractor(
    vectorization_method='PersTropicalCoordinates'
)

features = extractor.execute(image, mask)

Note: Slower computation, specialized use.

Using Multiple Methods

Combine methods for comprehensive feature sets:

extractor = FeatureExtractor(
    normalize=True,
    vectorization_method=[
        'PersStats',
        'BettiCurve',
        'EntropySummary'
    ]
)

features = extractor.execute(image, mask)
print(f"Total features: {len(features)}")

Features are combined with prefixes indicating method and dimension.

Example Workflow

from medtda import FeatureExtractor
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
import pandas as pd

# 1. Extract features with multiple methods
extractor = FeatureExtractor(
    normalize=True,
    spacing=(1.0, 1.0, 1.0),
    vectorization_method=[
        'PersStats',
        'BettiCurve',
        'EntropySummary'
    ]
)

# 2. Process dataset
results = []
for case in dataset:
    features = extractor.execute(case['image'], case['mask'])
    features['label'] = case['label']
    results.append(features)

# 3. Prepare for ML
df = pd.DataFrame(results)
X = df.drop('label', axis=1)
y = df['label']

# 4. Standardize
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# 5. Train classifier
clf = RandomForestClassifier()
clf.fit(X_scaled, y)

Next Steps