.. _api_vectorizers: =========== Vectorizers =========== .. currentmodule:: medtda.vectorizers The ``vectorizers`` module provides 8 different methods to convert persistence barcodes into fixed-length feature vectors. .. contents:: Contents :local: :depth: 2 Overview ======== Persistence barcodes are variable-length representations that need to be vectorized for machine learning. This module provides multiple vectorization strategies, each with different properties. **Available Methods:** 1. ``persistence_stats`` - Statistical summaries (fast, interpretable) 2. ``betti_curve`` - Betti numbers over filtration values 3. ``persistence_image`` - 2D histogram with Gaussian weighting 4. ``persistence_landscape`` - Functional representation 5. ``persistence_silhouette`` - Average persistence landscape 6. ``entropy_summary`` - Information-theoretic features 7. ``persistence_lifespan`` - Lifespan distribution 8. ``persistence_tropical_coordinates`` - Tropical algebra representation Quick Comparison ================ .. list-table:: :widths: 25 15 15 45 :header-rows: 1 * - Method - Speed - Size - Best For * - ``persistence_stats`` - Fast - dict (38 features) - Statistical summaries * - ``betti_curve`` - Fast - Medium (100) - Betti number evolution * - ``persistence_image`` - Medium - Large (400) - 2D histogram representation * - ``persistence_landscape`` - Medium - Large (500+) - Piecewise-linear landscape functions * - ``persistence_silhouette`` - Medium - Medium (100) - Weighted average landscape * - ``entropy_summary`` - Medium - Medium (100) - Entropy-based summary * - ``persistence_lifespan`` - Fast - Medium (100) - Lifespan distribution * - ``persistence_tropical_coordinates`` - Fast - 7 - Tropical polynomial invariants Functions ========= persistence_stats ----------------- .. autofunction:: medtda.vectorizers.persistence_stats Compute statistical summaries of persistence values. **Signature:** .. code-block:: python def persistence_stats(barcode: np.ndarray) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array of shape ``(n, 2)`` with ``[birth, death]`` columns **Returns:** * **stats** (*dict*) - Dictionary of 38 statistical features. Keys cover births, deaths, midpoints, and lifespans with statistics: mean, std, median, IQR, range, and percentiles (10, 25, 75, 90), plus ``count`` and ``entropy``. **Example:** :: from medtda.vectorizers import persistence_stats stats = persistence_stats(barcode) print(f"Feature count: {len(stats)}") # 38 # stats contains named features: # - stats['births_mean'], stats['births_std'], ... # - stats['lifespans_mean'], ... # - stats['count'], stats['entropy'] betti_curve ----------- .. autofunction:: medtda.vectorizers.betti_curve Compute Betti numbers as a function of filtration value. **Signature:** .. code-block:: python def betti_curve( barcode: np.ndarray, resolution: int = 100 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **resolution** (*int*) - Number of sample points (default: 100) **Returns:** * **curve** (*np.ndarray*) - 1D array of Betti numbers at each filtration value **Example:** :: from medtda.vectorizers import betti_curve # Default resolution curve = betti_curve(h1_barcode) print(f"Curve shape: {curve.shape}") # (100,) # Higher resolution for more detail curve_hires = betti_curve(h1_barcode, resolution=200) persistence_image ----------------- .. autofunction:: medtda.vectorizers.persistence_image Create a 2D histogram representation weighted by persistence. **Signature:** .. code-block:: python def persistence_image( barcode: np.ndarray, bandwidth: float = 0.2, resolution: int = 20 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **bandwidth** (*float*) - Gaussian kernel bandwidth (default: 0.2) * **resolution** (*int*) - Grid resolution (default: 20) **Returns:** * **image** (*np.ndarray*) - 2D array of shape ``(resolution, resolution)`` **Example:** :: from medtda.vectorizers import persistence_image # Default parameters pi = persistence_image(barcode) print(f"Image shape: {pi.shape}") # (20, 20) # Higher resolution, smaller bandwidth pi_hires = persistence_image( barcode, bandwidth=0.1, resolution=30 ) persistence_landscape ---------------------- .. autofunction:: medtda.vectorizers.persistence_landscape Compute persistence landscape representation. **Signature:** .. code-block:: python def persistence_landscape( barcode: np.ndarray, resolution: int = 100, num_landscapes: int = 5 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **resolution** (*int*) - Number of sample points (default: 100) * **num_landscapes** (*int*) - Number of landscape functions (default: 5) **Returns:** * **landscape** (*np.ndarray*) - 1D array of length ``num_landscapes * resolution`` **Example:** :: from medtda.vectorizers import persistence_landscape landscape = persistence_landscape(barcode) print(f"Shape: {landscape.shape}") # (500,) # Reshape for visualization landscape_2d = landscape.reshape(5, 100) # (num_landscapes, resolution) persistence_silhouette ---------------------- .. autofunction:: medtda.vectorizers.persistence_silhouette Compute persistence silhouette (average landscape). **Signature:** .. code-block:: python def persistence_silhouette( barcode: np.ndarray, resolution: int = 100, weight: float = 1.0 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **resolution** (*int*) - Number of sample points (default: 100) * **weight** (*float*) - Weighting power (default: 1.0) **Returns:** * **silhouette** (*np.ndarray*) - 1D array of length ``resolution`` **Example:** :: from medtda.vectorizers import persistence_silhouette silhouette = persistence_silhouette(barcode, resolution=150) entropy_summary --------------- .. autofunction:: medtda.vectorizers.entropy_summary Compute entropy-based features. **Signature:** .. code-block:: python def entropy_summary( barcode: np.ndarray, resolution: int = 100 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **resolution** (*int*) - Number of bins (default: 100) **Returns:** * **entropy_features** (*np.ndarray*) - 1D array of entropy-based features **Example:** :: from medtda.vectorizers import entropy_summary entropy_feats = entropy_summary(barcode) persistence_lifespan -------------------- .. autofunction:: medtda.vectorizers.persistence_lifespan Compute distribution of feature lifespans. **Signature:** .. code-block:: python def persistence_lifespan( barcode: np.ndarray, resolution: int = 100 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **resolution** (*int*) - Number of bins (default: 100) **Returns:** * **lifespan_dist** (*np.ndarray*) - 1D array of length ``resolution`` **Example:** :: from medtda.vectorizers import persistence_lifespan lifespan = persistence_lifespan(barcode) persistence_tropical_coordinates --------------------------------- .. autofunction:: medtda.vectorizers.persistence_tropical_coordinates Compute tropical coordinates representation. **Signature:** .. code-block:: python def persistence_tropical_coordinates( barcode: np.ndarray, r: int = 28 ) -> np.ndarray **Parameters:** * **barcode** (*np.ndarray*) - Barcode array * **r** (*int*) - Parameter for tropical coordinate computation (default: 28) **Returns:** * **coords** (*np.ndarray*) - 1D array of length 7 **Example:** :: from medtda.vectorizers import persistence_tropical_coordinates coords = persistence_tropical_coordinates(barcode, r=28) print(f"Coordinate vector size: {len(coords)}") # 7 Complete Examples ================= Example 1: Single Method ------------------------- :: from medtda import FeatureExtractor from medtda.vectorizers import persistence_image # Extract barcodes extractor = FeatureExtractor(return_barcodes=True) features, barcodes = extractor.execute('image.nii.gz') # Manually vectorize H1 barcode h1_barcode = barcodes['H1'] pi_features = persistence_image(h1_barcode, bandwidth=0.15, resolution=25) print(f"Persistence image size: {pi_features.shape}") Example 2: Multiple Methods ---------------------------- :: from medtda.vectorizers import ( persistence_stats, betti_curve, persistence_image ) import numpy as np # Get barcodes h1 = barcodes['H1'] # Apply multiple vectorizations stats = persistence_stats(h1) # returns dict of 38 features curve = betti_curve(h1, resolution=100) image = persistence_image(h1, resolution=20) # Concatenate for ML features = np.concatenate([ list(stats.values()), curve, image.flatten() ]) print(f"Combined feature vector size: {len(features)}") Example 3: Comparing Methods ----------------------------- :: from medtda.vectorizers import * import numpy as np methods = { 'stats': persistence_stats, 'betti': lambda b: betti_curve(b, resolution=100), 'pi': lambda b: persistence_image(b, resolution=20).flatten(), 'landscape': lambda b: persistence_landscape(b).flatten(), 'silhouette': lambda b: persistence_silhouette(b, resolution=100), 'entropy': lambda b: entropy_summary(b, resolution=100), 'lifespan': lambda b: persistence_lifespan(b, resolution=100), 'tropical': lambda b: persistence_tropical_coordinates(b, r=28) } for name, method in methods.items(): features = method(h1_barcode) print(f"{name:12s}: {len(features):4d} features") Example 4: Custom Parameters ----------------------------- :: from medtda.vectorizers import persistence_image, betti_curve # Experiment with different parameters # Coarse persistence image (fast) pi_coarse = persistence_image(barcode, resolution=15, bandwidth=0.3) # Fine persistence image (detailed) pi_fine = persistence_image(barcode, resolution=30, bandwidth=0.1) # Low-resolution Betti curve bc_low = betti_curve(barcode, resolution=50) # High-resolution Betti curve bc_high = betti_curve(barcode, resolution=200) Example 5: Multi-Dimensional Barcodes -------------------------------------- :: from medtda import BarcodeExtractor from medtda.vectorizers import persistence_image import numpy as np # Extract all dimensions extractor = BarcodeExtractor(max_dimension=2) barcodes = extractor.execute(image_3d) # Vectorize each dimension separately features_by_dim = {} for dim in [0, 1, 2]: if dim in barcodes and len(barcodes[dim]) > 0: features_by_dim[f'H{dim}'] = persistence_image( barcodes[dim], resolution=20 ).flatten() # Concatenate all dimensions all_features = np.concatenate([ features_by_dim['H0'], features_by_dim['H1'], features_by_dim['H2'] ]) print(f"Total feature vector size: {len(all_features)}") See Also ======== * :doc:`featureextractor` - Automatic vectorization * :doc:`barcodeextractor` - Extract barcodes * :doc:`../user_guide/vectorization` - Detailed vectorization guide * :doc:`../theory/vectorization_methods` - Mathematical background