slimtsf 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- slimtsf-1.0.2/.github/workflows/ci.yml +34 -0
- slimtsf-1.0.2/.github/workflows/publish.yml +95 -0
- slimtsf-1.0.2/.gitignore +67 -0
- slimtsf-1.0.2/CHANGELOG.md +27 -0
- slimtsf-1.0.2/PKG-INFO +214 -0
- slimtsf-1.0.2/README.md +184 -0
- slimtsf-1.0.2/environment.yml +22 -0
- slimtsf-1.0.2/pyproject.toml +82 -0
- slimtsf-1.0.2/setup.cfg +4 -0
- slimtsf-1.0.2/slimtsf/__init__.py +46 -0
- slimtsf-1.0.2/slimtsf/classifier.py +276 -0
- slimtsf-1.0.2/slimtsf/tests/__init__.py +0 -0
- slimtsf-1.0.2/slimtsf/tests/test_classifier.py +224 -0
- slimtsf-1.0.2/slimtsf/tests/test_interval_stats_pooling.py +430 -0
- slimtsf-1.0.2/slimtsf/tests/test_sliding_intervals.py +102 -0
- slimtsf-1.0.2/slimtsf/transformers/__init__.py +19 -0
- slimtsf-1.0.2/slimtsf/transformers/interval_stats_pooling.py +264 -0
- slimtsf-1.0.2/slimtsf/transformers/sliding_intervals.py +317 -0
- slimtsf-1.0.2/slimtsf.egg-info/PKG-INFO +214 -0
- slimtsf-1.0.2/slimtsf.egg-info/SOURCES.txt +21 -0
- slimtsf-1.0.2/slimtsf.egg-info/dependency_links.txt +1 -0
- slimtsf-1.0.2/slimtsf.egg-info/requires.txt +9 -0
- slimtsf-1.0.2/slimtsf.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["**"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["**"]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0 # needed for setuptools-scm to read git tags
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
uses: actions/setup-python@v6
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
- name: Install package and dev dependencies
|
|
29
|
+
run: |
|
|
30
|
+
python -m pip install --upgrade pip
|
|
31
|
+
pip install -e ".[dev]"
|
|
32
|
+
|
|
33
|
+
- name: Run tests
|
|
34
|
+
run: pytest -v
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
# Required for semantic-release to push tags and commits back to the repo
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release:
|
|
15
|
+
name: Semantic Release → PyPI
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
concurrency: release # prevent concurrent releases
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0 # full history needed for semantic-release
|
|
23
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
24
|
+
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.11"
|
|
29
|
+
|
|
30
|
+
- name: Install all dependencies
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install --upgrade pip
|
|
33
|
+
pip install -e ".[dev]"
|
|
34
|
+
# Explicitly install build tools in this same environment
|
|
35
|
+
# (semantic-release calls 'python -m build' in the same shell)
|
|
36
|
+
pip install build twine
|
|
37
|
+
|
|
38
|
+
# ---------------------------------------------------------------
|
|
39
|
+
# Run tests — block publish if tests fail
|
|
40
|
+
# ---------------------------------------------------------------
|
|
41
|
+
- name: Run tests
|
|
42
|
+
run: pytest -v
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------
|
|
45
|
+
# Capture the current latest tag so we can detect if PSR made a
|
|
46
|
+
# new release (used to gate the build + PyPI upload steps).
|
|
47
|
+
# ---------------------------------------------------------------
|
|
48
|
+
- name: Record tag before release
|
|
49
|
+
id: before
|
|
50
|
+
run: |
|
|
51
|
+
TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
|
|
52
|
+
echo "tag=$TAG" >> $GITHUB_OUTPUT
|
|
53
|
+
|
|
54
|
+
# ---------------------------------------------------------------
|
|
55
|
+
# Semantic Release — bumps version, commits, creates git tag,
|
|
56
|
+
# and pushes. Does NOT build (build_command="" in pyproject.toml)
|
|
57
|
+
# so setuptools-scm won't see a pre-tag dirty state.
|
|
58
|
+
# ---------------------------------------------------------------
|
|
59
|
+
- name: Python Semantic Release
|
|
60
|
+
run: semantic-release version
|
|
61
|
+
env:
|
|
62
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
63
|
+
|
|
64
|
+
# ---------------------------------------------------------------
|
|
65
|
+
# Detect if a new tag was created by PSR.
|
|
66
|
+
# ---------------------------------------------------------------
|
|
67
|
+
- name: Check if a new release was made
|
|
68
|
+
id: released
|
|
69
|
+
run: |
|
|
70
|
+
NEW_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
|
|
71
|
+
OLD_TAG="${{ steps.before.outputs.tag }}"
|
|
72
|
+
if [ "$NEW_TAG" != "$OLD_TAG" ]; then
|
|
73
|
+
echo "yes=true" >> $GITHUB_OUTPUT
|
|
74
|
+
else
|
|
75
|
+
echo "yes=false" >> $GITHUB_OUTPUT
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
# ---------------------------------------------------------------
|
|
79
|
+
# Build AFTER PSR has created + pushed the tag.
|
|
80
|
+
# setuptools-scm now sees the exact tag → clean version (e.g. 0.1.0)
|
|
81
|
+
# with no local identifier — accepted by PyPI.
|
|
82
|
+
# ---------------------------------------------------------------
|
|
83
|
+
- name: Build distribution
|
|
84
|
+
if: steps.released.outputs.yes == 'true'
|
|
85
|
+
run: python -m build
|
|
86
|
+
|
|
87
|
+
# ---------------------------------------------------------------
|
|
88
|
+
# Upload clean wheel + sdist to PyPI.
|
|
89
|
+
# ---------------------------------------------------------------
|
|
90
|
+
- name: Publish to PyPI
|
|
91
|
+
if: steps.released.outputs.yes == 'true'
|
|
92
|
+
run: twine upload dist/*
|
|
93
|
+
env:
|
|
94
|
+
TWINE_USERNAME: __token__
|
|
95
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
slimtsf-1.0.2/.gitignore
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
env/
|
|
12
|
+
venv/
|
|
13
|
+
ENV/
|
|
14
|
+
env.bak/
|
|
15
|
+
venv.bak/
|
|
16
|
+
*.egg-info/
|
|
17
|
+
dist/
|
|
18
|
+
build/
|
|
19
|
+
.eggs/
|
|
20
|
+
|
|
21
|
+
# Conda environment files
|
|
22
|
+
*.conda
|
|
23
|
+
*.env
|
|
24
|
+
|
|
25
|
+
# Jupyter Notebook checkpoints
|
|
26
|
+
.ipynb_checkpoints
|
|
27
|
+
|
|
28
|
+
# VSCode settings
|
|
29
|
+
.vscode/
|
|
30
|
+
|
|
31
|
+
# PyCharm settings
|
|
32
|
+
.idea/
|
|
33
|
+
|
|
34
|
+
# MacOS
|
|
35
|
+
.DS_Store
|
|
36
|
+
|
|
37
|
+
# Test, coverage, and profiling
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
.coverage
|
|
42
|
+
.coverage.*
|
|
43
|
+
.cache
|
|
44
|
+
nosetests.xml
|
|
45
|
+
coverage.xml
|
|
46
|
+
*.cover
|
|
47
|
+
*.py,cover
|
|
48
|
+
.hypothesis/
|
|
49
|
+
.pytest_cache/
|
|
50
|
+
|
|
51
|
+
# Data, logs, and outputs
|
|
52
|
+
*.log
|
|
53
|
+
*.out
|
|
54
|
+
*.dat
|
|
55
|
+
*.csv
|
|
56
|
+
*.tsv
|
|
57
|
+
*.db
|
|
58
|
+
*.sqlite
|
|
59
|
+
*.h5
|
|
60
|
+
*.hdf5
|
|
61
|
+
|
|
62
|
+
# Notebooks outputs (optional, if you want to ignore outputs)
|
|
63
|
+
**/.ipynb_checkpoints
|
|
64
|
+
**/*.nbconvert.ipynb
|
|
65
|
+
|
|
66
|
+
#
|
|
67
|
+
ignore_*
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CHANGELOG
|
|
2
|
+
|
|
3
|
+
<!-- version list -->
|
|
4
|
+
|
|
5
|
+
## v1.0.2 (2026-03-09)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Ci/cd twine publish
|
|
10
|
+
([`0c05fac`](https://github.com/kennaruk/slimtsf/commit/0c05fac3f08061d7be98d3e7d6f9a37ef733061a))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## v1.0.0 (2026-03-09)
|
|
14
|
+
|
|
15
|
+
- Initial Release
|
|
16
|
+
|
|
17
|
+
## v1.0.1 (2026-03-09)
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
- **CI/CD**: Correct env pypi key
|
|
22
|
+
([`fdbd0be`](https://github.com/kennaruk/slimtsf/commit/fdbd0be9c6987c320373867368e71b8f6e792eb2))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## v1.0.0 (2026-03-09)
|
|
26
|
+
|
|
27
|
+
- Initial Release
|
slimtsf-1.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: slimtsf
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Sliding-window multivariate time-series feature extraction and classification
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/kennaruk/slimtsf
|
|
7
|
+
Project-URL: Repository, https://github.com/kennaruk/slimtsf
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/kennaruk/slimtsf/issues
|
|
9
|
+
Keywords: time-series,machine-learning,classification,random-forest,sliding-window
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: numpy>=1.24
|
|
23
|
+
Requires-Dist: scikit-learn>=1.3
|
|
24
|
+
Requires-Dist: joblib>=1.3
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
27
|
+
Requires-Dist: python-semantic-release>=10.0; extra == "dev"
|
|
28
|
+
Requires-Dist: build; extra == "dev"
|
|
29
|
+
Requires-Dist: twine; extra == "dev"
|
|
30
|
+
|
|
31
|
+
# slimtsf · Sliding-Window Multivariate Time-Series Forest
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/slimtsf/)
|
|
34
|
+
[](https://github.com/kennaruk/slimtsf/actions/workflows/ci.yml)
|
|
35
|
+
[](https://www.python.org/)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
|
|
38
|
+
A minimal, **scikit-learn–compatible** library for classifying multivariate time-series data using multi-scale sliding-window feature extraction.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install slimtsf
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
### Full pipeline (recommended)
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import numpy as np
|
|
56
|
+
from slimtsf import SlimTSFClassifier
|
|
57
|
+
|
|
58
|
+
# X: (n_cases, n_channels, n_timepoints) — 3-D numpy array
|
|
59
|
+
X_train = np.random.randn(100, 3, 120)
|
|
60
|
+
y_train = np.array([0] * 50 + [1] * 50)
|
|
61
|
+
|
|
62
|
+
clf = SlimTSFClassifier(n_estimators=200, random_state=42)
|
|
63
|
+
clf.fit(X_train, y_train)
|
|
64
|
+
|
|
65
|
+
X_test = np.random.randn(20, 3, 120)
|
|
66
|
+
predictions = clf.predict(X_test) # shape (20,)
|
|
67
|
+
probabilities = clf.predict_proba(X_test) # shape (20, 2)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Transformers only (composable use)
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from slimtsf import SlidingWindowIntervalTransformer, IntervalStatsPoolingTransformer
|
|
74
|
+
|
|
75
|
+
# Stage 1 — extract sliding-window features
|
|
76
|
+
stage1 = SlidingWindowIntervalTransformer(
|
|
77
|
+
window_sizes=[8, 16, 32], # or None for auto
|
|
78
|
+
window_step_ratio=0.5,
|
|
79
|
+
feature_functions=["mean", "std", "slope"],
|
|
80
|
+
)
|
|
81
|
+
interval_features = stage1.fit_transform(X_train) # (n_cases, n_interval_features)
|
|
82
|
+
|
|
83
|
+
# Stage 2 — pool across windows
|
|
84
|
+
stage2 = IntervalStatsPoolingTransformer(aggregations=("min", "mean", "max"))
|
|
85
|
+
pooled = stage2.fit_transform(
|
|
86
|
+
interval_features,
|
|
87
|
+
feature_metadata=stage1.feature_metadata_, # wires Stage 1 → Stage 2
|
|
88
|
+
) # (n_cases, n_pooled_features)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Use with scikit-learn tools
|
|
92
|
+
|
|
93
|
+
Because `SlimTSFClassifier` exposes fitted stage attributes, you can access the underlying sklearn RF and use it with standard sklearn utilities:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from sklearn.model_selection import cross_val_score
|
|
97
|
+
|
|
98
|
+
# Fit first, then use sklearn metrics on transformed data
|
|
99
|
+
clf.fit(X_train, y_train)
|
|
100
|
+
Xt = clf.stage2_.transform(clf.stage1_.transform(X_train))
|
|
101
|
+
|
|
102
|
+
scores = cross_val_score(clf.stage3_, Xt, y_train, cv=5)
|
|
103
|
+
print(scores.mean())
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## How It Works
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
3-D time-series X (n_cases, n_channels, n_timepoints)
|
|
112
|
+
│
|
|
113
|
+
▼ Stage 1 — SlidingWindowIntervalTransformer
|
|
114
|
+
│ Slide windows of multiple sizes across each channel.
|
|
115
|
+
│ Compute mean / std / slope per window.
|
|
116
|
+
│ Output: 2-D matrix (n_cases, n_interval_features)
|
|
117
|
+
│
|
|
118
|
+
▼ Stage 2 — IntervalStatsPoolingTransformer
|
|
119
|
+
│ For each (channel, feature) group,
|
|
120
|
+
│ pool across windows: min / mean / max.
|
|
121
|
+
│ Output: 2-D compact matrix (n_cases, n_pooled_features)
|
|
122
|
+
│
|
|
123
|
+
▼ Stage 3 — RandomForestClassifier (scikit-learn)
|
|
124
|
+
Classify the pooled feature matrix.
|
|
125
|
+
Output: predicted labels / probabilities
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## API Reference
|
|
131
|
+
|
|
132
|
+
### `SlimTSFClassifier`
|
|
133
|
+
|
|
134
|
+
| Parameter | Type | Default | Description |
|
|
135
|
+
|---|---|---|---|
|
|
136
|
+
| `window_sizes` | `list[int] \| None` | `None` | Window sizes. Auto if `None` (`[T, T//2, …]`). |
|
|
137
|
+
| `window_step_ratio` | `float` | `0.5` | Step = ratio × window size. |
|
|
138
|
+
| `feature_functions` | `list[str\|FeatureFunction]` | `("mean","std","slope")` | Per-window features. |
|
|
139
|
+
| `aggregations` | `list[str]` | `("min","mean","max")` | Pooling statistics across windows. |
|
|
140
|
+
| `n_estimators` | `int` | `200` | Number of RF trees. |
|
|
141
|
+
| `max_depth` | `int\|None` | `None` | Max tree depth. |
|
|
142
|
+
| `class_weight` | `str\|dict\|None` | `"balanced"` | RF class weighting. |
|
|
143
|
+
| `random_state` | `int\|None` | `None` | Reproducibility seed. |
|
|
144
|
+
| `n_jobs` | `int` | `1` | Parallel jobs for RF (`-1` = all CPUs). |
|
|
145
|
+
|
|
146
|
+
**Methods:** `fit(X, y)` · `predict(X)` · `predict_proba(X)` · `get_feature_names_out()`
|
|
147
|
+
|
|
148
|
+
**Fitted attributes:** `stage1_` · `stage2_` · `stage3_` · `classes_` · `n_features_in_`
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### `SlidingWindowIntervalTransformer`
|
|
153
|
+
|
|
154
|
+
**Input:** `X` — shape `(n_cases, n_channels, n_timepoints)`
|
|
155
|
+
**Output:** 2-D feature matrix `(n_cases, n_interval_features)`
|
|
156
|
+
|
|
157
|
+
**Methods:** `fit(X)` · `transform(X)` · `fit_transform(X)` · `get_feature_names_out()`
|
|
158
|
+
**Fitted attributes:** `feature_metadata_` · `interval_list_`
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### `IntervalStatsPoolingTransformer`
|
|
163
|
+
|
|
164
|
+
**Input:** 2-D interval feature matrix from Stage 1 + `feature_metadata`
|
|
165
|
+
**Output:** 2-D pooled feature matrix `(n_cases, n_pooled_features)`
|
|
166
|
+
|
|
167
|
+
**Methods:** `fit(X, feature_metadata)` · `transform(X)` · `fit_transform(X, feature_metadata)` · `get_feature_names_out()`
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Custom Feature Functions
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from slimtsf import FeatureFunction, SlidingWindowIntervalTransformer
|
|
175
|
+
import numpy as np
|
|
176
|
+
|
|
177
|
+
# A custom feature: interquartile range
|
|
178
|
+
iqr = FeatureFunction(
|
|
179
|
+
name="iqr",
|
|
180
|
+
function=lambda seg: np.percentile(seg, 75, axis=1) - np.percentile(seg, 25, axis=1),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
transformer = SlidingWindowIntervalTransformer(feature_functions=["mean", iqr])
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Versioning
|
|
189
|
+
|
|
190
|
+
This project follows [Semantic Versioning](https://semver.org/) and [Conventional Commits](https://www.conventionalcommits.org/):
|
|
191
|
+
|
|
192
|
+
| Commit prefix | Effect |
|
|
193
|
+
|---|---|
|
|
194
|
+
| `fix:` | patch release (0.1.x) |
|
|
195
|
+
| `feat:` | minor release (0.x.0) |
|
|
196
|
+
| `feat!:` / `BREAKING CHANGE:` | major release (x.0.0) |
|
|
197
|
+
| `docs:` `chore:` `test:` | no release |
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Development
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
git clone https://github.com/kennaruk/slimtsf.git
|
|
205
|
+
cd slimtsf
|
|
206
|
+
pip install -e ".[dev]"
|
|
207
|
+
pytest -v
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT — see [LICENSE](LICENSE).
|
slimtsf-1.0.2/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# slimtsf · Sliding-Window Multivariate Time-Series Forest
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/slimtsf/)
|
|
4
|
+
[](https://github.com/kennaruk/slimtsf/actions/workflows/ci.yml)
|
|
5
|
+
[](https://www.python.org/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
A minimal, **scikit-learn–compatible** library for classifying multivariate time-series data using multi-scale sliding-window feature extraction.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install slimtsf
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### Full pipeline (recommended)
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import numpy as np
|
|
26
|
+
from slimtsf import SlimTSFClassifier
|
|
27
|
+
|
|
28
|
+
# X: (n_cases, n_channels, n_timepoints) — 3-D numpy array
|
|
29
|
+
X_train = np.random.randn(100, 3, 120)
|
|
30
|
+
y_train = np.array([0] * 50 + [1] * 50)
|
|
31
|
+
|
|
32
|
+
clf = SlimTSFClassifier(n_estimators=200, random_state=42)
|
|
33
|
+
clf.fit(X_train, y_train)
|
|
34
|
+
|
|
35
|
+
X_test = np.random.randn(20, 3, 120)
|
|
36
|
+
predictions = clf.predict(X_test) # shape (20,)
|
|
37
|
+
probabilities = clf.predict_proba(X_test) # shape (20, 2)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Transformers only (composable use)
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from slimtsf import SlidingWindowIntervalTransformer, IntervalStatsPoolingTransformer
|
|
44
|
+
|
|
45
|
+
# Stage 1 — extract sliding-window features
|
|
46
|
+
stage1 = SlidingWindowIntervalTransformer(
|
|
47
|
+
window_sizes=[8, 16, 32], # or None for auto
|
|
48
|
+
window_step_ratio=0.5,
|
|
49
|
+
feature_functions=["mean", "std", "slope"],
|
|
50
|
+
)
|
|
51
|
+
interval_features = stage1.fit_transform(X_train) # (n_cases, n_interval_features)
|
|
52
|
+
|
|
53
|
+
# Stage 2 — pool across windows
|
|
54
|
+
stage2 = IntervalStatsPoolingTransformer(aggregations=("min", "mean", "max"))
|
|
55
|
+
pooled = stage2.fit_transform(
|
|
56
|
+
interval_features,
|
|
57
|
+
feature_metadata=stage1.feature_metadata_, # wires Stage 1 → Stage 2
|
|
58
|
+
) # (n_cases, n_pooled_features)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Use with scikit-learn tools
|
|
62
|
+
|
|
63
|
+
Because `SlimTSFClassifier` exposes fitted stage attributes, you can access the underlying sklearn RF and use it with standard sklearn utilities:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from sklearn.model_selection import cross_val_score
|
|
67
|
+
|
|
68
|
+
# Fit first, then use sklearn metrics on transformed data
|
|
69
|
+
clf.fit(X_train, y_train)
|
|
70
|
+
Xt = clf.stage2_.transform(clf.stage1_.transform(X_train))
|
|
71
|
+
|
|
72
|
+
scores = cross_val_score(clf.stage3_, Xt, y_train, cv=5)
|
|
73
|
+
print(scores.mean())
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## How It Works
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
3-D time-series X (n_cases, n_channels, n_timepoints)
|
|
82
|
+
│
|
|
83
|
+
▼ Stage 1 — SlidingWindowIntervalTransformer
|
|
84
|
+
│ Slide windows of multiple sizes across each channel.
|
|
85
|
+
│ Compute mean / std / slope per window.
|
|
86
|
+
│ Output: 2-D matrix (n_cases, n_interval_features)
|
|
87
|
+
│
|
|
88
|
+
▼ Stage 2 — IntervalStatsPoolingTransformer
|
|
89
|
+
│ For each (channel, feature) group,
|
|
90
|
+
│ pool across windows: min / mean / max.
|
|
91
|
+
│ Output: 2-D compact matrix (n_cases, n_pooled_features)
|
|
92
|
+
│
|
|
93
|
+
▼ Stage 3 — RandomForestClassifier (scikit-learn)
|
|
94
|
+
Classify the pooled feature matrix.
|
|
95
|
+
Output: predicted labels / probabilities
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## API Reference
|
|
101
|
+
|
|
102
|
+
### `SlimTSFClassifier`
|
|
103
|
+
|
|
104
|
+
| Parameter | Type | Default | Description |
|
|
105
|
+
|---|---|---|---|
|
|
106
|
+
| `window_sizes` | `list[int] \| None` | `None` | Window sizes. Auto if `None` (`[T, T//2, …]`). |
|
|
107
|
+
| `window_step_ratio` | `float` | `0.5` | Step = ratio × window size. |
|
|
108
|
+
| `feature_functions` | `list[str\|FeatureFunction]` | `("mean","std","slope")` | Per-window features. |
|
|
109
|
+
| `aggregations` | `list[str]` | `("min","mean","max")` | Pooling statistics across windows. |
|
|
110
|
+
| `n_estimators` | `int` | `200` | Number of RF trees. |
|
|
111
|
+
| `max_depth` | `int\|None` | `None` | Max tree depth. |
|
|
112
|
+
| `class_weight` | `str\|dict\|None` | `"balanced"` | RF class weighting. |
|
|
113
|
+
| `random_state` | `int\|None` | `None` | Reproducibility seed. |
|
|
114
|
+
| `n_jobs` | `int` | `1` | Parallel jobs for RF (`-1` = all CPUs). |
|
|
115
|
+
|
|
116
|
+
**Methods:** `fit(X, y)` · `predict(X)` · `predict_proba(X)` · `get_feature_names_out()`
|
|
117
|
+
|
|
118
|
+
**Fitted attributes:** `stage1_` · `stage2_` · `stage3_` · `classes_` · `n_features_in_`
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### `SlidingWindowIntervalTransformer`
|
|
123
|
+
|
|
124
|
+
**Input:** `X` — shape `(n_cases, n_channels, n_timepoints)`
|
|
125
|
+
**Output:** 2-D feature matrix `(n_cases, n_interval_features)`
|
|
126
|
+
|
|
127
|
+
**Methods:** `fit(X)` · `transform(X)` · `fit_transform(X)` · `get_feature_names_out()`
|
|
128
|
+
**Fitted attributes:** `feature_metadata_` · `interval_list_`
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### `IntervalStatsPoolingTransformer`
|
|
133
|
+
|
|
134
|
+
**Input:** 2-D interval feature matrix from Stage 1 + `feature_metadata`
|
|
135
|
+
**Output:** 2-D pooled feature matrix `(n_cases, n_pooled_features)`
|
|
136
|
+
|
|
137
|
+
**Methods:** `fit(X, feature_metadata)` · `transform(X)` · `fit_transform(X, feature_metadata)` · `get_feature_names_out()`
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Custom Feature Functions
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from slimtsf import FeatureFunction, SlidingWindowIntervalTransformer
|
|
145
|
+
import numpy as np
|
|
146
|
+
|
|
147
|
+
# A custom feature: interquartile range
|
|
148
|
+
iqr = FeatureFunction(
|
|
149
|
+
name="iqr",
|
|
150
|
+
function=lambda seg: np.percentile(seg, 75, axis=1) - np.percentile(seg, 25, axis=1),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
transformer = SlidingWindowIntervalTransformer(feature_functions=["mean", iqr])
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Versioning
|
|
159
|
+
|
|
160
|
+
This project follows [Semantic Versioning](https://semver.org/) and [Conventional Commits](https://www.conventionalcommits.org/):
|
|
161
|
+
|
|
162
|
+
| Commit prefix | Effect |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `fix:` | patch release (0.1.x) |
|
|
165
|
+
| `feat:` | minor release (0.x.0) |
|
|
166
|
+
| `feat!:` / `BREAKING CHANGE:` | major release (x.0.0) |
|
|
167
|
+
| `docs:` `chore:` `test:` | no release |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
git clone https://github.com/kennaruk/slimtsf.git
|
|
175
|
+
cd slimtsf
|
|
176
|
+
pip install -e ".[dev]"
|
|
177
|
+
pytest -v
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: slimtsf-v1
|
|
2
|
+
channels:
|
|
3
|
+
- https://repo.anaconda.com/pkgs/main
|
|
4
|
+
- https://repo.anaconda.com/pkgs/r
|
|
5
|
+
- conda-forge
|
|
6
|
+
dependencies:
|
|
7
|
+
- python=3.13
|
|
8
|
+
- ipykernel
|
|
9
|
+
# Core runtime dependencies
|
|
10
|
+
- numpy>=1.24
|
|
11
|
+
- scikit-learn>=1.3
|
|
12
|
+
- joblib>=1.3
|
|
13
|
+
# Dev / testing tools
|
|
14
|
+
- pytest>=7.4
|
|
15
|
+
- pip
|
|
16
|
+
- pip:
|
|
17
|
+
# Installed via pip because they're not in conda channels
|
|
18
|
+
- setuptools-scm>=8
|
|
19
|
+
- python-semantic-release>=8.0
|
|
20
|
+
- build
|
|
21
|
+
- twine
|
|
22
|
+
prefix: /opt/anaconda3/envs/slimtsf-v1
|