gaitsetpy.features.physionet_features
PhysioNet VGRF Feature Extractor. Maintainer: @aharshit123456
This module contains feature extractors specific to the PhysioNet VGRF dataset, including Local Binary Pattern (LBP) and Fourier series analysis.
1''' 2PhysioNet VGRF Feature Extractor. 3Maintainer: @aharshit123456 4 5This module contains feature extractors specific to the PhysioNet VGRF dataset, 6including Local Binary Pattern (LBP) and Fourier series analysis. 7''' 8 9from typing import List, Dict, Any 10import numpy as np 11import pandas as pd 12from scipy.integrate import simpson 13from scipy.signal import find_peaks 14from scipy.optimize import curve_fit 15from scipy import fftpack 16import logging 17from tqdm import tqdm 18from ..core.base_classes import BaseFeatureExtractor 19 20# Set up logging 21logging.basicConfig(level=logging.INFO) 22logger = logging.getLogger(__name__) 23 24 25class LBPFeatureExtractor(BaseFeatureExtractor): 26 """ 27 Local Binary Pattern (LBP) feature extractor for VGRF data. 28 29 This extractor converts time-series data into LBP codes and extracts 30 histogram features from the LBP representation. 31 """ 32 33 def __init__(self, verbose: bool = True): 34 super().__init__( 35 name="lbp_features", 36 description="Local Binary Pattern feature extractor for VGRF time-series data" 37 ) 38 self.verbose = verbose 39 self.config = { 40 'radius': 2, # LBP radius (number of neighbors) 41 'n_bins': 256, # Number of histogram bins 42 'normalize': True # Normalize histogram 43 } 44 45 if self.verbose: 46 print("🔍 LBP Feature Extractor initialized!") 47 48 def lbp_1d(self, data: np.ndarray, radius: int = 2) -> str: 49 """ 50 Compute 1D Local Binary Pattern for time-series data. 51 52 Args: 53 data: Input time-series data 54 radius: Radius for LBP computation 55 56 Returns: 57 LBP code as binary string 58 """ 59 n = len(data) 60 lbp_code = '' 61 62 for i in range(n): 63 pattern = '' 64 for j in range(i - radius, i + radius + 1): 65 if j < 0 or j >= n: 66 pattern += '0' 67 elif data[j] >= data[i]: 68 pattern += '1' 69 else: 70 pattern += '0' 71 lbp_code += pattern 72 73 return lbp_code 74 75 def lbp_to_histogram(self, lbp_code: str, n_bins: int = 256, normalize: bool = True) -> np.ndarray: 76 """ 77 Convert LBP code to histogram features. 78 79 Args: 80 lbp_code: Binary LBP code string 81 n_bins: Number of histogram bins 82 normalize: Whether to normalize histogram 83 84 Returns: 85 Histogram features as numpy array 86 """ 87 # Convert LBP code to integer values 88 if len(lbp_code) == 0: 89 return np.zeros(n_bins) 90 91 # Process LBP code in chunks of 8 bits (or smaller) 92 chunk_size = 8 93 lbp_values = [] 94 95 for i in range(0, len(lbp_code), chunk_size): 96 chunk = lbp_code[i:i + chunk_size] 97 if len(chunk) > 0: 98 # Convert binary string to integer 99 try: 100 value = int(chunk, 2) 101 lbp_values.append(value % n_bins) # Ensure within bin range 102 except ValueError: 103 continue 104 105 if len(lbp_values) == 0: 106 return np.zeros(n_bins) 107 108 # Create histogram 109 hist, _ = np.histogram(lbp_values, bins=n_bins, range=(0, n_bins)) 110 111 if normalize and np.sum(hist) > 0: 112 hist = hist / np.sum(hist) 113 114 return hist 115 116 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 117 """ 118 Extract LBP features from sliding windows. 119 120 Args: 121 windows: List of sliding window dictionaries 122 fs: Sampling frequency (unused for LBP) 123 **kwargs: Additional arguments 124 125 Returns: 126 List of feature dictionaries 127 """ 128 # Update config with any passed arguments 129 radius = kwargs.get('radius', self.config['radius']) 130 n_bins = kwargs.get('n_bins', self.config['n_bins']) 131 normalize = kwargs.get('normalize', self.config['normalize']) 132 133 if self.verbose: 134 print(f"\n🔍 LBP Feature Extraction") 135 print(f"📊 Radius: {radius}, Bins: {n_bins}, Normalize: {normalize}") 136 137 features = [] 138 139 for window_dict in tqdm(windows, desc="Processing LBP features", disable=not self.verbose): 140 sensor_name = window_dict['name'] 141 window_data = window_dict['data'] 142 143 # Skip annotation windows 144 if sensor_name == 'annotations': 145 continue 146 147 sensor_features = {'name': sensor_name, 'features': {}} 148 149 # Extract LBP features for each window 150 lbp_histograms = [] 151 lbp_means = [] 152 lbp_stds = [] 153 154 for window in window_data: 155 # Ensure window is numpy array 156 if hasattr(window, 'values'): 157 window = window.values 158 159 # Compute LBP 160 lbp_code = self.lbp_1d(window, radius) 161 162 # Convert to histogram 163 hist = self.lbp_to_histogram(lbp_code, n_bins, normalize) 164 lbp_histograms.append(hist) 165 166 # Extract summary statistics 167 lbp_means.append(np.mean(hist)) 168 lbp_stds.append(np.std(hist)) 169 170 # Store features 171 sensor_features['features'] = { 172 'lbp_histograms': lbp_histograms, 173 'lbp_mean': lbp_means, 174 'lbp_std': lbp_stds, 175 'lbp_energy': [np.sum(hist**2) for hist in lbp_histograms], 176 'lbp_entropy': [self._calculate_entropy(hist) for hist in lbp_histograms] 177 } 178 179 features.append(sensor_features) 180 181 return features 182 183 def _calculate_entropy(self, hist: np.ndarray) -> float: 184 """Calculate entropy of histogram.""" 185 # Avoid log(0) by adding small value 186 hist = hist + 1e-10 187 return -np.sum(hist * np.log2(hist)) 188 189 def get_feature_names(self) -> List[str]: 190 """Get names of LBP features.""" 191 return [ 192 'lbp_histograms', 'lbp_mean', 'lbp_std', 193 'lbp_energy', 'lbp_entropy' 194 ] 195 196 197class FourierSeriesFeatureExtractor(BaseFeatureExtractor): 198 """ 199 Fourier Series feature extractor for VGRF data. 200 201 This extractor fits Fourier series to time-series data and extracts 202 coefficients and reconstruction features. 203 """ 204 205 def __init__(self, verbose: bool = True): 206 super().__init__( 207 name="fourier_features", 208 description="Fourier series feature extractor for VGRF time-series data" 209 ) 210 self.verbose = verbose 211 self.config = { 212 'n_terms': 10, # Number of Fourier terms 213 'period': 3.0, # Period for Fourier series 214 'extract_coefficients': True, 215 'extract_reconstruction_error': True 216 } 217 218 if self.verbose: 219 print("🌊 Fourier Series Feature Extractor initialized!") 220 221 def fit_fourier_series(self, signal: np.ndarray, time_points: np.ndarray, 222 period: float = 3.0, n_terms: int = 10) -> Dict[str, Any]: 223 """ 224 Fit Fourier series to signal. 225 226 Args: 227 signal: Input signal 228 time_points: Time points 229 period: Period of the Fourier series 230 n_terms: Number of Fourier terms 231 232 Returns: 233 Dictionary containing Fourier series parameters 234 """ 235 try: 236 # Calculate Fourier coefficients 237 L = period 238 239 # Calculate a0 (DC component) 240 a0 = 2/L * simpson(signal, time_points) 241 242 # Calculate an and bn coefficients 243 an = [] 244 bn = [] 245 246 for n in range(1, n_terms + 1): 247 # Calculate an coefficient 248 an_val = 2.0/L * simpson(signal * np.cos(2.*np.pi*n*time_points/L), time_points) 249 an.append(an_val) 250 251 # Calculate bn coefficient 252 bn_val = 2.0/L * simpson(signal * np.sin(2.*np.pi*n*time_points/L), time_points) 253 bn.append(bn_val) 254 255 # Reconstruct signal 256 reconstructed = np.full_like(time_points, a0/2) 257 for n in range(n_terms): 258 reconstructed += an[n] * np.cos(2.*np.pi*(n+1)*time_points/L) 259 reconstructed += bn[n] * np.sin(2.*np.pi*(n+1)*time_points/L) 260 261 # Calculate reconstruction error 262 reconstruction_error = np.mean((signal - reconstructed)**2) 263 264 return { 265 'a0': a0, 266 'an': an, 267 'bn': bn, 268 'reconstructed': reconstructed, 269 'reconstruction_error': reconstruction_error, 270 'fourier_energy': a0**2 + 2*np.sum(np.array(an)**2 + np.array(bn)**2) 271 } 272 273 except Exception as e: 274 if self.verbose: 275 print(f"Error in Fourier series fitting: {e}") 276 return { 277 'a0': 0, 278 'an': [0] * n_terms, 279 'bn': [0] * n_terms, 280 'reconstructed': np.zeros_like(time_points), 281 'reconstruction_error': float('inf'), 282 'fourier_energy': 0 283 } 284 285 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 286 """ 287 Extract Fourier series features from sliding windows. 288 289 Args: 290 windows: List of sliding window dictionaries 291 fs: Sampling frequency 292 **kwargs: Additional arguments 293 294 Returns: 295 List of feature dictionaries 296 """ 297 # Update config with any passed arguments 298 n_terms = kwargs.get('n_terms', self.config['n_terms']) 299 period = kwargs.get('period', self.config['period']) 300 301 if self.verbose: 302 print(f"\n🌊 Fourier Series Feature Extraction") 303 print(f"📊 Terms: {n_terms}, Period: {period}") 304 305 features = [] 306 307 for window_dict in tqdm(windows, desc="Processing Fourier features", disable=not self.verbose): 308 sensor_name = window_dict['name'] 309 window_data = window_dict['data'] 310 311 # Skip annotation windows 312 if sensor_name == 'annotations': 313 continue 314 315 sensor_features = {'name': sensor_name, 'features': {}} 316 317 # Extract Fourier features for each window 318 a0_values = [] 319 an_values = [] 320 bn_values = [] 321 reconstruction_errors = [] 322 fourier_energies = [] 323 324 for window in window_data: 325 # Ensure window is numpy array 326 if hasattr(window, 'values'): 327 window = window.values 328 329 # Create time points 330 time_points = np.linspace(0, period, len(window)) 331 332 # Fit Fourier series 333 fourier_result = self.fit_fourier_series(window, time_points, period, n_terms) 334 335 # Store results 336 a0_values.append(fourier_result['a0']) 337 an_values.append(fourier_result['an']) 338 bn_values.append(fourier_result['bn']) 339 reconstruction_errors.append(fourier_result['reconstruction_error']) 340 fourier_energies.append(fourier_result['fourier_energy']) 341 342 # Store features 343 sensor_features['features'] = { 344 'fourier_a0': a0_values, 345 'fourier_an': an_values, 346 'fourier_bn': bn_values, 347 'fourier_reconstruction_error': reconstruction_errors, 348 'fourier_energy': fourier_energies, 349 'fourier_an_mean': [np.mean(an) for an in an_values], 350 'fourier_bn_mean': [np.mean(bn) for bn in bn_values], 351 'fourier_an_std': [np.std(an) for an in an_values], 352 'fourier_bn_std': [np.std(bn) for bn in bn_values] 353 } 354 355 features.append(sensor_features) 356 357 return features 358 359 def get_feature_names(self) -> List[str]: 360 """Get names of Fourier series features.""" 361 return [ 362 'fourier_a0', 'fourier_an', 'fourier_bn', 363 'fourier_reconstruction_error', 'fourier_energy', 364 'fourier_an_mean', 'fourier_bn_mean', 365 'fourier_an_std', 'fourier_bn_std' 366 ] 367 368 369class PhysioNetFeatureExtractor(BaseFeatureExtractor): 370 """ 371 Combined feature extractor for PhysioNet VGRF data. 372 373 This extractor combines LBP and Fourier series features along with 374 basic statistical features specific to VGRF data. 375 """ 376 377 def __init__(self, verbose: bool = True): 378 super().__init__( 379 name="physionet_features", 380 description="Combined feature extractor for PhysioNet VGRF data including LBP and Fourier features" 381 ) 382 self.verbose = verbose 383 self.lbp_extractor = LBPFeatureExtractor(verbose=False) 384 self.fourier_extractor = FourierSeriesFeatureExtractor(verbose=False) 385 386 if self.verbose: 387 print("🚀 PhysioNet Feature Extractor initialized!") 388 389 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 390 """ 391 Extract combined features from sliding windows. 392 393 Args: 394 windows: List of sliding window dictionaries 395 fs: Sampling frequency 396 **kwargs: Additional arguments 397 398 Returns: 399 List of feature dictionaries 400 """ 401 # Extract features from each extractor 402 extract_lbp = kwargs.get('extract_lbp', True) 403 extract_fourier = kwargs.get('extract_fourier', True) 404 extract_statistical = kwargs.get('extract_statistical', True) 405 406 if self.verbose: 407 print(f"\n🔍 PhysioNet Feature Extraction") 408 print(f"📊 LBP: {extract_lbp}, Fourier: {extract_fourier}, Statistical: {extract_statistical}") 409 410 features = [] 411 412 # Extract LBP features 413 if extract_lbp: 414 lbp_features = self.lbp_extractor.extract_features(windows, fs, **kwargs) 415 else: 416 lbp_features = [] 417 418 # Extract Fourier features 419 if extract_fourier: 420 fourier_features = self.fourier_extractor.extract_features(windows, fs, **kwargs) 421 else: 422 fourier_features = [] 423 424 # Extract statistical features 425 if extract_statistical: 426 statistical_features = self._extract_statistical_features(windows) 427 else: 428 statistical_features = [] 429 430 # Combine features 431 for i, window_dict in enumerate(windows): 432 sensor_name = window_dict['name'] 433 434 # Skip annotation windows 435 if sensor_name == 'annotations': 436 continue 437 438 combined_features = {'name': sensor_name, 'features': {}} 439 440 # Add LBP features 441 if extract_lbp and i < len(lbp_features): 442 combined_features['features'].update(lbp_features[i]['features']) 443 444 # Add Fourier features 445 if extract_fourier and i < len(fourier_features): 446 combined_features['features'].update(fourier_features[i]['features']) 447 448 # Add statistical features 449 if extract_statistical and i < len(statistical_features): 450 combined_features['features'].update(statistical_features[i]['features']) 451 452 features.append(combined_features) 453 454 return features 455 456 def _extract_statistical_features(self, windows: List[Dict]) -> List[Dict]: 457 """Extract basic statistical features.""" 458 features = [] 459 460 for window_dict in windows: 461 sensor_name = window_dict['name'] 462 window_data = window_dict['data'] 463 464 # Skip annotation windows 465 if sensor_name == 'annotations': 466 continue 467 468 sensor_features = {'name': sensor_name, 'features': {}} 469 470 # Extract statistical features for each window 471 means = [] 472 stds = [] 473 maxs = [] 474 mins = [] 475 ranges = [] 476 477 for window in window_data: 478 # Ensure window is numpy array 479 if hasattr(window, 'values'): 480 window = window.values 481 482 means.append(np.mean(window)) 483 stds.append(np.std(window)) 484 maxs.append(np.max(window)) 485 mins.append(np.min(window)) 486 ranges.append(np.max(window) - np.min(window)) 487 488 # Store features 489 sensor_features['features'] = { 490 'vgrf_mean': means, 491 'vgrf_std': stds, 492 'vgrf_max': maxs, 493 'vgrf_min': mins, 494 'vgrf_range': ranges 495 } 496 497 features.append(sensor_features) 498 499 return features 500 501 def get_feature_names(self) -> List[str]: 502 """Get names of all features.""" 503 feature_names = [] 504 feature_names.extend(self.lbp_extractor.get_feature_names()) 505 feature_names.extend(self.fourier_extractor.get_feature_names()) 506 feature_names.extend(['vgrf_mean', 'vgrf_std', 'vgrf_max', 'vgrf_min', 'vgrf_range']) 507 return feature_names 508 509 510# Legacy functions for backward compatibility 511def extract_lbp_features(windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 512 """ 513 Legacy function to extract LBP features. 514 515 Args: 516 windows: List of sliding window dictionaries 517 fs: Sampling frequency 518 **kwargs: Additional arguments 519 520 Returns: 521 List of feature dictionaries 522 """ 523 extractor = LBPFeatureExtractor(verbose=kwargs.get('verbose', True)) 524 return extractor.extract_features(windows, fs, **kwargs) 525 526 527def extract_fourier_features(windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 528 """ 529 Legacy function to extract Fourier series features. 530 531 Args: 532 windows: List of sliding window dictionaries 533 fs: Sampling frequency 534 **kwargs: Additional arguments 535 536 Returns: 537 List of feature dictionaries 538 """ 539 extractor = FourierSeriesFeatureExtractor(verbose=kwargs.get('verbose', True)) 540 return extractor.extract_features(windows, fs, **kwargs) 541 542 543def extract_physionet_features(windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 544 """ 545 Legacy function to extract combined PhysioNet features. 546 547 Args: 548 windows: List of sliding window dictionaries 549 fs: Sampling frequency 550 **kwargs: Additional arguments 551 552 Returns: 553 List of feature dictionaries 554 """ 555 extractor = PhysioNetFeatureExtractor(verbose=kwargs.get('verbose', True)) 556 return extractor.extract_features(windows, fs, **kwargs)
26class LBPFeatureExtractor(BaseFeatureExtractor): 27 """ 28 Local Binary Pattern (LBP) feature extractor for VGRF data. 29 30 This extractor converts time-series data into LBP codes and extracts 31 histogram features from the LBP representation. 32 """ 33 34 def __init__(self, verbose: bool = True): 35 super().__init__( 36 name="lbp_features", 37 description="Local Binary Pattern feature extractor for VGRF time-series data" 38 ) 39 self.verbose = verbose 40 self.config = { 41 'radius': 2, # LBP radius (number of neighbors) 42 'n_bins': 256, # Number of histogram bins 43 'normalize': True # Normalize histogram 44 } 45 46 if self.verbose: 47 print("🔍 LBP Feature Extractor initialized!") 48 49 def lbp_1d(self, data: np.ndarray, radius: int = 2) -> str: 50 """ 51 Compute 1D Local Binary Pattern for time-series data. 52 53 Args: 54 data: Input time-series data 55 radius: Radius for LBP computation 56 57 Returns: 58 LBP code as binary string 59 """ 60 n = len(data) 61 lbp_code = '' 62 63 for i in range(n): 64 pattern = '' 65 for j in range(i - radius, i + radius + 1): 66 if j < 0 or j >= n: 67 pattern += '0' 68 elif data[j] >= data[i]: 69 pattern += '1' 70 else: 71 pattern += '0' 72 lbp_code += pattern 73 74 return lbp_code 75 76 def lbp_to_histogram(self, lbp_code: str, n_bins: int = 256, normalize: bool = True) -> np.ndarray: 77 """ 78 Convert LBP code to histogram features. 79 80 Args: 81 lbp_code: Binary LBP code string 82 n_bins: Number of histogram bins 83 normalize: Whether to normalize histogram 84 85 Returns: 86 Histogram features as numpy array 87 """ 88 # Convert LBP code to integer values 89 if len(lbp_code) == 0: 90 return np.zeros(n_bins) 91 92 # Process LBP code in chunks of 8 bits (or smaller) 93 chunk_size = 8 94 lbp_values = [] 95 96 for i in range(0, len(lbp_code), chunk_size): 97 chunk = lbp_code[i:i + chunk_size] 98 if len(chunk) > 0: 99 # Convert binary string to integer 100 try: 101 value = int(chunk, 2) 102 lbp_values.append(value % n_bins) # Ensure within bin range 103 except ValueError: 104 continue 105 106 if len(lbp_values) == 0: 107 return np.zeros(n_bins) 108 109 # Create histogram 110 hist, _ = np.histogram(lbp_values, bins=n_bins, range=(0, n_bins)) 111 112 if normalize and np.sum(hist) > 0: 113 hist = hist / np.sum(hist) 114 115 return hist 116 117 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 118 """ 119 Extract LBP features from sliding windows. 120 121 Args: 122 windows: List of sliding window dictionaries 123 fs: Sampling frequency (unused for LBP) 124 **kwargs: Additional arguments 125 126 Returns: 127 List of feature dictionaries 128 """ 129 # Update config with any passed arguments 130 radius = kwargs.get('radius', self.config['radius']) 131 n_bins = kwargs.get('n_bins', self.config['n_bins']) 132 normalize = kwargs.get('normalize', self.config['normalize']) 133 134 if self.verbose: 135 print(f"\n🔍 LBP Feature Extraction") 136 print(f"📊 Radius: {radius}, Bins: {n_bins}, Normalize: {normalize}") 137 138 features = [] 139 140 for window_dict in tqdm(windows, desc="Processing LBP features", disable=not self.verbose): 141 sensor_name = window_dict['name'] 142 window_data = window_dict['data'] 143 144 # Skip annotation windows 145 if sensor_name == 'annotations': 146 continue 147 148 sensor_features = {'name': sensor_name, 'features': {}} 149 150 # Extract LBP features for each window 151 lbp_histograms = [] 152 lbp_means = [] 153 lbp_stds = [] 154 155 for window in window_data: 156 # Ensure window is numpy array 157 if hasattr(window, 'values'): 158 window = window.values 159 160 # Compute LBP 161 lbp_code = self.lbp_1d(window, radius) 162 163 # Convert to histogram 164 hist = self.lbp_to_histogram(lbp_code, n_bins, normalize) 165 lbp_histograms.append(hist) 166 167 # Extract summary statistics 168 lbp_means.append(np.mean(hist)) 169 lbp_stds.append(np.std(hist)) 170 171 # Store features 172 sensor_features['features'] = { 173 'lbp_histograms': lbp_histograms, 174 'lbp_mean': lbp_means, 175 'lbp_std': lbp_stds, 176 'lbp_energy': [np.sum(hist**2) for hist in lbp_histograms], 177 'lbp_entropy': [self._calculate_entropy(hist) for hist in lbp_histograms] 178 } 179 180 features.append(sensor_features) 181 182 return features 183 184 def _calculate_entropy(self, hist: np.ndarray) -> float: 185 """Calculate entropy of histogram.""" 186 # Avoid log(0) by adding small value 187 hist = hist + 1e-10 188 return -np.sum(hist * np.log2(hist)) 189 190 def get_feature_names(self) -> List[str]: 191 """Get names of LBP features.""" 192 return [ 193 'lbp_histograms', 'lbp_mean', 'lbp_std', 194 'lbp_energy', 'lbp_entropy' 195 ]
Local Binary Pattern (LBP) feature extractor for VGRF data.
This extractor converts time-series data into LBP codes and extracts histogram features from the LBP representation.
34 def __init__(self, verbose: bool = True): 35 super().__init__( 36 name="lbp_features", 37 description="Local Binary Pattern feature extractor for VGRF time-series data" 38 ) 39 self.verbose = verbose 40 self.config = { 41 'radius': 2, # LBP radius (number of neighbors) 42 'n_bins': 256, # Number of histogram bins 43 'normalize': True # Normalize histogram 44 } 45 46 if self.verbose: 47 print("🔍 LBP Feature Extractor initialized!")
Initialize the feature extractor.
Args: name: Name of the feature extractor description: Description of the feature extractor
49 def lbp_1d(self, data: np.ndarray, radius: int = 2) -> str: 50 """ 51 Compute 1D Local Binary Pattern for time-series data. 52 53 Args: 54 data: Input time-series data 55 radius: Radius for LBP computation 56 57 Returns: 58 LBP code as binary string 59 """ 60 n = len(data) 61 lbp_code = '' 62 63 for i in range(n): 64 pattern = '' 65 for j in range(i - radius, i + radius + 1): 66 if j < 0 or j >= n: 67 pattern += '0' 68 elif data[j] >= data[i]: 69 pattern += '1' 70 else: 71 pattern += '0' 72 lbp_code += pattern 73 74 return lbp_code
Compute 1D Local Binary Pattern for time-series data.
Args: data: Input time-series data radius: Radius for LBP computation
Returns: LBP code as binary string
76 def lbp_to_histogram(self, lbp_code: str, n_bins: int = 256, normalize: bool = True) -> np.ndarray: 77 """ 78 Convert LBP code to histogram features. 79 80 Args: 81 lbp_code: Binary LBP code string 82 n_bins: Number of histogram bins 83 normalize: Whether to normalize histogram 84 85 Returns: 86 Histogram features as numpy array 87 """ 88 # Convert LBP code to integer values 89 if len(lbp_code) == 0: 90 return np.zeros(n_bins) 91 92 # Process LBP code in chunks of 8 bits (or smaller) 93 chunk_size = 8 94 lbp_values = [] 95 96 for i in range(0, len(lbp_code), chunk_size): 97 chunk = lbp_code[i:i + chunk_size] 98 if len(chunk) > 0: 99 # Convert binary string to integer 100 try: 101 value = int(chunk, 2) 102 lbp_values.append(value % n_bins) # Ensure within bin range 103 except ValueError: 104 continue 105 106 if len(lbp_values) == 0: 107 return np.zeros(n_bins) 108 109 # Create histogram 110 hist, _ = np.histogram(lbp_values, bins=n_bins, range=(0, n_bins)) 111 112 if normalize and np.sum(hist) > 0: 113 hist = hist / np.sum(hist) 114 115 return hist
Convert LBP code to histogram features.
Args: lbp_code: Binary LBP code string n_bins: Number of histogram bins normalize: Whether to normalize histogram
Returns: Histogram features as numpy array
117 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 118 """ 119 Extract LBP features from sliding windows. 120 121 Args: 122 windows: List of sliding window dictionaries 123 fs: Sampling frequency (unused for LBP) 124 **kwargs: Additional arguments 125 126 Returns: 127 List of feature dictionaries 128 """ 129 # Update config with any passed arguments 130 radius = kwargs.get('radius', self.config['radius']) 131 n_bins = kwargs.get('n_bins', self.config['n_bins']) 132 normalize = kwargs.get('normalize', self.config['normalize']) 133 134 if self.verbose: 135 print(f"\n🔍 LBP Feature Extraction") 136 print(f"📊 Radius: {radius}, Bins: {n_bins}, Normalize: {normalize}") 137 138 features = [] 139 140 for window_dict in tqdm(windows, desc="Processing LBP features", disable=not self.verbose): 141 sensor_name = window_dict['name'] 142 window_data = window_dict['data'] 143 144 # Skip annotation windows 145 if sensor_name == 'annotations': 146 continue 147 148 sensor_features = {'name': sensor_name, 'features': {}} 149 150 # Extract LBP features for each window 151 lbp_histograms = [] 152 lbp_means = [] 153 lbp_stds = [] 154 155 for window in window_data: 156 # Ensure window is numpy array 157 if hasattr(window, 'values'): 158 window = window.values 159 160 # Compute LBP 161 lbp_code = self.lbp_1d(window, radius) 162 163 # Convert to histogram 164 hist = self.lbp_to_histogram(lbp_code, n_bins, normalize) 165 lbp_histograms.append(hist) 166 167 # Extract summary statistics 168 lbp_means.append(np.mean(hist)) 169 lbp_stds.append(np.std(hist)) 170 171 # Store features 172 sensor_features['features'] = { 173 'lbp_histograms': lbp_histograms, 174 'lbp_mean': lbp_means, 175 'lbp_std': lbp_stds, 176 'lbp_energy': [np.sum(hist**2) for hist in lbp_histograms], 177 'lbp_entropy': [self._calculate_entropy(hist) for hist in lbp_histograms] 178 } 179 180 features.append(sensor_features) 181 182 return features
Extract LBP features from sliding windows.
Args: windows: List of sliding window dictionaries fs: Sampling frequency (unused for LBP) **kwargs: Additional arguments
Returns: List of feature dictionaries
190 def get_feature_names(self) -> List[str]: 191 """Get names of LBP features.""" 192 return [ 193 'lbp_histograms', 'lbp_mean', 'lbp_std', 194 'lbp_energy', 'lbp_entropy' 195 ]
Get names of LBP features.
Inherited Members
198class FourierSeriesFeatureExtractor(BaseFeatureExtractor): 199 """ 200 Fourier Series feature extractor for VGRF data. 201 202 This extractor fits Fourier series to time-series data and extracts 203 coefficients and reconstruction features. 204 """ 205 206 def __init__(self, verbose: bool = True): 207 super().__init__( 208 name="fourier_features", 209 description="Fourier series feature extractor for VGRF time-series data" 210 ) 211 self.verbose = verbose 212 self.config = { 213 'n_terms': 10, # Number of Fourier terms 214 'period': 3.0, # Period for Fourier series 215 'extract_coefficients': True, 216 'extract_reconstruction_error': True 217 } 218 219 if self.verbose: 220 print("🌊 Fourier Series Feature Extractor initialized!") 221 222 def fit_fourier_series(self, signal: np.ndarray, time_points: np.ndarray, 223 period: float = 3.0, n_terms: int = 10) -> Dict[str, Any]: 224 """ 225 Fit Fourier series to signal. 226 227 Args: 228 signal: Input signal 229 time_points: Time points 230 period: Period of the Fourier series 231 n_terms: Number of Fourier terms 232 233 Returns: 234 Dictionary containing Fourier series parameters 235 """ 236 try: 237 # Calculate Fourier coefficients 238 L = period 239 240 # Calculate a0 (DC component) 241 a0 = 2/L * simpson(signal, time_points) 242 243 # Calculate an and bn coefficients 244 an = [] 245 bn = [] 246 247 for n in range(1, n_terms + 1): 248 # Calculate an coefficient 249 an_val = 2.0/L * simpson(signal * np.cos(2.*np.pi*n*time_points/L), time_points) 250 an.append(an_val) 251 252 # Calculate bn coefficient 253 bn_val = 2.0/L * simpson(signal * np.sin(2.*np.pi*n*time_points/L), time_points) 254 bn.append(bn_val) 255 256 # Reconstruct signal 257 reconstructed = np.full_like(time_points, a0/2) 258 for n in range(n_terms): 259 reconstructed += an[n] * np.cos(2.*np.pi*(n+1)*time_points/L) 260 reconstructed += bn[n] * np.sin(2.*np.pi*(n+1)*time_points/L) 261 262 # Calculate reconstruction error 263 reconstruction_error = np.mean((signal - reconstructed)**2) 264 265 return { 266 'a0': a0, 267 'an': an, 268 'bn': bn, 269 'reconstructed': reconstructed, 270 'reconstruction_error': reconstruction_error, 271 'fourier_energy': a0**2 + 2*np.sum(np.array(an)**2 + np.array(bn)**2) 272 } 273 274 except Exception as e: 275 if self.verbose: 276 print(f"Error in Fourier series fitting: {e}") 277 return { 278 'a0': 0, 279 'an': [0] * n_terms, 280 'bn': [0] * n_terms, 281 'reconstructed': np.zeros_like(time_points), 282 'reconstruction_error': float('inf'), 283 'fourier_energy': 0 284 } 285 286 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 287 """ 288 Extract Fourier series features from sliding windows. 289 290 Args: 291 windows: List of sliding window dictionaries 292 fs: Sampling frequency 293 **kwargs: Additional arguments 294 295 Returns: 296 List of feature dictionaries 297 """ 298 # Update config with any passed arguments 299 n_terms = kwargs.get('n_terms', self.config['n_terms']) 300 period = kwargs.get('period', self.config['period']) 301 302 if self.verbose: 303 print(f"\n🌊 Fourier Series Feature Extraction") 304 print(f"📊 Terms: {n_terms}, Period: {period}") 305 306 features = [] 307 308 for window_dict in tqdm(windows, desc="Processing Fourier features", disable=not self.verbose): 309 sensor_name = window_dict['name'] 310 window_data = window_dict['data'] 311 312 # Skip annotation windows 313 if sensor_name == 'annotations': 314 continue 315 316 sensor_features = {'name': sensor_name, 'features': {}} 317 318 # Extract Fourier features for each window 319 a0_values = [] 320 an_values = [] 321 bn_values = [] 322 reconstruction_errors = [] 323 fourier_energies = [] 324 325 for window in window_data: 326 # Ensure window is numpy array 327 if hasattr(window, 'values'): 328 window = window.values 329 330 # Create time points 331 time_points = np.linspace(0, period, len(window)) 332 333 # Fit Fourier series 334 fourier_result = self.fit_fourier_series(window, time_points, period, n_terms) 335 336 # Store results 337 a0_values.append(fourier_result['a0']) 338 an_values.append(fourier_result['an']) 339 bn_values.append(fourier_result['bn']) 340 reconstruction_errors.append(fourier_result['reconstruction_error']) 341 fourier_energies.append(fourier_result['fourier_energy']) 342 343 # Store features 344 sensor_features['features'] = { 345 'fourier_a0': a0_values, 346 'fourier_an': an_values, 347 'fourier_bn': bn_values, 348 'fourier_reconstruction_error': reconstruction_errors, 349 'fourier_energy': fourier_energies, 350 'fourier_an_mean': [np.mean(an) for an in an_values], 351 'fourier_bn_mean': [np.mean(bn) for bn in bn_values], 352 'fourier_an_std': [np.std(an) for an in an_values], 353 'fourier_bn_std': [np.std(bn) for bn in bn_values] 354 } 355 356 features.append(sensor_features) 357 358 return features 359 360 def get_feature_names(self) -> List[str]: 361 """Get names of Fourier series features.""" 362 return [ 363 'fourier_a0', 'fourier_an', 'fourier_bn', 364 'fourier_reconstruction_error', 'fourier_energy', 365 'fourier_an_mean', 'fourier_bn_mean', 366 'fourier_an_std', 'fourier_bn_std' 367 ]
Fourier Series feature extractor for VGRF data.
This extractor fits Fourier series to time-series data and extracts coefficients and reconstruction features.
206 def __init__(self, verbose: bool = True): 207 super().__init__( 208 name="fourier_features", 209 description="Fourier series feature extractor for VGRF time-series data" 210 ) 211 self.verbose = verbose 212 self.config = { 213 'n_terms': 10, # Number of Fourier terms 214 'period': 3.0, # Period for Fourier series 215 'extract_coefficients': True, 216 'extract_reconstruction_error': True 217 } 218 219 if self.verbose: 220 print("🌊 Fourier Series Feature Extractor initialized!")
Initialize the feature extractor.
Args: name: Name of the feature extractor description: Description of the feature extractor
222 def fit_fourier_series(self, signal: np.ndarray, time_points: np.ndarray, 223 period: float = 3.0, n_terms: int = 10) -> Dict[str, Any]: 224 """ 225 Fit Fourier series to signal. 226 227 Args: 228 signal: Input signal 229 time_points: Time points 230 period: Period of the Fourier series 231 n_terms: Number of Fourier terms 232 233 Returns: 234 Dictionary containing Fourier series parameters 235 """ 236 try: 237 # Calculate Fourier coefficients 238 L = period 239 240 # Calculate a0 (DC component) 241 a0 = 2/L * simpson(signal, time_points) 242 243 # Calculate an and bn coefficients 244 an = [] 245 bn = [] 246 247 for n in range(1, n_terms + 1): 248 # Calculate an coefficient 249 an_val = 2.0/L * simpson(signal * np.cos(2.*np.pi*n*time_points/L), time_points) 250 an.append(an_val) 251 252 # Calculate bn coefficient 253 bn_val = 2.0/L * simpson(signal * np.sin(2.*np.pi*n*time_points/L), time_points) 254 bn.append(bn_val) 255 256 # Reconstruct signal 257 reconstructed = np.full_like(time_points, a0/2) 258 for n in range(n_terms): 259 reconstructed += an[n] * np.cos(2.*np.pi*(n+1)*time_points/L) 260 reconstructed += bn[n] * np.sin(2.*np.pi*(n+1)*time_points/L) 261 262 # Calculate reconstruction error 263 reconstruction_error = np.mean((signal - reconstructed)**2) 264 265 return { 266 'a0': a0, 267 'an': an, 268 'bn': bn, 269 'reconstructed': reconstructed, 270 'reconstruction_error': reconstruction_error, 271 'fourier_energy': a0**2 + 2*np.sum(np.array(an)**2 + np.array(bn)**2) 272 } 273 274 except Exception as e: 275 if self.verbose: 276 print(f"Error in Fourier series fitting: {e}") 277 return { 278 'a0': 0, 279 'an': [0] * n_terms, 280 'bn': [0] * n_terms, 281 'reconstructed': np.zeros_like(time_points), 282 'reconstruction_error': float('inf'), 283 'fourier_energy': 0 284 }
Fit Fourier series to signal.
Args: signal: Input signal time_points: Time points period: Period of the Fourier series n_terms: Number of Fourier terms
Returns: Dictionary containing Fourier series parameters
286 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 287 """ 288 Extract Fourier series features from sliding windows. 289 290 Args: 291 windows: List of sliding window dictionaries 292 fs: Sampling frequency 293 **kwargs: Additional arguments 294 295 Returns: 296 List of feature dictionaries 297 """ 298 # Update config with any passed arguments 299 n_terms = kwargs.get('n_terms', self.config['n_terms']) 300 period = kwargs.get('period', self.config['period']) 301 302 if self.verbose: 303 print(f"\n🌊 Fourier Series Feature Extraction") 304 print(f"📊 Terms: {n_terms}, Period: {period}") 305 306 features = [] 307 308 for window_dict in tqdm(windows, desc="Processing Fourier features", disable=not self.verbose): 309 sensor_name = window_dict['name'] 310 window_data = window_dict['data'] 311 312 # Skip annotation windows 313 if sensor_name == 'annotations': 314 continue 315 316 sensor_features = {'name': sensor_name, 'features': {}} 317 318 # Extract Fourier features for each window 319 a0_values = [] 320 an_values = [] 321 bn_values = [] 322 reconstruction_errors = [] 323 fourier_energies = [] 324 325 for window in window_data: 326 # Ensure window is numpy array 327 if hasattr(window, 'values'): 328 window = window.values 329 330 # Create time points 331 time_points = np.linspace(0, period, len(window)) 332 333 # Fit Fourier series 334 fourier_result = self.fit_fourier_series(window, time_points, period, n_terms) 335 336 # Store results 337 a0_values.append(fourier_result['a0']) 338 an_values.append(fourier_result['an']) 339 bn_values.append(fourier_result['bn']) 340 reconstruction_errors.append(fourier_result['reconstruction_error']) 341 fourier_energies.append(fourier_result['fourier_energy']) 342 343 # Store features 344 sensor_features['features'] = { 345 'fourier_a0': a0_values, 346 'fourier_an': an_values, 347 'fourier_bn': bn_values, 348 'fourier_reconstruction_error': reconstruction_errors, 349 'fourier_energy': fourier_energies, 350 'fourier_an_mean': [np.mean(an) for an in an_values], 351 'fourier_bn_mean': [np.mean(bn) for bn in bn_values], 352 'fourier_an_std': [np.std(an) for an in an_values], 353 'fourier_bn_std': [np.std(bn) for bn in bn_values] 354 } 355 356 features.append(sensor_features) 357 358 return features
Extract Fourier series features from sliding windows.
Args: windows: List of sliding window dictionaries fs: Sampling frequency **kwargs: Additional arguments
Returns: List of feature dictionaries
360 def get_feature_names(self) -> List[str]: 361 """Get names of Fourier series features.""" 362 return [ 363 'fourier_a0', 'fourier_an', 'fourier_bn', 364 'fourier_reconstruction_error', 'fourier_energy', 365 'fourier_an_mean', 'fourier_bn_mean', 366 'fourier_an_std', 'fourier_bn_std' 367 ]
Get names of Fourier series features.
Inherited Members
370class PhysioNetFeatureExtractor(BaseFeatureExtractor): 371 """ 372 Combined feature extractor for PhysioNet VGRF data. 373 374 This extractor combines LBP and Fourier series features along with 375 basic statistical features specific to VGRF data. 376 """ 377 378 def __init__(self, verbose: bool = True): 379 super().__init__( 380 name="physionet_features", 381 description="Combined feature extractor for PhysioNet VGRF data including LBP and Fourier features" 382 ) 383 self.verbose = verbose 384 self.lbp_extractor = LBPFeatureExtractor(verbose=False) 385 self.fourier_extractor = FourierSeriesFeatureExtractor(verbose=False) 386 387 if self.verbose: 388 print("🚀 PhysioNet Feature Extractor initialized!") 389 390 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 391 """ 392 Extract combined features from sliding windows. 393 394 Args: 395 windows: List of sliding window dictionaries 396 fs: Sampling frequency 397 **kwargs: Additional arguments 398 399 Returns: 400 List of feature dictionaries 401 """ 402 # Extract features from each extractor 403 extract_lbp = kwargs.get('extract_lbp', True) 404 extract_fourier = kwargs.get('extract_fourier', True) 405 extract_statistical = kwargs.get('extract_statistical', True) 406 407 if self.verbose: 408 print(f"\n🔍 PhysioNet Feature Extraction") 409 print(f"📊 LBP: {extract_lbp}, Fourier: {extract_fourier}, Statistical: {extract_statistical}") 410 411 features = [] 412 413 # Extract LBP features 414 if extract_lbp: 415 lbp_features = self.lbp_extractor.extract_features(windows, fs, **kwargs) 416 else: 417 lbp_features = [] 418 419 # Extract Fourier features 420 if extract_fourier: 421 fourier_features = self.fourier_extractor.extract_features(windows, fs, **kwargs) 422 else: 423 fourier_features = [] 424 425 # Extract statistical features 426 if extract_statistical: 427 statistical_features = self._extract_statistical_features(windows) 428 else: 429 statistical_features = [] 430 431 # Combine features 432 for i, window_dict in enumerate(windows): 433 sensor_name = window_dict['name'] 434 435 # Skip annotation windows 436 if sensor_name == 'annotations': 437 continue 438 439 combined_features = {'name': sensor_name, 'features': {}} 440 441 # Add LBP features 442 if extract_lbp and i < len(lbp_features): 443 combined_features['features'].update(lbp_features[i]['features']) 444 445 # Add Fourier features 446 if extract_fourier and i < len(fourier_features): 447 combined_features['features'].update(fourier_features[i]['features']) 448 449 # Add statistical features 450 if extract_statistical and i < len(statistical_features): 451 combined_features['features'].update(statistical_features[i]['features']) 452 453 features.append(combined_features) 454 455 return features 456 457 def _extract_statistical_features(self, windows: List[Dict]) -> List[Dict]: 458 """Extract basic statistical features.""" 459 features = [] 460 461 for window_dict in windows: 462 sensor_name = window_dict['name'] 463 window_data = window_dict['data'] 464 465 # Skip annotation windows 466 if sensor_name == 'annotations': 467 continue 468 469 sensor_features = {'name': sensor_name, 'features': {}} 470 471 # Extract statistical features for each window 472 means = [] 473 stds = [] 474 maxs = [] 475 mins = [] 476 ranges = [] 477 478 for window in window_data: 479 # Ensure window is numpy array 480 if hasattr(window, 'values'): 481 window = window.values 482 483 means.append(np.mean(window)) 484 stds.append(np.std(window)) 485 maxs.append(np.max(window)) 486 mins.append(np.min(window)) 487 ranges.append(np.max(window) - np.min(window)) 488 489 # Store features 490 sensor_features['features'] = { 491 'vgrf_mean': means, 492 'vgrf_std': stds, 493 'vgrf_max': maxs, 494 'vgrf_min': mins, 495 'vgrf_range': ranges 496 } 497 498 features.append(sensor_features) 499 500 return features 501 502 def get_feature_names(self) -> List[str]: 503 """Get names of all features.""" 504 feature_names = [] 505 feature_names.extend(self.lbp_extractor.get_feature_names()) 506 feature_names.extend(self.fourier_extractor.get_feature_names()) 507 feature_names.extend(['vgrf_mean', 'vgrf_std', 'vgrf_max', 'vgrf_min', 'vgrf_range']) 508 return feature_names
Combined feature extractor for PhysioNet VGRF data.
This extractor combines LBP and Fourier series features along with basic statistical features specific to VGRF data.
378 def __init__(self, verbose: bool = True): 379 super().__init__( 380 name="physionet_features", 381 description="Combined feature extractor for PhysioNet VGRF data including LBP and Fourier features" 382 ) 383 self.verbose = verbose 384 self.lbp_extractor = LBPFeatureExtractor(verbose=False) 385 self.fourier_extractor = FourierSeriesFeatureExtractor(verbose=False) 386 387 if self.verbose: 388 print("🚀 PhysioNet Feature Extractor initialized!")
Initialize the feature extractor.
Args: name: Name of the feature extractor description: Description of the feature extractor
390 def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 391 """ 392 Extract combined features from sliding windows. 393 394 Args: 395 windows: List of sliding window dictionaries 396 fs: Sampling frequency 397 **kwargs: Additional arguments 398 399 Returns: 400 List of feature dictionaries 401 """ 402 # Extract features from each extractor 403 extract_lbp = kwargs.get('extract_lbp', True) 404 extract_fourier = kwargs.get('extract_fourier', True) 405 extract_statistical = kwargs.get('extract_statistical', True) 406 407 if self.verbose: 408 print(f"\n🔍 PhysioNet Feature Extraction") 409 print(f"📊 LBP: {extract_lbp}, Fourier: {extract_fourier}, Statistical: {extract_statistical}") 410 411 features = [] 412 413 # Extract LBP features 414 if extract_lbp: 415 lbp_features = self.lbp_extractor.extract_features(windows, fs, **kwargs) 416 else: 417 lbp_features = [] 418 419 # Extract Fourier features 420 if extract_fourier: 421 fourier_features = self.fourier_extractor.extract_features(windows, fs, **kwargs) 422 else: 423 fourier_features = [] 424 425 # Extract statistical features 426 if extract_statistical: 427 statistical_features = self._extract_statistical_features(windows) 428 else: 429 statistical_features = [] 430 431 # Combine features 432 for i, window_dict in enumerate(windows): 433 sensor_name = window_dict['name'] 434 435 # Skip annotation windows 436 if sensor_name == 'annotations': 437 continue 438 439 combined_features = {'name': sensor_name, 'features': {}} 440 441 # Add LBP features 442 if extract_lbp and i < len(lbp_features): 443 combined_features['features'].update(lbp_features[i]['features']) 444 445 # Add Fourier features 446 if extract_fourier and i < len(fourier_features): 447 combined_features['features'].update(fourier_features[i]['features']) 448 449 # Add statistical features 450 if extract_statistical and i < len(statistical_features): 451 combined_features['features'].update(statistical_features[i]['features']) 452 453 features.append(combined_features) 454 455 return features
Extract combined features from sliding windows.
Args: windows: List of sliding window dictionaries fs: Sampling frequency **kwargs: Additional arguments
Returns: List of feature dictionaries
502 def get_feature_names(self) -> List[str]: 503 """Get names of all features.""" 504 feature_names = [] 505 feature_names.extend(self.lbp_extractor.get_feature_names()) 506 feature_names.extend(self.fourier_extractor.get_feature_names()) 507 feature_names.extend(['vgrf_mean', 'vgrf_std', 'vgrf_max', 'vgrf_min', 'vgrf_range']) 508 return feature_names
Get names of all features.
Inherited Members
512def extract_lbp_features(windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 513 """ 514 Legacy function to extract LBP features. 515 516 Args: 517 windows: List of sliding window dictionaries 518 fs: Sampling frequency 519 **kwargs: Additional arguments 520 521 Returns: 522 List of feature dictionaries 523 """ 524 extractor = LBPFeatureExtractor(verbose=kwargs.get('verbose', True)) 525 return extractor.extract_features(windows, fs, **kwargs)
Legacy function to extract LBP features.
Args: windows: List of sliding window dictionaries fs: Sampling frequency **kwargs: Additional arguments
Returns: List of feature dictionaries
528def extract_fourier_features(windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 529 """ 530 Legacy function to extract Fourier series features. 531 532 Args: 533 windows: List of sliding window dictionaries 534 fs: Sampling frequency 535 **kwargs: Additional arguments 536 537 Returns: 538 List of feature dictionaries 539 """ 540 extractor = FourierSeriesFeatureExtractor(verbose=kwargs.get('verbose', True)) 541 return extractor.extract_features(windows, fs, **kwargs)
Legacy function to extract Fourier series features.
Args: windows: List of sliding window dictionaries fs: Sampling frequency **kwargs: Additional arguments
Returns: List of feature dictionaries
544def extract_physionet_features(windows: List[Dict], fs: int, **kwargs) -> List[Dict]: 545 """ 546 Legacy function to extract combined PhysioNet features. 547 548 Args: 549 windows: List of sliding window dictionaries 550 fs: Sampling frequency 551 **kwargs: Additional arguments 552 553 Returns: 554 List of feature dictionaries 555 """ 556 extractor = PhysioNetFeatureExtractor(verbose=kwargs.get('verbose', True)) 557 return extractor.extract_features(windows, fs, **kwargs)
Legacy function to extract combined PhysioNet features.
Args: windows: List of sliding window dictionaries fs: Sampling frequency **kwargs: Additional arguments
Returns: List of feature dictionaries