Comprehensive signal feature extraction with decomposition, batch processing, and sklearn integration
Project description
SigFeatX
A comprehensive Python library for extracting statistical features from 1D signals using advanced decomposition techniques and signal processing metrics.
Features
Signal Preprocessing
- Denoising: Wavelet, median filter, lowpass, bandpass, notch
- Normalization: Z-score, min-max, robust (MAD-based)
- Detrending: Linear, constant, and ALS baseline detrending
- Resampling: Linear and Fourier-based resampling
Workflow Utilities
- Batch Extraction: Feature tables for multiple signals with optional parallelism
- Sliding-Window Extraction: Per-window features with sample/time metadata
- Multi-Channel Extraction: Channel-prefixed features plus coherence, PLV, and cross-correlation
Decomposition Methods
- Fourier Transform (FT): Classical frequency domain decomposition
- Short-Time Fourier Transform (STFT): Time-frequency analysis
- Discrete Wavelet Transform (DWT): Multi-resolution analysis
- Wavelet Packet Decomposition (WPD): Full wavelet tree decomposition
- Empirical Mode Decomposition (EMD): Data-driven decomposition
- Variational Mode Decomposition (VMD): Optimization-based decomposition
- Successive VMD (SVMD): Sequential mode extraction
- Empirical Fourier Decomposition (EFD): Adaptive frequency bands
Statistical Features (100+)
Time Domain
- Basic: Mean, Std, Variance, Median, Mode, Min, Max, Range
- Energy: RMS, Energy, Power, Mean Absolute Value
- Shape: Crest Factor, Shape Factor, Impulse Factor, Clearance Factor
- Distribution: Skewness, Kurtosis, Percentiles, IQR
- Signal Characteristics: Zero Crossings, Peak-to-Peak
Frequency Domain
- Spectral: Centroid, Bandwidth, Rolloff, Flatness, Flux
- Energy Distribution: Energy in frequency bands (very low, low, medium, high, very high)
- Statistical: Spectral Entropy, Skewness, Kurtosis
- Dominant Frequency and Maximum Magnitude
Entropy Measures
- Shannon Entropy
- Sample Entropy
- Permutation Entropy
- Approximate Entropy
- Spectral Entropy
Nonlinear Dynamics
- Hjorth Parameters: Activity, Mobility, Complexity
- Fractal Dimensions: Higuchi, Petrosian
- Hurst Exponent (R/S analysis)
- Lyapunov Exponent
- Detrended Fluctuation Analysis (DFA)
Decomposition-Based Features
- Energy per level/component
- RMS per level
- Entropy per level
- Correlations between components
- Energy ratios between components
- Relative entropy (KL divergence) between components
Installation
pip install SigFeatX
Optional extras pull in heavier, feature-specific dependencies:
pip install "SigFeatX[sklearn]" # scikit-learn transformer
pip install "SigFeatX[all]" # sklearn + tqdm + parquet + hdf5 + viz
Or install from source for development:
git clone https://github.com/diptiman-mohanta/SigFeatX.git
cd SigFeatX
pip install -e ".[dev,all]"
Requirements
numpy>=1.24.0
scipy>=1.10.0
PyWavelets>=1.4.0
pandas>=1.5.0
Quick Start
import numpy as np
from SigFeatX import FeatureAggregator
# Generate sample signal
t = np.linspace(0, 1, 1000)
signal = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 10 * t)
# Initialize feature extractor
extractor = FeatureAggregator(fs=1000)
# Extract features
features = extractor.extract_all_features(
signal,
decomposition_methods=['fourier', 'dwt', 'emd'],
preprocess_signal=True,
denoise=True,
normalize=True,
detrend=True
)
print(f"Extracted {len(features)} features")
print(f"Mean: {features['raw_mean']:.4f}")
print(f"RMS: {features['raw_rms']:.4f}")
print(f"Dominant Frequency: {features['raw_dominant_frequency']:.2f} Hz")
Usage Examples
Basic Feature Extraction
from SigFeatX import FeatureAggregator, SignalIO
# Load signal
io = SignalIO()
signal = io.load_signal('signal.npy')
# Extract features
extractor = FeatureAggregator(fs=1000)
features = extractor.extract_all_features(signal)
# Save features
io.save_features(features, 'features.json')
Custom Preprocessing
from SigFeatX.preprocess import SignalPreprocessor
preprocessor = SignalPreprocessor()
# Denoise with wavelet
clean_signal = preprocessor.denoise(signal, method='wavelet',
wavelet='db6', level=3)
# Normalize
normalized = preprocessor.normalize(clean_signal, method='robust')
# Detrend
detrended = preprocessor.detrend(normalized, method='linear')
Individual Decomposition Methods
from SigFeatX.decompose import WaveletDecomposer, EMD, VMD
# Wavelet decomposition
wavelet = WaveletDecomposer(wavelet='db4')
coeffs = wavelet.dwt(signal, level=4)
# EMD
emd = EMD(max_imf=10)
imfs = emd.decompose(signal)
# VMD
vmd = VMD(K=5, alpha=2000)
modes = vmd.decompose(signal)
Specific Feature Categories
from SigFeatX.features.features import (
TimeDomainFeatures,
FrequencyDomainFeatures,
EntropyFeatures,
NonlinearFeatures
)
# Extract specific feature categories
time_features = TimeDomainFeatures.extract(signal)
freq_features = FrequencyDomainFeatures.extract(signal, fs=1000)
entropy_features = EntropyFeatures.extract(signal)
nonlinear_features = NonlinearFeatures.extract(signal)
Batch Processing
signals = [signal1, signal2, signal3]
result = extractor.extract_batch(
signals,
decomposition_methods=['fourier', 'dwt'],
preprocess_signal=False,
n_jobs=2,
)
df = result.dataframe
df.to_csv('features.csv', index=False)
Sliding-Window Processing
windowed = extractor.extract_windowed(
signal,
window_size=256,
step_size=128,
decomposition_methods=['fourier'],
preprocess_signal=False,
)
# Includes window_idx, start_sample, end_sample, start_time_s, end_time_s
window_df = windowed.dataframe
Multi-Channel Processing
multichannel = np.vstack([signal_ch1, signal_ch2, signal_ch3])
features = extractor.extract_multichannel(
multichannel,
channel_names=['Fz', 'Cz', 'Pz'],
decomposition_methods=['fourier'],
include_cross=True,
)
Using Utility Functions
from SigFeatX.utils import SignalUtils
# Create sliding windows
windows = SignalUtils.sliding_window(signal, window_size=256, step_size=128)
# Segment signal
segments = SignalUtils.segment_signal(signal, n_segments=5)
# Detect peaks
peaks, properties = SignalUtils.detect_peaks(signal, height=0.5)
# Compute envelope
envelope = SignalUtils.compute_envelope(signal)
# Add noise
noisy_signal = SignalUtils.add_noise(signal, snr_db=10)
API Reference
FeatureAggregator
Main class for feature extraction pipeline.
FeatureAggregator(fs=1.0)
Parameters:
fs: Sampling frequency (default: 1.0)
Methods:
extract_all_features(signal, decomposition_methods=None, preprocess_signal=True, extract_raw=True, **preprocess_kwargs)
Extract all features from signal.
Parameters:
signal: Input 1D numpy arraydecomposition_methods: List of decomposition methods to apply- Options:
['fourier', 'stft', 'dwt', 'wpd', 'emd', 'vmd', 'svmd', 'efd']
- Options:
preprocess_signal: Whether to preprocess signal (default: True)extract_raw: Extract features from raw signal (default: True)**preprocess_kwargs: Preprocessing parametersdenoise: Apply denoising (default: True)normalize: Apply normalization (default: True)detrend: Apply detrending (default: True)denoise_method: Denoising method ('wavelet', 'median', 'lowpass', 'bandpass', 'notch')normalize_method: Normalization method ('zscore', 'minmax', 'robust')detrend_method: Detrending method ('linear', 'constant', 'als')detrend_params: Extra ALS parameters such aslam,p, andn_iter
Returns:
- Dictionary of feature names and values
extract_batch(signals, ..., n_jobs=1, on_error='warn')
Extract features for a list or 2D array of signals and return a BatchResult
containing a pandas DataFrame plus success/error metadata.
extract_windowed(signal, window_size, step_size, ...)
Run the normal extraction pipeline over sliding windows and return a
BatchResult with per-window metadata columns.
extract_multichannel(signals_2d, channel_names=None, include_cross=True, ...)
Extract per-channel features from a (n_channels, n_samples) array and,
optionally, pairwise coherence, cross-correlation, and PLV summaries.
SignalPreprocessor
Preprocessing operations for signals.
SignalPreprocessor()
Methods:
denoise(sig, method='wavelet', **kwargs)
Denoise signal using various methods.
normalize(sig, method='zscore')
Normalize signal.
detrend(sig, method='linear', **kwargs)
Remove trend from signal. For method='als', pass lam, p, and n_iter
through **kwargs.
resample(sig, target_length, method='linear')
Resample signal to target length.
Decomposition Classes
FourierTransform
FourierTransform(fs=1.0)
transform(signal): Compute FFTget_power_spectrum(signal): Get power spectrumget_phase_spectrum(signal): Get phase spectrum
WaveletDecomposer
WaveletDecomposer(wavelet='db4')
dwt(signal, level=None): Discrete Wavelet Transformwpd(signal, level=3): Wavelet Packet Decompositioncwt(signal, scales=None): Continuous Wavelet Transform- If the configured wavelet is discrete-only (for example
db4), CWT falls back tomorl
- If the configured wavelet is discrete-only (for example
swt(signal, level=1): Stationary Wavelet Transform
EMD
EMD(max_imf=10, max_iter=100)
decompose(signal): Decompose into IMFsreconstruct(imfs): Reconstruct signal from IMFs
VMD
VMD(alpha=2000, K=3, tau=0.0, DC=False, init=1, tol=1e-7, max_iter=500)
decompose(signal): Decompose into modesreconstruct(modes): Reconstruct signal from modes
SVMD
SVMD(alpha=2000, K_max=10, tol=1e-7, max_iter=500)
decompose(signal): Successive decomposition
EFD
EFD(n_modes=5)
decompose(signal): Empirical Fourier decomposition
Feature Extraction Classes
TimeDomainFeatures
TimeDomainFeatures.extract(signal)
Returns dictionary with 25+ time domain features.
FrequencyDomainFeatures
FrequencyDomainFeatures.extract(signal, fs=1.0)
Returns dictionary with 20+ frequency domain features.
EntropyFeatures
EntropyFeatures.extract(signal)
Returns dictionary with 4 entropy measures.
NonlinearFeatures
NonlinearFeatures.extract(signal)
Returns dictionary with 9+ nonlinear features.
DecompositionFeatures
DecompositionFeatures.extract_from_components(components, prefix='comp')
Extract features from decomposition components.
SignalIO
Handle signal data I/O operations.
SignalIO()
Methods:
load_signal(filepath, file_format='auto'): Load signal from filesave_signal(signal, filepath, file_format='auto'): Save signal to filesave_features(features, filepath, file_format='auto'): Save featuresload_features(filepath, file_format='auto'): Load features
SignalUtils
Utility functions for signal processing.
SignalUtils()
Static Methods:
sliding_window(sig, window_size, step_size): Create sliding windowspad_signal(sig, target_length, mode='constant'): Pad signalsegment_signal(sig, n_segments): Segment signalcompute_snr(sig, noise): Compute SNRdetect_peaks(sig, height=None, distance=None): Detect peakscompute_envelope(sig): Compute signal envelopecompute_instantaneous_frequency(sig, fs=1.0): Compute inst. frequencyremove_outliers(sig, n_std=3.0): Remove outliersadd_noise(sig, snr_db, noise_type='gaussian'): Add noise
Feature List
Time Domain (25 features)
- mean, std, variance, median, mode
- max, min, range, peak_to_peak
- skewness, kurtosis
- rms, energy, power
- mean_absolute, sum_absolute
- zero_crossings, zero_crossing_rate
- crest_factor, shape_factor, impulse_factor, clearance_factor
- q25, q75, iqr, coeff_variation
Frequency Domain (20+ features)
- spectral_centroid, spectral_spread, spectral_bandwidth
- spectral_rolloff, dominant_frequency, max_magnitude
- spectral_flatness, spectral_entropy, spectral_flux
- spectral_kurtosis, spectral_skewness
- energy_very_low, energy_low, energy_medium, energy_high, energy_very_high
- energy_ratio_very_low, energy_ratio_low, energy_ratio_medium, energy_ratio_high, energy_ratio_very_high
Entropy Features (4 features)
- shannon_entropy
- sample_entropy
- permutation_entropy
- approximate_entropy
Nonlinear Features (9 features)
- hjorth_activity, hjorth_mobility, hjorth_complexity
- higuchi_fractal_dimension, petrosian_fractal_dimension
- hurst_exponent
- lyapunov_exponent
- dfa_alpha
Decomposition Features (per component)
- energy, rms, mean, std, max, entropy
- energy_ratio
- correlations between components
- energy ratios between components
- kl_divergence between components
Choosing Methods
Which Decomposition Should I Use?
- Use
fourierwhen the signal is roughly stationary and you mainly care about dominant frequencies, spectral spread, or band energy. - Use
stftwhen frequencies change over time and you need a compact time-frequency summary without the full cost of adaptive methods. - Use
dwtwhen you want a fast, robust default for denoising or multiscale structure. It is usually the best first choice for production pipelines. - Use
wpdwhen you want a denser wavelet tree than DWT and are willing to trade speed and simplicity for extra sub-band detail. - Use
emdwhen the signal is nonlinear or non-stationary and you want data-driven intrinsic mode functions instead of fixed basis functions. - Use
vmdwhen you want cleaner, more stable band-limited modes than EMD and can afford tuningKandalpha. - Use
svmdwhen you want VMD-like behavior but prefer sequential mode discovery over specifying a fixed mode count up front. - Use
efdwhen you want adaptive frequency-band decomposition with explicit frequency segmentation behavior.
Preprocessing Defaults
- Use
detrend_method='linear',denoise_method='wavelet', andnormalize_method='zscore'as general-purpose defaults. - Use
detrend_method='als'when the signal has a curved baseline or slow drift under mostly positive peaks, such as spectroscopy or biomedical traces. - Use
denoise_method='bandpass'when you know the band of interest ahead of time. - Use
denoise_method='notch'to remove narrow interference such as 50/60 Hz line noise. - Use
normalize_method='robust'when spikes or outliers make z-score scaling unstable.
Practical Heuristics
- Start with raw features plus
fourieranddwtif you want a fast, stable baseline. - Add
stft,emd, orvmdonly when the problem really depends on non-stationary structure. - Prefer
extract_windowed(...)when labels or events vary over time inside a long recording. - Prefer
extract_multichannel(...)when relationships between channels matter, since it adds coherence, cross-correlation, and PLV summaries.
Advanced Topics
Custom Wavelet Selection
# Available wavelets: db1-db20, sym2-sym20, coif1-coif17, bior, rbio, dmey
wavelet = WaveletDecomposer(wavelet='sym8')
coeffs = wavelet.dwt(signal, level=5)
Optimizing VMD Parameters
# For signals with known number of modes
vmd = VMD(K=3, alpha=2000) # K = number of modes
# For noisy signals, increase alpha
vmd = VMD(K=3, alpha=5000)
# For signals with closely spaced frequencies
vmd = VMD(K=3, alpha=1000, init=2) # Random initialization
Memory-Efficient Batch Processing
def extract_features_generator(signals, extractor):
for sig in signals:
yield extractor.extract_all_features(sig)
# Process large datasets
features_gen = extract_features_generator(large_signal_list, extractor)
for i, features in enumerate(features_gen):
# Process or save features incrementally
io.save_features(features, f'features_{i}.json')
Parallel Processing
from multiprocessing import Pool
def extract_wrapper(sig):
extractor = FeatureAggregator(fs=1000)
return extractor.extract_all_features(sig)
# Process signals in parallel
with Pool(processes=4) as pool:
all_features = pool.map(extract_wrapper, signals)
Performance Considerations
- Signal Length: Most methods work efficiently for signals up to 10,000 samples
- Decomposition Methods: EMD and VMD are computationally expensive; use DWT for faster processing
- Feature Count: Extracting all features with all decomposition methods can yield 200+ features
- Memory: VMD and SVMD require more memory for long signals
- MODWT: uses an FFT-based pyramid algorithm (not a direct loop), so it scales well even at long signal lengths and many decomposition levels.
- CEEMDAN: pass
n_jobs=-1to parallelize the (embarrassingly parallel) trial ensemble across CPU cores; output is identical ton_jobs=1for the samerngseed.
Documentation
The docs/ directory has a Sphinx setup (quickstart + full API reference).
Build it locally with:
pip install -e ".[docs]"
sphinx-build -b html docs docs/_build/html
# open docs/_build/html/index.html
For a live, runnable tour instead, see
examples/playground.ipynb: one synthetic
signal, decomposed and perfectly reconstructed by every decomposition
method in the library side by side (with the reconstruction error printed,
not just claimed), every feature family run on it, and a mini experiment
checking that well-known features (Hurst exponent, DFA) land where
signal-processing theory says they should.
Benchmarking
Run the local benchmark script to compare common extraction workflows on your machine:
python benchmarks/benchmark_feature_extraction.py
Useful options:
--repeats 10for a more stable timing estimate--include-slowto include an EMD benchmark--jsonto emit machine-readable benchmark output
The script reports median/mean/best runtime, standard deviation, peak traced memory, and any runtime notes such as thread fallback when process-based parallelism is unavailable.
Troubleshooting
Common Issues
Issue: Features contain NaN or Inf values
# Solution: Check signal quality and preprocessing
features = {k: v for k, v in features.items() if not (np.isnan(v) or np.isinf(v))}
Issue: EMD fails to converge
# Solution: Reduce max_imf or smooth signal first
emd = EMD(max_imf=5, max_iter=50)
Issue: Memory error with large signals
# Solution: Use sliding windows
windows = SignalUtils.sliding_window(signal, window_size=1000, step_size=500)
for window in windows:
features = extractor.extract_all_features(window)
Citation
If you use SigFeatX in your research, please cite:
@software{sigfeatx2024,
title={SigFeatX: Signal Feature Extraction Library},
author={Diptiman Mohanta},
year={2024},
url={https://github.com/diptiman-mohanta/SigFeatX}
}
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- PyWavelets for wavelet transforms
- SciPy for signal processing functions
- NumPy for numerical computations
Contact
For questions and support, please open an issue on GitHub.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sigfeatx-0.4.0.tar.gz.
File metadata
- Download URL: sigfeatx-0.4.0.tar.gz
- Upload date:
- Size: 92.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0d9fc2dd431337cc2ede1d1196250be2193996df8e206248050e8b8ad889b63
|
|
| MD5 |
ca6d3ce500f66210599f55544dec90e4
|
|
| BLAKE2b-256 |
2fd0a56ae5c3970cb4b8885ef96da41d9b8b77ed8f083891c507fc34bd40d90d
|
Provenance
The following attestation bundles were made for sigfeatx-0.4.0.tar.gz:
Publisher:
release.yml on diptiman-mohanta/SigFeatX
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sigfeatx-0.4.0.tar.gz -
Subject digest:
f0d9fc2dd431337cc2ede1d1196250be2193996df8e206248050e8b8ad889b63 - Sigstore transparency entry: 2187081277
- Sigstore integration time:
-
Permalink:
diptiman-mohanta/SigFeatX@37bc0e69eb602eff171de0dc5647c5dcaa52f2b8 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/diptiman-mohanta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37bc0e69eb602eff171de0dc5647c5dcaa52f2b8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sigfeatx-0.4.0-py3-none-any.whl.
File metadata
- Download URL: sigfeatx-0.4.0-py3-none-any.whl
- Upload date:
- Size: 92.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af2ef1387fbf57030662c52e7dd4cdb71eae18034b0d3c53338a1eebda32be64
|
|
| MD5 |
1fbaeb8f9b97abe40b8047620a5e518b
|
|
| BLAKE2b-256 |
b3a1fe425bf68efaa070c13d066ba0f5574ae55159577c1fcfaaed00cb34c414
|
Provenance
The following attestation bundles were made for sigfeatx-0.4.0-py3-none-any.whl:
Publisher:
release.yml on diptiman-mohanta/SigFeatX
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sigfeatx-0.4.0-py3-none-any.whl -
Subject digest:
af2ef1387fbf57030662c52e7dd4cdb71eae18034b0d3c53338a1eebda32be64 - Sigstore transparency entry: 2187081281
- Sigstore integration time:
-
Permalink:
diptiman-mohanta/SigFeatX@37bc0e69eb602eff171de0dc5647c5dcaa52f2b8 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/diptiman-mohanta
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@37bc0e69eb602eff171de0dc5647c5dcaa52f2b8 -
Trigger Event:
push
-
Statement type: