heterodecomp 0.1.0__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.
- heterodecomp-0.1.0/MANIFEST.in +1 -0
- heterodecomp-0.1.0/PKG-INFO +156 -0
- heterodecomp-0.1.0/README.md +133 -0
- heterodecomp-0.1.0/examples/01_perpca.py +40 -0
- heterodecomp-0.1.0/examples/02_hmf.py +45 -0
- heterodecomp-0.1.0/examples/03_jive.py +36 -0
- heterodecomp-0.1.0/examples/04_robust_jive.py +38 -0
- heterodecomp-0.1.0/examples/05_rajive.py +44 -0
- heterodecomp-0.1.0/examples/06_slide.py +43 -0
- heterodecomp-0.1.0/examples/07_pertucker.py +43 -0
- heterodecomp-0.1.0/examples/08_percdl.py +43 -0
- heterodecomp-0.1.0/examples/09_robust_pca.py +42 -0
- heterodecomp-0.1.0/examples/10_real_bold_no_ground_truth.py +38 -0
- heterodecomp-0.1.0/examples/README.md +60 -0
- heterodecomp-0.1.0/examples/_common.py +71 -0
- heterodecomp-0.1.0/heterodecomp/__init__.py +27 -0
- heterodecomp-0.1.0/heterodecomp/_engine/__init__.py +3 -0
- heterodecomp-0.1.0/heterodecomp/_engine/metrics.py +169 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/__init__.py +47 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/base.py +66 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/hmf_adapter.py +54 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/jive_adapter.py +121 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/percdl_adapter.py +66 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/perpca_adapter.py +65 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/pertucker_adapter.py +61 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/robust_pca_adapter.py +44 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/slide_adapter.py +113 -0
- heterodecomp-0.1.0/heterodecomp/_engine/models/utils.py +88 -0
- heterodecomp-0.1.0/heterodecomp/_engine/progress.py +118 -0
- heterodecomp-0.1.0/heterodecomp/_engine/types.py +32 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/__init__.py +7 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/hmf.py +529 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/percdl.py +239 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/perpca.py +162 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/pertucker.py +265 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/rajive.py +487 -0
- heterodecomp-0.1.0/heterodecomp/_engine/vendor/slide.py +460 -0
- heterodecomp-0.1.0/heterodecomp/core.py +734 -0
- heterodecomp-0.1.0/heterodecomp/p300.py +231 -0
- heterodecomp-0.1.0/heterodecomp.egg-info/PKG-INFO +156 -0
- heterodecomp-0.1.0/heterodecomp.egg-info/SOURCES.txt +49 -0
- heterodecomp-0.1.0/heterodecomp.egg-info/dependency_links.txt +1 -0
- heterodecomp-0.1.0/heterodecomp.egg-info/requires.txt +14 -0
- heterodecomp-0.1.0/heterodecomp.egg-info/top_level.txt +1 -0
- heterodecomp-0.1.0/pyproject.toml +32 -0
- heterodecomp-0.1.0/setup.cfg +4 -0
- heterodecomp-0.1.0/tests/test_algorithms.py +69 -0
- heterodecomp-0.1.0/tests/test_core.py +96 -0
- heterodecomp-0.1.0/tests/test_fixtures.py +71 -0
- heterodecomp-0.1.0/tests/test_p300.py +68 -0
- heterodecomp-0.1.0/tests/test_progress.py +36 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include examples *.py *.md
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: heterodecomp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Shared and individual pattern decomposition for heterogeneous data
|
|
5
|
+
Classifier: Development Status :: 3 - Alpha
|
|
6
|
+
Classifier: Intended Audience :: Science/Research
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
Requires-Dist: numpy>=1.23
|
|
12
|
+
Requires-Dist: openpyxl>=3.1
|
|
13
|
+
Requires-Dist: pandas>=1.5
|
|
14
|
+
Requires-Dist: pillow>=9
|
|
15
|
+
Requires-Dist: scipy>=1.9
|
|
16
|
+
Requires-Dist: tensorly>=0.8
|
|
17
|
+
Requires-Dist: torch>=2.0
|
|
18
|
+
Provides-Extra: eeg
|
|
19
|
+
Requires-Dist: mne>=1.6; extra == "eeg"
|
|
20
|
+
Provides-Extra: test
|
|
21
|
+
Requires-Dist: build>=1; extra == "test"
|
|
22
|
+
Requires-Dist: twine>=5; extra == "test"
|
|
23
|
+
|
|
24
|
+
# HeteroDecomp
|
|
25
|
+
|
|
26
|
+
HeteroDecomp separates repeated data items into shared, individual-specific, and
|
|
27
|
+
residual patterns. It accepts time-series tables (BOLD, EEG, and similar
|
|
28
|
+
signals), general matrices (including symmetric FC matrices), and common image
|
|
29
|
+
formats.
|
|
30
|
+
|
|
31
|
+
## Install for development
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install -e .
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Install the optional EEG reader for MNE FIF files:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
python -m pip install -e ".[eeg]"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Basic API
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from heterodecomp import decompose
|
|
47
|
+
|
|
48
|
+
result = decompose(
|
|
49
|
+
r"D:\data\bold",
|
|
50
|
+
kind="timeseries",
|
|
51
|
+
algorithm="perpca",
|
|
52
|
+
shared_rank=5,
|
|
53
|
+
individual_rank=2,
|
|
54
|
+
params={"epochs": 200, "lr": 0.01},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
print(result.summary_metrics)
|
|
58
|
+
print(result.output_dir)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Before fitting, HeteroDecomp prints detected shapes, headers, index columns, missing
|
|
62
|
+
values, constant columns, symmetry, and a recommended truncation length when
|
|
63
|
+
time series differ in duration. Use explicit `header=` and `index=` arguments
|
|
64
|
+
to override conservative automatic detection.
|
|
65
|
+
|
|
66
|
+
By default, outputs are saved beside the input directory in separate `shared`,
|
|
67
|
+
`individual`, `reconstruction`, and `residual` folders. Per-item metrics,
|
|
68
|
+
summary metrics, the data audit, and model metadata are saved with them.
|
|
69
|
+
|
|
70
|
+
## Functional-connectivity matrices
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
result = decompose(
|
|
74
|
+
r"D:\data\fc",
|
|
75
|
+
kind="matrix",
|
|
76
|
+
algorithm="perpca",
|
|
77
|
+
shared_rank=10,
|
|
78
|
+
individual_rank=3,
|
|
79
|
+
output_format="xlsx",
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If every input is square and symmetric within tolerance, every saved shared and
|
|
84
|
+
individual FC component is explicitly symmetrized and keeps its detected row
|
|
85
|
+
and column labels.
|
|
86
|
+
|
|
87
|
+
## Images
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
result = decompose(
|
|
91
|
+
r"D:\data\frames",
|
|
92
|
+
kind="image",
|
|
93
|
+
algorithm="perpca",
|
|
94
|
+
shared_rank=5,
|
|
95
|
+
individual_rank=20,
|
|
96
|
+
image_format="png",
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
PNG previews are accompanied by `exact_components.npz`, which preserves signed
|
|
101
|
+
individual and residual arrays without visualization clipping.
|
|
102
|
+
|
|
103
|
+
## Simulated ground truth
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from heterodecomp import evaluate_ground_truth
|
|
107
|
+
|
|
108
|
+
metrics = evaluate_ground_truth(
|
|
109
|
+
result,
|
|
110
|
+
r"D:\data\shared_signal",
|
|
111
|
+
r"D:\data\individual_signal",
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Ground-truth recovery metrics are kept separate from real-data metrics so that
|
|
116
|
+
recovery claims cannot accidentally be made for empirical datasets.
|
|
117
|
+
|
|
118
|
+
## P300 validation
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from heterodecomp import prepare_p300, validate_p300
|
|
122
|
+
|
|
123
|
+
prepared = prepare_p300(r"D:\data\P300")
|
|
124
|
+
validation = validate_p300(prepared, shared_rank=5, individual_rank=2)
|
|
125
|
+
print(validation.pearson_r, validation.permutation_p)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
P300 validation matches the recovered shared spatial basis to the group target
|
|
129
|
+
topography, applies a maximum-component channel-label permutation test, and
|
|
130
|
+
reports target/non-target projection effects and peak latency.
|
|
131
|
+
|
|
132
|
+
## Algorithms
|
|
133
|
+
|
|
134
|
+
`perpca`, `hmf`, `jive`, `robust_jive`, `rajive`, `slide`, `pertucker`,
|
|
135
|
+
`percdl`, and `robust_pca` share one interface. Algorithm-specific settings are
|
|
136
|
+
passed through `params`; see each adapter in `heterodecomp/_engine/models` for the
|
|
137
|
+
accepted options.
|
|
138
|
+
|
|
139
|
+
All algorithms print interpretable quality metrics approximately every 1% of
|
|
140
|
+
the configured iterations (`epochs=300` prints every 3 iterations), including
|
|
141
|
+
explained variance, reconstruction correlation, residual energy, and—where
|
|
142
|
+
available—shared/individual energy allocation. Internal optimizer losses are
|
|
143
|
+
not printed. Runs shorter than 100 iterations print every iteration. Pass
|
|
144
|
+
`params={"progress": False}` to disable progress. RaJIVE has no epoch loop, so
|
|
145
|
+
it reports the equivalent block and decomposition stages instead.
|
|
146
|
+
|
|
147
|
+
Complete runnable examples for every algorithm are in
|
|
148
|
+
[`examples/README.md`](examples/README.md).
|
|
149
|
+
|
|
150
|
+
## Test
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python -m unittest discover -s tests -v
|
|
154
|
+
python -m build
|
|
155
|
+
python -m twine check dist/*
|
|
156
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# HeteroDecomp
|
|
2
|
+
|
|
3
|
+
HeteroDecomp separates repeated data items into shared, individual-specific, and
|
|
4
|
+
residual patterns. It accepts time-series tables (BOLD, EEG, and similar
|
|
5
|
+
signals), general matrices (including symmetric FC matrices), and common image
|
|
6
|
+
formats.
|
|
7
|
+
|
|
8
|
+
## Install for development
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
python -m pip install -e .
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Install the optional EEG reader for MNE FIF files:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python -m pip install -e ".[eeg]"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Basic API
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from heterodecomp import decompose
|
|
24
|
+
|
|
25
|
+
result = decompose(
|
|
26
|
+
r"D:\data\bold",
|
|
27
|
+
kind="timeseries",
|
|
28
|
+
algorithm="perpca",
|
|
29
|
+
shared_rank=5,
|
|
30
|
+
individual_rank=2,
|
|
31
|
+
params={"epochs": 200, "lr": 0.01},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
print(result.summary_metrics)
|
|
35
|
+
print(result.output_dir)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Before fitting, HeteroDecomp prints detected shapes, headers, index columns, missing
|
|
39
|
+
values, constant columns, symmetry, and a recommended truncation length when
|
|
40
|
+
time series differ in duration. Use explicit `header=` and `index=` arguments
|
|
41
|
+
to override conservative automatic detection.
|
|
42
|
+
|
|
43
|
+
By default, outputs are saved beside the input directory in separate `shared`,
|
|
44
|
+
`individual`, `reconstruction`, and `residual` folders. Per-item metrics,
|
|
45
|
+
summary metrics, the data audit, and model metadata are saved with them.
|
|
46
|
+
|
|
47
|
+
## Functional-connectivity matrices
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
result = decompose(
|
|
51
|
+
r"D:\data\fc",
|
|
52
|
+
kind="matrix",
|
|
53
|
+
algorithm="perpca",
|
|
54
|
+
shared_rank=10,
|
|
55
|
+
individual_rank=3,
|
|
56
|
+
output_format="xlsx",
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If every input is square and symmetric within tolerance, every saved shared and
|
|
61
|
+
individual FC component is explicitly symmetrized and keeps its detected row
|
|
62
|
+
and column labels.
|
|
63
|
+
|
|
64
|
+
## Images
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
result = decompose(
|
|
68
|
+
r"D:\data\frames",
|
|
69
|
+
kind="image",
|
|
70
|
+
algorithm="perpca",
|
|
71
|
+
shared_rank=5,
|
|
72
|
+
individual_rank=20,
|
|
73
|
+
image_format="png",
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
PNG previews are accompanied by `exact_components.npz`, which preserves signed
|
|
78
|
+
individual and residual arrays without visualization clipping.
|
|
79
|
+
|
|
80
|
+
## Simulated ground truth
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from heterodecomp import evaluate_ground_truth
|
|
84
|
+
|
|
85
|
+
metrics = evaluate_ground_truth(
|
|
86
|
+
result,
|
|
87
|
+
r"D:\data\shared_signal",
|
|
88
|
+
r"D:\data\individual_signal",
|
|
89
|
+
)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Ground-truth recovery metrics are kept separate from real-data metrics so that
|
|
93
|
+
recovery claims cannot accidentally be made for empirical datasets.
|
|
94
|
+
|
|
95
|
+
## P300 validation
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from heterodecomp import prepare_p300, validate_p300
|
|
99
|
+
|
|
100
|
+
prepared = prepare_p300(r"D:\data\P300")
|
|
101
|
+
validation = validate_p300(prepared, shared_rank=5, individual_rank=2)
|
|
102
|
+
print(validation.pearson_r, validation.permutation_p)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
P300 validation matches the recovered shared spatial basis to the group target
|
|
106
|
+
topography, applies a maximum-component channel-label permutation test, and
|
|
107
|
+
reports target/non-target projection effects and peak latency.
|
|
108
|
+
|
|
109
|
+
## Algorithms
|
|
110
|
+
|
|
111
|
+
`perpca`, `hmf`, `jive`, `robust_jive`, `rajive`, `slide`, `pertucker`,
|
|
112
|
+
`percdl`, and `robust_pca` share one interface. Algorithm-specific settings are
|
|
113
|
+
passed through `params`; see each adapter in `heterodecomp/_engine/models` for the
|
|
114
|
+
accepted options.
|
|
115
|
+
|
|
116
|
+
All algorithms print interpretable quality metrics approximately every 1% of
|
|
117
|
+
the configured iterations (`epochs=300` prints every 3 iterations), including
|
|
118
|
+
explained variance, reconstruction correlation, residual energy, and—where
|
|
119
|
+
available—shared/individual energy allocation. Internal optimizer losses are
|
|
120
|
+
not printed. Runs shorter than 100 iterations print every iteration. Pass
|
|
121
|
+
`params={"progress": False}` to disable progress. RaJIVE has no epoch loop, so
|
|
122
|
+
it reports the equivalent block and decomposition stages instead.
|
|
123
|
+
|
|
124
|
+
Complete runnable examples for every algorithm are in
|
|
125
|
+
[`examples/README.md`](examples/README.md).
|
|
126
|
+
|
|
127
|
+
## Test
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
python -m unittest discover -s tests -v
|
|
131
|
+
python -m build
|
|
132
|
+
python -m twine check dist/*
|
|
133
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Detailed PerPCA example for BOLD time-series matrices.
|
|
2
|
+
|
|
3
|
+
PerPCA is the recommended default when the goal is an explicit shared feature
|
|
4
|
+
subspace plus an orthogonal subject-specific subspace.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "perpca"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"epochs": 200, # Number of distributed covariance-gradient iterations.
|
|
20
|
+
"lr": 0.01, # Initial manifold-gradient step size.
|
|
21
|
+
"progress": True, # Print interpretable quality metrics every ~1%.
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
run_example(
|
|
27
|
+
algorithm="perpca",
|
|
28
|
+
params=PARAMS,
|
|
29
|
+
data_dir=DATA_DIR,
|
|
30
|
+
data_kind="timeseries",
|
|
31
|
+
pattern="*.csv",
|
|
32
|
+
max_items=10, # Use None for every subject.
|
|
33
|
+
shared_rank=3,
|
|
34
|
+
individual_rank=3,
|
|
35
|
+
target_length=150,
|
|
36
|
+
scaling="zscore",
|
|
37
|
+
output_dir=OUTPUT_DIR,
|
|
38
|
+
true_shared_dir=TRUE_SHARED_DIR, # Set both truth paths to None for real data.
|
|
39
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
40
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Detailed HMF example for shared/individual BOLD decomposition.
|
|
2
|
+
|
|
3
|
+
HMF uses separate global and local matrix factors and is useful when accurate
|
|
4
|
+
reconstruction is more important than strict projection-only components.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "hmf"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"epochs": 100,
|
|
20
|
+
"lr": 0.001,
|
|
21
|
+
"beta": 0.1, # Coupling strength for the shared factors.
|
|
22
|
+
"wd": 0.0, # Optimizer weight decay.
|
|
23
|
+
"optim": "SGD", # The vendored implementation also accepts Adam.
|
|
24
|
+
"epsilon": 0.0, # Set above zero to enable convergence stopping.
|
|
25
|
+
"device": "cpu", # Change to "cuda" when a compatible GPU is available.
|
|
26
|
+
"progress": True,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == "__main__":
|
|
31
|
+
run_example(
|
|
32
|
+
algorithm="hmf",
|
|
33
|
+
params=PARAMS,
|
|
34
|
+
data_dir=DATA_DIR,
|
|
35
|
+
data_kind="timeseries",
|
|
36
|
+
pattern="*.csv",
|
|
37
|
+
max_items=10,
|
|
38
|
+
shared_rank=3,
|
|
39
|
+
individual_rank=3,
|
|
40
|
+
target_length=150,
|
|
41
|
+
scaling="zscore",
|
|
42
|
+
output_dir=OUTPUT_DIR,
|
|
43
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
44
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
45
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Detailed JIVE example for joint and individual variation."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from _common import run_example
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
9
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
10
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
11
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
12
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "jive"
|
|
13
|
+
|
|
14
|
+
PARAMS = {
|
|
15
|
+
"epochs": 100, # Alternating joint/individual update iterations.
|
|
16
|
+
"device": "cpu",
|
|
17
|
+
"progress": True,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
run_example(
|
|
23
|
+
algorithm="jive",
|
|
24
|
+
params=PARAMS,
|
|
25
|
+
data_dir=DATA_DIR,
|
|
26
|
+
data_kind="timeseries",
|
|
27
|
+
pattern="*.csv",
|
|
28
|
+
max_items=10,
|
|
29
|
+
shared_rank=3,
|
|
30
|
+
individual_rank=3,
|
|
31
|
+
target_length=150,
|
|
32
|
+
scaling="zscore",
|
|
33
|
+
output_dir=OUTPUT_DIR,
|
|
34
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
35
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
36
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Detailed RobustJIVE example with an explicit sparse-error component."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from _common import run_example
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
9
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
10
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
11
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
12
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "robust_jive"
|
|
13
|
+
|
|
14
|
+
PARAMS = {
|
|
15
|
+
"epochs": 100,
|
|
16
|
+
"mu": 10.0, # Augmented-Lagrangian penalty.
|
|
17
|
+
"lbd": 0.01, # Sparse-error regularization strength.
|
|
18
|
+
"device": "cpu",
|
|
19
|
+
"progress": True,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if __name__ == "__main__":
|
|
24
|
+
run_example(
|
|
25
|
+
algorithm="robust_jive",
|
|
26
|
+
params=PARAMS,
|
|
27
|
+
data_dir=DATA_DIR,
|
|
28
|
+
data_kind="timeseries",
|
|
29
|
+
pattern="*.csv",
|
|
30
|
+
max_items=10,
|
|
31
|
+
shared_rank=3,
|
|
32
|
+
individual_rank=3,
|
|
33
|
+
target_length=150,
|
|
34
|
+
scaling="zscore",
|
|
35
|
+
output_dir=OUTPUT_DIR,
|
|
36
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
37
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
38
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Detailed angle-based robust JIVE (RaJIVE) example.
|
|
2
|
+
|
|
3
|
+
RaJIVE estimates joint structure using resampled Wedin and random-direction
|
|
4
|
+
bounds. Its sampling controls trade runtime for rank-selection stability.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "rajive"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"n_wedin_samples": 100,
|
|
20
|
+
"n_rand_dir_samples": 100,
|
|
21
|
+
"joint_rank": 3, # Set to None only when automatic selection is desired.
|
|
22
|
+
"robust_niter": 100,
|
|
23
|
+
"robust_tol": 1e-5,
|
|
24
|
+
"use_hmf_variant": False,
|
|
25
|
+
"progress": True,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
run_example(
|
|
31
|
+
algorithm="rajive",
|
|
32
|
+
params=PARAMS,
|
|
33
|
+
data_dir=DATA_DIR,
|
|
34
|
+
data_kind="timeseries",
|
|
35
|
+
pattern="*.csv",
|
|
36
|
+
max_items=10,
|
|
37
|
+
shared_rank=3,
|
|
38
|
+
individual_rank=3,
|
|
39
|
+
target_length=150,
|
|
40
|
+
scaling="zscore",
|
|
41
|
+
output_dir=OUTPUT_DIR,
|
|
42
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
43
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
44
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Detailed SLIDE example with a fixed shared/individual structure.
|
|
2
|
+
|
|
3
|
+
The default avoids expensive bi-cross-validation and constructs a structure
|
|
4
|
+
from the requested ranks. Enable ``use_bcv`` for data-driven structure search.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "slide"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"use_bcv": False,
|
|
20
|
+
"center": True,
|
|
21
|
+
"k_max": 1000,
|
|
22
|
+
"eps": 1e-6,
|
|
23
|
+
"progress": True,
|
|
24
|
+
# BCV-only controls: n_lambda, lambda_min, n_fold, p_fold, ratio_max.
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
run_example(
|
|
30
|
+
algorithm="slide",
|
|
31
|
+
params=PARAMS,
|
|
32
|
+
data_dir=DATA_DIR,
|
|
33
|
+
data_kind="timeseries",
|
|
34
|
+
pattern="*.csv",
|
|
35
|
+
max_items=10,
|
|
36
|
+
shared_rank=3,
|
|
37
|
+
individual_rank=3,
|
|
38
|
+
target_length=150,
|
|
39
|
+
scaling="zscore",
|
|
40
|
+
output_dir=OUTPUT_DIR,
|
|
41
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
42
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
43
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Detailed Personalized Tucker decomposition example.
|
|
2
|
+
|
|
3
|
+
Each 2-D input is represented as a small tensor internally. This method is most
|
|
4
|
+
useful when multilinear row and column structure is scientifically meaningful.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "pertucker"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"max_itr": 100,
|
|
20
|
+
"tol": 1e-8,
|
|
21
|
+
"rho": 0.0, # Optional local-factor regularization.
|
|
22
|
+
"init_method": "random", # Supported by the vendored PerTucker solver.
|
|
23
|
+
"orthogonal": True,
|
|
24
|
+
"progress": True,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
run_example(
|
|
30
|
+
algorithm="pertucker",
|
|
31
|
+
params=PARAMS,
|
|
32
|
+
data_dir=DATA_DIR,
|
|
33
|
+
data_kind="timeseries",
|
|
34
|
+
pattern="*.csv",
|
|
35
|
+
max_items=10,
|
|
36
|
+
shared_rank=3,
|
|
37
|
+
individual_rank=3,
|
|
38
|
+
target_length=150,
|
|
39
|
+
scaling="zscore",
|
|
40
|
+
output_dir=OUTPUT_DIR,
|
|
41
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
42
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
43
|
+
)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Detailed personalized convolutional dictionary learning example.
|
|
2
|
+
|
|
3
|
+
PerCDL is specialized for one-dimensional time series. Each feature/ROI is
|
|
4
|
+
treated as a signal; it should not be the first choice for FC matrices/images.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "percdl"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"n_steps": 100,
|
|
20
|
+
"n_atoms": 3,
|
|
21
|
+
"atom_length": 24, # Must be shorter than the aligned time series.
|
|
22
|
+
"step_size": 1e-3,
|
|
23
|
+
"sparsity": 0.05,
|
|
24
|
+
"progress": True,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
run_example(
|
|
30
|
+
algorithm="percdl",
|
|
31
|
+
params=PARAMS,
|
|
32
|
+
data_dir=DATA_DIR,
|
|
33
|
+
data_kind="timeseries",
|
|
34
|
+
pattern="*.csv",
|
|
35
|
+
max_items=10,
|
|
36
|
+
shared_rank=3,
|
|
37
|
+
individual_rank=3,
|
|
38
|
+
target_length=150,
|
|
39
|
+
scaling="zscore",
|
|
40
|
+
output_dir=OUTPUT_DIR,
|
|
41
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
42
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
43
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Detailed robust PCA baseline example.
|
|
2
|
+
|
|
3
|
+
The adapter fits low-rank plus sparse structure per item, defines the group mean
|
|
4
|
+
low-rank matrix as shared, and treats deviations from it as individual-specific.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from _common import run_example
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
DATA_ROOT = Path("YOUR_DATA_ROOT")
|
|
13
|
+
DATA_DIR = DATA_ROOT / "BOLD" / "full_signal"
|
|
14
|
+
TRUE_SHARED_DIR = DATA_ROOT / "BOLD" / "shared_signal"
|
|
15
|
+
TRUE_INDIVIDUAL_DIR = DATA_ROOT / "BOLD" / "individual_signal"
|
|
16
|
+
OUTPUT_DIR = Path(__file__).resolve().parents[1] / "example_outputs" / "robust_pca"
|
|
17
|
+
|
|
18
|
+
PARAMS = {
|
|
19
|
+
"outer_epochs": 100,
|
|
20
|
+
"lbd_s_outer": 0.02, # Sparse-component shrinkage.
|
|
21
|
+
"rho": 0.95, # Continuation factor used by the robust solver.
|
|
22
|
+
"device": "cpu",
|
|
23
|
+
"progress": True,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
run_example(
|
|
29
|
+
algorithm="robust_pca",
|
|
30
|
+
params=PARAMS,
|
|
31
|
+
data_dir=DATA_DIR,
|
|
32
|
+
data_kind="timeseries",
|
|
33
|
+
pattern="*.csv",
|
|
34
|
+
max_items=10,
|
|
35
|
+
shared_rank=3,
|
|
36
|
+
individual_rank=3,
|
|
37
|
+
target_length=150,
|
|
38
|
+
scaling="zscore",
|
|
39
|
+
output_dir=OUTPUT_DIR,
|
|
40
|
+
true_shared_dir=TRUE_SHARED_DIR,
|
|
41
|
+
true_individual_dir=TRUE_INDIVIDUAL_DIR,
|
|
42
|
+
)
|