SublimeX: Supervised Bottom-Up Localized Multi-Representative Feature eXtraction for time series and spatial data
Project description
SublimeX
Supervised Bottom-Up Localized Multi-Representative Feature eXtraction
SublimeX is an interpretable feature extraction framework for time series and spatial data. It discovers a minimal set of task-specific features through Bayesian optimization, where each feature has explicit, human-readable semantics.
Key Features
- Minimal feature sets: Typically 5-15 features vs. thousands from other methods
- Full interpretability: Each feature = statistic over optimized segment of transformed signal
- Competitive performance: Matches deep learning on many tasks
- Modular design: Custom transforms, objectives, and ML models
Installation
pip install sublimex
Or install from source:
git clone https://github.com/Prgrmmrjns/SublimeX.git
cd SublimeX
pip install -e .
Quick Start
import sublimex
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
# Your data: list of arrays/DataFrames, one per channel
# Each array has shape (n_samples, n_time_points)
X = [channel1_data, channel2_data, channel3_data] # 3 channels
y = labels # Binary or continuous targets
# Split data
X_train, X_test, y_train, y_test = train_test_split(
range(len(y)), test_size=0.2, stratify=y, random_state=42
)
X_train = [x.iloc[X_train] for x in X]
X_test = [x.iloc[X_test] for x in X]
y_train, y_test = y[X_train], y[X_test]
# Fit SublimeX
model = sublimex.SublimeX(metric='auc', n_trials=100, verbose=True)
train_features = model.fit_transform(X_train, y_train)
test_features = model.transform(X_test)
# Use with any classifier
clf = RandomForestClassifier()
clf.fit(train_features, y_train)
predictions = clf.predict(test_features)
# Interpret discovered features
for desc in model.get_feature_descriptions():
print(desc)
How It Works
SublimeX discovers discriminative features through a simple but effective process:
-
Signal Transformation: Apply multiple transforms to create different "views" of the data (raw, z-score normalized, derivative, FFT power spectrum)
-
Segment Optimization: Use Bayesian optimization (Optuna) to find segments that maximize downstream model performance
-
Feature Extraction: Compute statistics (e.g., mean) over discovered segments
-
Iterative Discovery: Repeat until adding new features no longer improves performance
Each discovered feature is fully interpretable:
"Mean of z-score normalized signal in channel 2, positions 40-60"
Configuration
Basic Parameters
import sublimex
model = sublimex.SublimeX(
metric='auc', # 'auc', 'accuracy', or 'rmse'
n_trials=300, # Optimization trials per feature
inner_cv=1, # Internal CV folds (1 = single split)
val_size=0.5, # Validation size when inner_cv=1
verbose=True, # Print progress
)
Custom Transforms
import sublimex
# Register a custom transform
def hilbert_envelope(data):
from scipy.signal import hilbert
return np.abs(hilbert(data, axis=-1))
sublimex.register_transform('hilbert', hilbert_envelope)
# Use specific transforms
model = sublimex.SublimeX(
transforms={
'raw': lambda x: x,
'hilbert': hilbert_envelope,
}
)
Custom Objective Functions
import sublimex
import numpy as np
# Create objective with custom aggregation
def rms(segment):
"""Root mean square."""
return np.sqrt((segment ** 2).mean(axis=1, keepdims=True))
rms_objective = sublimex.create_custom_objective(rms, 'rms')
model = sublimex.SublimeX(objective_fn=rms_objective)
Custom ML Models
import sublimex
from sklearn.ensemble import RandomForestClassifier
# Wrap any sklearn estimator
rf = RandomForestClassifier(n_estimators=100)
model = sublimex.SublimeX(model=sublimex.SklearnModelWrapper(rf))
Built-in Options
Transforms
| Transform | Description | Use Case |
|---|---|---|
raw |
Identity (original signal) | Amplitude differences |
zscore |
Z-score normalization | Shape differences |
derivative |
First-order gradient | Rate of change, transitions |
fft_power |
FFT power spectrum | Frequency content, periodicity |
Aggregations (for aggregate_objective)
| Aggregation | Description |
|---|---|
mean |
Average value (default) |
min, max |
Extreme values |
range |
max - min |
std |
Standard deviation |
median |
Robust central tendency |
argmin, argmax |
Position of extrema |
Objectives
| Objective | Description |
|---|---|
mean_objective |
Mean over segment (default, most interpretable) |
aggregate_objective |
Choose from 8 aggregations |
pattern_objective |
B-spline pattern matching |
Visualization
import sublimex
import matplotlib.pyplot as plt
# Compare feature values across classes
fig = sublimex.plot_feature_distributions(features, y, feature_idx=0)
plt.show()
# Show where a feature's segment falls on the signal
fig = sublimex.plot_segment_on_signal(
signal, model.extracted_features[0], model.n_time
)
plt.show()
# Compare all transforms for a sample
fig = sublimex.plot_transform_comparison(signal, sublimex.TRANSFORMS)
plt.show()
Saving and Loading
import sublimex
# Save discovered features
model.save_features('features.json')
# Load and reuse
new_model = sublimex.SublimeX()
new_model.load_features('features.json')
features = new_model.transform(X_new)
Complete Example: Synthetic Multi-Channel Time Series
"""Complete example with synthetic data."""
import sublimex
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
import lightgbm as lgb
# Generate synthetic multi-channel time series
np.random.seed(42)
n_samples, n_channels, n_bins = 500, 5, 200
X = []
y = np.random.randint(0, 2, n_samples)
for channel in range(n_channels):
channel_data = []
for i in range(n_samples):
t = np.linspace(0, 4 * np.pi, n_bins)
if y[i] == 1:
# Class 1: Higher amplitude with distinctive peak
signal = 2.0 * np.sin(t) + 1.5 * np.sin(2 * t)
peak = n_bins // 2
signal[peak-20:peak+20] += 1.5 * np.exp(-((np.arange(40) - 20) ** 2) / 50)
else:
# Class 0: Lower amplitude, more noise
signal = 1.0 * np.sin(t) + 0.5 * np.sin(3 * t)
signal += np.random.normal(0, 0.3, n_bins)
channel_data.append(signal)
X.append(pd.DataFrame(channel_data, columns=[f'bin_{j}' for j in range(n_bins)]))
# Split data
idx_train, idx_test = train_test_split(
range(len(y)), test_size=0.2, stratify=y, random_state=42
)
X_train = [x.iloc[idx_train].astype(np.float32) for x in X]
X_test = [x.iloc[idx_test].astype(np.float32) for x in X]
y_train, y_test = y[idx_train], y[idx_test]
# Discover features with SublimeX
model = sublimex.SublimeX(metric='auc', n_trials=50, verbose=True)
train_features = model.fit_transform(X_train, y_train)
test_features = model.transform(X_test)
print(f"Discovered {train_features.shape[1]} features")
# Train classifier
clf = lgb.LGBMClassifier(n_estimators=100, verbose=-1)
clf.fit(train_features, y_train)
auc = roc_auc_score(y_test, clf.predict_proba(test_features)[:, 1])
print(f"Test AUC: {auc:.4f}")
# Interpret features
print("\nDiscovered Features:")
for desc in model.get_feature_descriptions():
print(f" {desc}")
# Visualize
import matplotlib.pyplot as plt
fig = sublimex.plot_feature_importance(
clf.feature_importances_,
model.get_feature_descriptions()
)
plt.show()
Comparison with Other Methods
| Method | Features | Interpretability | Optimization |
|---|---|---|---|
| SublimeX | 5-15 | High (explicit segments) | Bayesian |
| tsfresh | 100-800 | Medium (statistical) | Filter |
| catch22 | 22 | Medium (fixed set) | None |
| MiniRocket | ~10,000 | Low | Deterministic |
| RDST | 2k-10k | Medium (shapelets) | Random |
Citation
If you use SublimeX in your research, please cite:
@software{sublimex2025,
title={SublimeX: Supervised Bottom-Up Localized Multi-Representative Feature eXtraction},
author={Wolber, J.C.},
year={2026},
url={https://github.com/Prgrmmrjns/SublimeX}
}
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
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 sublimex-0.1.0.tar.gz.
File metadata
- Download URL: sublimex-0.1.0.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10a811dbdb24ae97a1221bcb4dfc4ba4c024e3e0233c07f64b4afb521fddbc60
|
|
| MD5 |
fa4d56bc614054042d5afb23bf5eea71
|
|
| BLAKE2b-256 |
103c21b508a38480b77dd6ed054f555bcb1b8f9589cad05329deb311ba47db49
|
File details
Details for the file sublimex-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sublimex-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd1d1706ea80ccdc6ec382c7bbbe512c541a00644087480944a5bb1f867cdfd2
|
|
| MD5 |
7e4673a3cc58de19930feb8a1f21487b
|
|
| BLAKE2b-256 |
4bc741cfdc3ac43e50c15299bd83f99c3fc17d35fdc10f98c1802df51996eb48
|