indi-net-extract 0.1.0.dev0__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.
Files changed (37) hide show
  1. indi_net_extract-0.1.0.dev0/CHANGELOG.md +11 -0
  2. indi_net_extract-0.1.0.dev0/LICENSE +30 -0
  3. indi_net_extract-0.1.0.dev0/MANIFEST.in +4 -0
  4. indi_net_extract-0.1.0.dev0/PKG-INFO +158 -0
  5. indi_net_extract-0.1.0.dev0/README.md +137 -0
  6. indi_net_extract-0.1.0.dev0/THIRD_PARTY_NOTICES.md +30 -0
  7. indi_net_extract-0.1.0.dev0/docs/distribution.md +55 -0
  8. indi_net_extract-0.1.0.dev0/docs/methods.md +31 -0
  9. indi_net_extract-0.1.0.dev0/docs/validation.md +35 -0
  10. indi_net_extract-0.1.0.dev0/examples/batch_extraction.py +26 -0
  11. indi_net_extract-0.1.0.dev0/examples/compare_postprocessing.py +27 -0
  12. indi_net_extract-0.1.0.dev0/pyproject.toml +30 -0
  13. indi_net_extract-0.1.0.dev0/setup.cfg +4 -0
  14. indi_net_extract-0.1.0.dev0/src/indi_net_extract.egg-info/PKG-INFO +158 -0
  15. indi_net_extract-0.1.0.dev0/src/indi_net_extract.egg-info/SOURCES.txt +35 -0
  16. indi_net_extract-0.1.0.dev0/src/indi_net_extract.egg-info/dependency_links.txt +1 -0
  17. indi_net_extract-0.1.0.dev0/src/indi_net_extract.egg-info/requires.txt +4 -0
  18. indi_net_extract-0.1.0.dev0/src/indi_net_extract.egg-info/top_level.txt +1 -0
  19. indi_net_extract-0.1.0.dev0/src/indinetextract/__init__.py +13 -0
  20. indi_net_extract-0.1.0.dev0/src/indinetextract/_algorithms/__init__.py +1 -0
  21. indi_net_extract-0.1.0.dev0/src/indinetextract/_algorithms/dual_regression.py +148 -0
  22. indi_net_extract-0.1.0.dev0/src/indinetextract/_algorithms/gig_ica.py +412 -0
  23. indi_net_extract-0.1.0.dev0/src/indinetextract/_io.py +302 -0
  24. indi_net_extract-0.1.0.dev0/src/indinetextract/_types.py +114 -0
  25. indi_net_extract-0.1.0.dev0/src/indinetextract/_validation.py +124 -0
  26. indi_net_extract-0.1.0.dev0/src/indinetextract/_version.py +1 -0
  27. indi_net_extract-0.1.0.dev0/src/indinetextract/batch.py +218 -0
  28. indi_net_extract-0.1.0.dev0/src/indinetextract/evaluation.py +129 -0
  29. indi_net_extract-0.1.0.dev0/src/indinetextract/extraction.py +326 -0
  30. indi_net_extract-0.1.0.dev0/src/indinetextract/postprocessing.py +391 -0
  31. indi_net_extract-0.1.0.dev0/tests/__init__.py +1 -0
  32. indi_net_extract-0.1.0.dev0/tests/helpers.py +151 -0
  33. indi_net_extract-0.1.0.dev0/tests/test_batch.py +157 -0
  34. indi_net_extract-0.1.0.dev0/tests/test_extraction_numerics.py +146 -0
  35. indi_net_extract-0.1.0.dev0/tests/test_postprocess.py +244 -0
  36. indi_net_extract-0.1.0.dev0/tests/test_results_io.py +155 -0
  37. indi_net_extract-0.1.0.dev0/tests/validate_distribution.py +100 -0
@@ -0,0 +1,11 @@
1
+ # 更新记录
2
+
3
+ ## 0.1.0.dev0
4
+
5
+ - 初始开发版本:模板引导的双回归β和独立Python GIG-ICA。
6
+ - 支持按被试批处理、两层并行参数、连续结果保存与重新载入。
7
+ - 提供空间平滑、有限有符号Top-N、精确模板Dice及网络重叠比例。
8
+ - 分发名为indi-net-extract,导入名为indinetextract。
9
+ - 源码包补齐文档、示例和完整测试附件;构建与复查步骤见[分发说明](docs/distribution.md)。
10
+ - 许可证元数据采用标准SPDX表达式和project.license-files,最低构建依赖更新为setuptools 77.0.3。
11
+ - 尚未发布到PyPI;验证范围见docs/validation.md。
@@ -0,0 +1,30 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, indinetextract contributors
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice,
10
+ this list of conditions and the following disclaimer.
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+ 3. Neither the name of the copyright holder nor the names of its contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ The GIG-ICA source additionally retains its original notice; see
30
+ THIRD_PARTY_NOTICES.md and src/indinetextract/_algorithms/gig_ica.py.
@@ -0,0 +1,4 @@
1
+ include README.md CHANGELOG.md
2
+ include docs/methods.md docs/validation.md docs/distribution.md
3
+ recursive-include examples *.py
4
+ recursive-include tests *.py
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: indi-net-extract
3
+ Version: 0.1.0.dev0
4
+ Summary: Template-guided individual network extraction and spatial overlap evaluation
5
+ License-Expression: BSD-3-Clause
6
+ Project-URL: Source, https://github.com/sonia1maslova/indi-net-extract
7
+ Project-URL: Documentation, https://github.com/sonia1maslova/indi-net-extract/blob/main/README.md
8
+ Project-URL: Issues, https://github.com/sonia1maslova/indi-net-extract/issues
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ License-File: THIRD_PARTY_NOTICES.md
16
+ Requires-Dist: numpy>=1.26
17
+ Requires-Dist: scipy>=1.11
18
+ Requires-Dist: nibabel>=5.2
19
+ Requires-Dist: threadpoolctl>=3.1
20
+ Dynamic: license-file
21
+
22
+ # IndiNetExtract
23
+
24
+ Python分发名(安装名):`indi-net-extract`。Python导入名和源码包目录:`indinetextract`。
25
+
26
+ 模板引导的个体网络提取工具包,开发初版 `0.1.0.dev0`。目前提供Python源码,尚未发布到PyPI。
27
+
28
+ 输入被试ID列表、逐项对应的静息态影像路径,以及全体共用的模板和mask。输出每名被试的连续网络图、时间序列及运行记录。支持经典双回归β和独立NumPy/SciPy GIG-ICA。
29
+
30
+ **每名被试只输入一份已经准备好的4D NIfTI。** 数据清洗、扫描标准化、拼接和空间配准在包外完成。批处理列表表示不同被试,不表示要拼接的扫描。算法内部所需的中心化、白化和双回归时间序列归一化仍保留。
31
+
32
+ ## 从源码安装
33
+
34
+ 当前为开发初版,尚未发布到PyPI。可从本仓库安装:
35
+
36
+ ```bash
37
+ git clone https://github.com/sonia1maslova/indi-net-extract.git
38
+ cd indi-net-extract
39
+ python -m pip install .
40
+ ```
41
+
42
+ ## 快速使用
43
+
44
+ 在已具备NumPy、SciPy、NiBabel、threadpoolctl的环境中,将本包 `src` 加入 `PYTHONPATH`,或安装本地构建产物。已测试的软件版本和验证边界见 `docs/validation.md`;以下示例不下载或修改数据。
45
+
46
+ 安装已下载的wheel时,文件名中的分发名按打包规则写成 `indi_net_extract`:
47
+
48
+ ```bash
49
+ python -m pip install /path/to/indi_net_extract-0.1.0.dev0-py3-none-any.whl
50
+ ```
51
+
52
+ 安装后仍使用 `from indinetextract import ...`。分发名中的连字符不用于Python导入语句。
53
+
54
+ ```python
55
+ from indinetextract import extract_batch
56
+
57
+ def main():
58
+ batch = extract_batch(
59
+ subject_ids=["sub-001", "sub-002"],
60
+ fmri_paths=[
61
+ "/data/sub-001/rest_preprocessed.nii.gz",
62
+ "/data/sub-002/rest_preprocessed.nii.gz",
63
+ ],
64
+ templates="/data/templates.nii.gz",
65
+ mask="/data/analysis_mask.nii.gz",
66
+ output_root="/results/gig_ica",
67
+ method="gig_ica",
68
+ n_jobs=2,
69
+ n_threads=2,
70
+ )
71
+ print(batch.summary)
72
+
73
+ if __name__ == "__main__":
74
+ main()
75
+ ```
76
+
77
+ 并行采用独立进程,脚本需要上面的 `__main__` 保护。只处理一名时,也传入长度为1的两个列表。输入文件名不必含被试ID;包按列表位置配对,不推测文件属于谁。
78
+
79
+ | 参数 | 含义 |
80
+ | --- | --- |
81
+ | `subject_ids` | 非空且唯一的字符串ID列表 |
82
+ | `fmri_paths` | 等长路径列表,每条路径是一名被试的一份4D影像 |
83
+ | `templates` | 同一份4D空间模板,第四维为K个成分 |
84
+ | `mask` | 同一份3D二值分析mask |
85
+ | `method` | `"dual_regression"` 或 `"gig_ica"` |
86
+ | `n_jobs=1` | 最多同时处理的被试数,即进程数 |
87
+ | `n_threads=2` | 每名被试数值计算的线程预算 |
88
+ | `label="extraction"` | 被试目录下的本次输出标签;可用不同标签区分方法、模板或测量日 |
89
+ | `on_error="continue"` | 记录失败后继续;`"raise"` 表示停止提交新被试,等待正在运行的被试结束后报错 |
90
+ | `work_dir=None` | 可选临时存储目录;每名被试使用独立临时子目录 |
91
+
92
+ 例如 `n_jobs=3, n_threads=2` 表示最多3名被试同时拟合,每名的数值运算预算为2线程。它不保证总内存足够;GIG-ICA仍需白化和SVD工作内存。默认串行执行,不自动增加进程。
93
+
94
+ ## 输出
95
+
96
+ ```text
97
+ output_root/
98
+ _batches/<batch_id>/
99
+ inputs.tsv # 保存原ID—影像配对
100
+ summary.tsv # 顺序与输入一致,包含状态及失败原因
101
+ metadata.json # 共用设置、环境及源码指纹
102
+ sub-001/extraction/
103
+ continuous_components.nii.gz # X×Y×Z×K,连续成分
104
+ timecourses.tsv # T×K,行是时间点,无标题行
105
+ components.tsv # 0起始图像索引与成分ID
106
+ mask.nii.gz
107
+ metadata.json
108
+ sub-002/extraction/
109
+ ...
110
+ ```
111
+
112
+ 连续图的第四维是**成分**,不是时间;第i张图对应第i个模板。默认成分ID为C1…CK。双回归输出空间β,GIG-ICA输出成分权重,两者不当作统计Z或概率。
113
+
114
+ 一名完成后立即保存。`BatchResult`只返回轻量记录和文件路径,不把全体影像留在内存。失败被试不产生一个伪成功的结果目录。默认不覆盖已有结果;显式调用结果对象的 `save(overwrite=True)` 时,旧目录改名为备份并保留。
115
+
116
+ ## 独立后处理与模板Dice
117
+
118
+ 已经提取好的连续图可以重新载入,改变平滑或Top-N时不用重新拟合:
119
+
120
+ ```python
121
+ from indinetextract import NetworkResult, postprocess_maps, template_dice, overlap_fraction
122
+
123
+ fit = NetworkResult.load("/results/gig_ica/sub-001/extraction")
124
+ binary = postprocess_maps(
125
+ fit,
126
+ fwhm_mm=6,
127
+ count_reference="/data/fixed_binary_reference.nii.gz",
128
+ )
129
+ binary.save("/results/gig_ica", label="fwhm_6mm")
130
+
131
+ dice = template_dice(binary, reference="/data/fixed_binary_reference.nii.gz")
132
+ print(dice.per_component, dice.mean_dice)
133
+ dice.save("/results/gig_ica", label="fwhm_6mm/template_dice")
134
+
135
+ pleiotropy = overlap_fraction(binary) # 3D NIfTI对象,值为所选成分比例
136
+ ```
137
+
138
+ - `count_reference`必须是二值图,在mask内计数得到每成分N。也可以改用显式的 `top_n=[...]`,两者必须二选一。
139
+ - 用于提取的模板允许连续值;用于计数和Dice的参考图必须明确为0/1。切换提取模板不自动改变N。
140
+ - 平滑使用 `G(M*f)/G(M)`,仅沿空间维,保留原mask。每个宽度都从原始连续图开始。NIfTI空间单位unknown时按mm解释并记录;正宽度平滑拒绝剪切网格。
141
+ - Top-N按有限的有符号数值降序选严格N个,允许零值和负值;并列按原始Fortran体素索引。候选不足时报错,不自动缩小N。
142
+ - Dice矩阵行是个体成分,列是参考成分;对应分数是对角线。不自动换序、翻符号或选择最佳配对。
143
+ - 单侧为空时Dice为0,双侧为空为NaN;存在无效对应成分时完整K成分均值为NaN。JSON中缺失数值保存为null,TSV中为nan。
144
+ - `overlap_fraction`为K张二值图的逐体素平均;它不自动构成统计显著性检验。
145
+
146
+ ## 输入约束与验证边界
147
+
148
+ 所有影像必须事先对齐,空间形状一致,affine数值在记录的容差内一致。mask显式提供,保持不变。mask外不参与计算;mask内NaN/Inf或时间常量BOLD序列会报错,包不自动插补或删除体素。
149
+
150
+ 独立Python GIG核心保留原算法源码许可与控制流程。此前合成数据及三名真实被试有MATLAB对照,真实数据不是所有数值严格相等。此包封装的验证范围和具体检查见 [docs/validation.md](docs/validation.md);不能只依据模板Dice较高就判定个体网络科学有效。
151
+
152
+ 当前实际验证使用Python3.13项目环境;其他Python版本和Windows原生并行尚需分别测试。声明最低Python版本不等于所有组合均已测试。
153
+
154
+ 自动单元测试不依赖MATLAB或FSL;本轮另外完成了两种模板的小型FSL对照。更新算法一致性结论时,应保留输入、源码、参数和数值误差。
155
+
156
+ ## 来源与许可
157
+
158
+ GIG数值核心位于 `_algorithms/gig_ica.py`,来自已有NumPy/SciPy移植;原始来源为GIFT `icatb_gigicar.m`,作者Yuhui Du、Yong Fan。版权与许可保留在文件头及 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。其他初版代码采用BSD-3-Clause许可。
@@ -0,0 +1,137 @@
1
+ # IndiNetExtract
2
+
3
+ Python分发名(安装名):`indi-net-extract`。Python导入名和源码包目录:`indinetextract`。
4
+
5
+ 模板引导的个体网络提取工具包,开发初版 `0.1.0.dev0`。目前提供Python源码,尚未发布到PyPI。
6
+
7
+ 输入被试ID列表、逐项对应的静息态影像路径,以及全体共用的模板和mask。输出每名被试的连续网络图、时间序列及运行记录。支持经典双回归β和独立NumPy/SciPy GIG-ICA。
8
+
9
+ **每名被试只输入一份已经准备好的4D NIfTI。** 数据清洗、扫描标准化、拼接和空间配准在包外完成。批处理列表表示不同被试,不表示要拼接的扫描。算法内部所需的中心化、白化和双回归时间序列归一化仍保留。
10
+
11
+ ## 从源码安装
12
+
13
+ 当前为开发初版,尚未发布到PyPI。可从本仓库安装:
14
+
15
+ ```bash
16
+ git clone https://github.com/sonia1maslova/indi-net-extract.git
17
+ cd indi-net-extract
18
+ python -m pip install .
19
+ ```
20
+
21
+ ## 快速使用
22
+
23
+ 在已具备NumPy、SciPy、NiBabel、threadpoolctl的环境中,将本包 `src` 加入 `PYTHONPATH`,或安装本地构建产物。已测试的软件版本和验证边界见 `docs/validation.md`;以下示例不下载或修改数据。
24
+
25
+ 安装已下载的wheel时,文件名中的分发名按打包规则写成 `indi_net_extract`:
26
+
27
+ ```bash
28
+ python -m pip install /path/to/indi_net_extract-0.1.0.dev0-py3-none-any.whl
29
+ ```
30
+
31
+ 安装后仍使用 `from indinetextract import ...`。分发名中的连字符不用于Python导入语句。
32
+
33
+ ```python
34
+ from indinetextract import extract_batch
35
+
36
+ def main():
37
+ batch = extract_batch(
38
+ subject_ids=["sub-001", "sub-002"],
39
+ fmri_paths=[
40
+ "/data/sub-001/rest_preprocessed.nii.gz",
41
+ "/data/sub-002/rest_preprocessed.nii.gz",
42
+ ],
43
+ templates="/data/templates.nii.gz",
44
+ mask="/data/analysis_mask.nii.gz",
45
+ output_root="/results/gig_ica",
46
+ method="gig_ica",
47
+ n_jobs=2,
48
+ n_threads=2,
49
+ )
50
+ print(batch.summary)
51
+
52
+ if __name__ == "__main__":
53
+ main()
54
+ ```
55
+
56
+ 并行采用独立进程,脚本需要上面的 `__main__` 保护。只处理一名时,也传入长度为1的两个列表。输入文件名不必含被试ID;包按列表位置配对,不推测文件属于谁。
57
+
58
+ | 参数 | 含义 |
59
+ | --- | --- |
60
+ | `subject_ids` | 非空且唯一的字符串ID列表 |
61
+ | `fmri_paths` | 等长路径列表,每条路径是一名被试的一份4D影像 |
62
+ | `templates` | 同一份4D空间模板,第四维为K个成分 |
63
+ | `mask` | 同一份3D二值分析mask |
64
+ | `method` | `"dual_regression"` 或 `"gig_ica"` |
65
+ | `n_jobs=1` | 最多同时处理的被试数,即进程数 |
66
+ | `n_threads=2` | 每名被试数值计算的线程预算 |
67
+ | `label="extraction"` | 被试目录下的本次输出标签;可用不同标签区分方法、模板或测量日 |
68
+ | `on_error="continue"` | 记录失败后继续;`"raise"` 表示停止提交新被试,等待正在运行的被试结束后报错 |
69
+ | `work_dir=None` | 可选临时存储目录;每名被试使用独立临时子目录 |
70
+
71
+ 例如 `n_jobs=3, n_threads=2` 表示最多3名被试同时拟合,每名的数值运算预算为2线程。它不保证总内存足够;GIG-ICA仍需白化和SVD工作内存。默认串行执行,不自动增加进程。
72
+
73
+ ## 输出
74
+
75
+ ```text
76
+ output_root/
77
+ _batches/<batch_id>/
78
+ inputs.tsv # 保存原ID—影像配对
79
+ summary.tsv # 顺序与输入一致,包含状态及失败原因
80
+ metadata.json # 共用设置、环境及源码指纹
81
+ sub-001/extraction/
82
+ continuous_components.nii.gz # X×Y×Z×K,连续成分
83
+ timecourses.tsv # T×K,行是时间点,无标题行
84
+ components.tsv # 0起始图像索引与成分ID
85
+ mask.nii.gz
86
+ metadata.json
87
+ sub-002/extraction/
88
+ ...
89
+ ```
90
+
91
+ 连续图的第四维是**成分**,不是时间;第i张图对应第i个模板。默认成分ID为C1…CK。双回归输出空间β,GIG-ICA输出成分权重,两者不当作统计Z或概率。
92
+
93
+ 一名完成后立即保存。`BatchResult`只返回轻量记录和文件路径,不把全体影像留在内存。失败被试不产生一个伪成功的结果目录。默认不覆盖已有结果;显式调用结果对象的 `save(overwrite=True)` 时,旧目录改名为备份并保留。
94
+
95
+ ## 独立后处理与模板Dice
96
+
97
+ 已经提取好的连续图可以重新载入,改变平滑或Top-N时不用重新拟合:
98
+
99
+ ```python
100
+ from indinetextract import NetworkResult, postprocess_maps, template_dice, overlap_fraction
101
+
102
+ fit = NetworkResult.load("/results/gig_ica/sub-001/extraction")
103
+ binary = postprocess_maps(
104
+ fit,
105
+ fwhm_mm=6,
106
+ count_reference="/data/fixed_binary_reference.nii.gz",
107
+ )
108
+ binary.save("/results/gig_ica", label="fwhm_6mm")
109
+
110
+ dice = template_dice(binary, reference="/data/fixed_binary_reference.nii.gz")
111
+ print(dice.per_component, dice.mean_dice)
112
+ dice.save("/results/gig_ica", label="fwhm_6mm/template_dice")
113
+
114
+ pleiotropy = overlap_fraction(binary) # 3D NIfTI对象,值为所选成分比例
115
+ ```
116
+
117
+ - `count_reference`必须是二值图,在mask内计数得到每成分N。也可以改用显式的 `top_n=[...]`,两者必须二选一。
118
+ - 用于提取的模板允许连续值;用于计数和Dice的参考图必须明确为0/1。切换提取模板不自动改变N。
119
+ - 平滑使用 `G(M*f)/G(M)`,仅沿空间维,保留原mask。每个宽度都从原始连续图开始。NIfTI空间单位unknown时按mm解释并记录;正宽度平滑拒绝剪切网格。
120
+ - Top-N按有限的有符号数值降序选严格N个,允许零值和负值;并列按原始Fortran体素索引。候选不足时报错,不自动缩小N。
121
+ - Dice矩阵行是个体成分,列是参考成分;对应分数是对角线。不自动换序、翻符号或选择最佳配对。
122
+ - 单侧为空时Dice为0,双侧为空为NaN;存在无效对应成分时完整K成分均值为NaN。JSON中缺失数值保存为null,TSV中为nan。
123
+ - `overlap_fraction`为K张二值图的逐体素平均;它不自动构成统计显著性检验。
124
+
125
+ ## 输入约束与验证边界
126
+
127
+ 所有影像必须事先对齐,空间形状一致,affine数值在记录的容差内一致。mask显式提供,保持不变。mask外不参与计算;mask内NaN/Inf或时间常量BOLD序列会报错,包不自动插补或删除体素。
128
+
129
+ 独立Python GIG核心保留原算法源码许可与控制流程。此前合成数据及三名真实被试有MATLAB对照,真实数据不是所有数值严格相等。此包封装的验证范围和具体检查见 [docs/validation.md](docs/validation.md);不能只依据模板Dice较高就判定个体网络科学有效。
130
+
131
+ 当前实际验证使用Python3.13项目环境;其他Python版本和Windows原生并行尚需分别测试。声明最低Python版本不等于所有组合均已测试。
132
+
133
+ 自动单元测试不依赖MATLAB或FSL;本轮另外完成了两种模板的小型FSL对照。更新算法一致性结论时,应保留输入、源码、参数和数值误差。
134
+
135
+ ## 来源与许可
136
+
137
+ GIG数值核心位于 `_algorithms/gig_ica.py`,来自已有NumPy/SciPy移植;原始来源为GIFT `icatb_gigicar.m`,作者Yuhui Du、Yong Fan。版权与许可保留在文件头及 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。其他初版代码采用BSD-3-Clause许可。
@@ -0,0 +1,30 @@
1
+ # Third-party source notices
2
+
3
+ The GIG-ICA Python core retains the following original notice. Original source: GIFT icatb_gigicar.m; source SHA256: 6a0bbf665524d0122686ce6416d06350cb21d71f90460c282aa539f76803773c.
4
+
5
+ Copyright (c) 2012 Yuhui DU and Yong FAN
6
+ All rights reserved.
7
+
8
+ Redistribution and use in source or any other forms, with or without
9
+ modification, are permitted provided that the following conditions are met:
10
+
11
+ * Redistributions of source code must retain the above copyright notice,
12
+ this list of conditions and the following disclaimer.
13
+ * Redistributions in any other form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+ * Neither the names of the copyright holders nor the names of future
17
+ contributors may be used to endorse or promote products derived from this
18
+ software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,55 @@
1
+ # 构建与检查分发文件
2
+
3
+ 源码发行包(sdist,扩展名为 `.tar.gz`)保留源码和开发附件。安装包(wheel,扩展名为 `.whl`)用于安装运行库。两者用途不同,因此包含的文件也不同。
4
+
5
+ ## 源码包附件清单
6
+
7
+ `MANIFEST.in` 指定需要额外收入源码包的文件:
8
+
9
+ | 文件或目录 | 内容 |
10
+ | --- | --- |
11
+ | `README.md`、`CHANGELOG.md` | 使用入口和更新记录 |
12
+ | `docs/methods.md` | 方法与参数说明 |
13
+ | `docs/validation.md` | 已完成的验证及其边界 |
14
+ | `docs/distribution.md` | 本构建说明 |
15
+ | `examples/*.py` | 两个使用示例,需要用户提供输入影像和输出路径 |
16
+ | `tests/*.py` | 四个测试模块、`helpers.py`、`__init__.py` 和 `validate_distribution.py` |
17
+
18
+ `pyproject.toml` 声明运行依赖、构建依赖和许可证;构建工具同时收入 `src/indinetextract/` 下的运行源码。`LICENSE` 和 `THIRD_PARTY_NOTICES.md` 由 `project.license-files` 指定,同时进入源码包和 wheel。
19
+
20
+ wheel 包含运行库、分发元数据和许可证文件。文档、示例和测试保留在源码包中,不随 wheel 安装。
21
+
22
+ ## 构建和格式检查
23
+
24
+ 在维护者的开发环境中安装构建工具,然后从源码根目录执行:
25
+
26
+ ```bash
27
+ python -m pip install build twine
28
+ python -m build
29
+ python -m twine check --strict dist/*
30
+ ```
31
+
32
+ 构建依赖要求 `setuptools>=77.0.3`,以支持标准许可证标识(SPDX 表达式)和 `project.license-files`。当前许可证表达式为 `BSD-3-Clause`。配置格式更新不改变许可证正文和第三方声明。
33
+
34
+ 默认的 `python -m build` 先生成源码包,再从源码包构建 wheel。已有构建依赖的受控环境可使用 `python -m build --no-isolation`,直接使用当前环境中的工具。
35
+
36
+ `twine check` 检查分发元数据和 README 格式,不验证算法,也不会上传文件。
37
+
38
+ ## 从源码包复查
39
+
40
+ 将生成的 `.tar.gz` 解压到一个新目录,进入包含 `pyproject.toml` 的目录,在已安装运行依赖的环境中执行:
41
+
42
+ ```bash
43
+ python -m pip install .
44
+ python -m unittest discover -s tests -t . -v
45
+ ```
46
+
47
+ 测试使用合成数据,不需要研究影像、MATLAB 或 FSL。命令在解压目录中执行,可以检查源码包是否带齐测试模块及其辅助文件。
48
+
49
+ 若需要检查 wheel 中的两进程 GIG-ICA 和结果保存/载入,先安装对应 wheel,再从同一解压目录执行以下命令;输出目录必须尚不存在:
50
+
51
+ ```bash
52
+ python -m tests.validate_distribution --output-root ./synthetic-distribution-check
53
+ ```
54
+
55
+ 此命令默认只用合成数据。可选参数 `--fsl-dir` 用于额外的 FSL 对照,具体范围见 [验证说明](validation.md)。构建、格式检查、单元测试和上传是不同步骤;上述命令均不发布到 PyPI。
@@ -0,0 +1,31 @@
1
+ # 方法与数据约定
2
+
3
+ ## 输入与方法分开
4
+
5
+ 每名被试提供一份已准备好的4D静息态NIfTI。清洗、逐扫描标准化、拼接和配准由调用者完成。包只在共同mask内提取数据,并按各算法本身的要求中心化、白化或归一化。没有 `run_normalization` 或扫描拼接参数。
6
+
7
+ 内部矩阵为BOLD `T×V`、模板 `V×K`、个体图 `V×K`、时间序列 `T×K`。mask内体素按NIfTI Fortran索引排列,并按同一顺序映射回图像。成分顺序从模板保留到输出,不自动匹配或翻转符号。
8
+
9
+ ## 经典双回归
10
+
11
+ 第一步以K张模板为共同解释变量,估计各成分随时间变化的系数;第二步以这些时间序列为共同解释变量,估计每个体素的成分β。
12
+
13
+ 实现沿用项目已对照的经典路线:模板空间去均值及总体标准差缩放;输入整体时间去均值;第一步时间序列去均值并按样本标准差 `ddof=1` 归一化;第二步包含截距。该设置对应FSL `des_norm=1`。输出是连续β,不是统计Z;没有空间先验惩罚或时间点加权。
14
+
15
+ ## GIG-ICA
16
+
17
+ 采用现有独立NumPy/SciPy移植,保留作者算法的白化、阈值与回退、模板标准化、非高斯性和模板对应目标,以及迭代停止规则。默认使用已对照的SVD伪逆路线。没有另外加入跨成分正交约束。
18
+
19
+ 输入加载使用临时memmap控制加载副本;白化和SVD仍需要内存,不能把该实现理解为完全在磁盘上运算。逐被试完成后保存结果,批次只返回状态和路径。
20
+
21
+ ## 平滑与选取
22
+
23
+ 平滑在连续图提取后、二值化前执行:`G(M*f)/G(M)`,保留原mask,高斯核截断4倍标准差。每个宽度从同一份原始连续图独立计算,只沿三个空间轴平滑。
24
+
25
+ 固定Top-N按有限带符号值降序选取;零值、负值可以入选。并列时按原始Fortran体素索引排序。每成分必须选足N,N来自显式列表或固定二值参考在mask内的计数。
26
+
27
+ ## 评价
28
+
29
+ 精确Dice为 `2×交集体素数/(个体体素数+参考体素数)`。完整矩阵的行是个体成分,列是参考成分;对应分数取对角线。单侧为空为0,双侧为空为NaN,不能静默忽略无效成分后报告完整K成分均值。
30
+
31
+ `overlap_fraction` 是K张二值图的逐体素平均。固定mask、K和各成分N时,全mask平均值固定,因此不是有个体差异的总体指标。
@@ -0,0 +1,35 @@
1
+ # 验证范围
2
+
3
+ 版本:0.1.0.dev0。验证日期:2026-11-10。本页概述已完成的检查和仍未验证的范围;首次公开仓库不会自动增加已验证的平台或数据范围。
4
+
5
+ ## 初版检查
6
+
7
+ - 54项单元及接口测试通过:批处理10项、提取数值12项、后处理和Dice 21项、保存/载入11项。
8
+ - 小型合成输入中,双回归串行和两进程结果一致;wheel中的两进程GIG-ICA、平滑、Top-N及结果保存/回读通过。
9
+ - 两组小型FSL双回归对照通过。连续与二值模板的β最大绝对差分别为1.0529613776733004e-6和1.190774973361397e-6。
10
+ - 分发名改为indi-net-extract后,独立目标目录安装、元数据、导入和小型并行检查通过;该次修改没有重跑上述全部54项检查或FSL。
11
+
12
+ ## 独立GIG-ICA核心
13
+
14
+ 已有11项核心检查、6组合成数据与未修改作者MATLAB核心的独立对照,以及原研究队列中预先选定的三名真实被试对照。真实被试连续成分的最低空间相关为0.997386、0.999585、0.999906,最大单成分相对误差为7.23%、2.88%、1.37%。结果接近,但没有全部达到严格数值等价标准。
15
+
16
+ MATLAB复算、白化及求解器诊断支持近零特征值的数值敏感性是差异来源之一,尚未证明它是唯一原因。不能只凭高相关或高Dice认定逐值一致,也不能把核心的历史验证当作封装后真实大样本的完整验证。
17
+
18
+ ## 实际测试环境
19
+
20
+ Python 3.13.14;NumPy 2.2.6;SciPy 1.15.3;NiBabel 5.4.2;threadpoolctl 3.6.0。FSL独立对照使用6.0.4。MATLAB和FSL用于外部对照,不是工具运行依赖。
21
+
22
+ 声明Python >=3.11不等于所有这些版本都已测试。其他Python/数值库组合、Windows原生多进程、真实大样本内存峰值和长时运行仍待验证。
23
+
24
+ ## 在自己的环境复查
25
+
26
+ 先安装运行依赖,再从仓库根目录执行:
27
+
28
+ ```bash
29
+ python -m pip install .
30
+ python -m unittest discover -s tests -t . -v
31
+ ```
32
+
33
+ 本仓库的单元测试使用合成数据,不需要下载研究影像,不调用MATLAB或FSL。可选的分发检查脚本是tests/validate_distribution.py;它要求使用新输出目录。
34
+
35
+ 源码包也包含上述测试模块及其辅助文件。构建、格式检查和从解压目录复查的步骤见[分发说明](distribution.md)。`tests.validate_distribution`不传`--fsl-dir`时只执行合成数据检查,传入该参数时再增加FSL对照。
@@ -0,0 +1,26 @@
1
+ """Run a batch from already prepared images; no raw-data preprocessing."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+
7
+ from indinetextract import extract_batch
8
+
9
+
10
+ def main():
11
+ parser = argparse.ArgumentParser(description=__doc__)
12
+ parser.add_argument("--subject-ids", nargs="+", required=True)
13
+ parser.add_argument("--fmri-paths", nargs="+", required=True)
14
+ parser.add_argument("--templates", required=True)
15
+ parser.add_argument("--mask", required=True)
16
+ parser.add_argument("--output-root", required=True)
17
+ parser.add_argument("--method", choices=["dual_regression", "gig_ica"], required=True)
18
+ parser.add_argument("--n-jobs", type=int, default=1)
19
+ parser.add_argument("--n-threads", type=int, default=2)
20
+ args = parser.parse_args()
21
+ result = extract_batch(**vars(args))
22
+ print(json.dumps(result.summary, indent=2, ensure_ascii=False))
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
@@ -0,0 +1,27 @@
1
+ """Re-use one saved fit for independent smoothing widths and exact Dice."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+
6
+ from indinetextract import NetworkResult, postprocess_maps, template_dice
7
+
8
+
9
+ def main():
10
+ parser = argparse.ArgumentParser(description=__doc__)
11
+ parser.add_argument("--extraction", required=True)
12
+ parser.add_argument("--binary-reference", required=True)
13
+ parser.add_argument("--output-root", required=True)
14
+ parser.add_argument("--fwhm-mm", type=float, nargs="+", default=[0, 2, 4, 6])
15
+ args = parser.parse_args()
16
+ fit = NetworkResult.load(args.extraction)
17
+ for width in args.fwhm_mm:
18
+ label = "fwhm_" + format(width, "g") + "mm"
19
+ binary = postprocess_maps(fit, fwhm_mm=width, count_reference=args.binary_reference)
20
+ binary.save(args.output_root, label=label)
21
+ result = template_dice(binary, reference=args.binary_reference)
22
+ result.save(args.output_root, label=label + "/template_dice")
23
+ print(width, result.mean_dice)
24
+
25
+
26
+ if __name__ == "__main__":
27
+ main()
@@ -0,0 +1,30 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0.3", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "indi-net-extract"
7
+ version = "0.1.0.dev0"
8
+ description = "Template-guided individual network extraction and spatial overlap evaluation"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "BSD-3-Clause"
12
+ license-files = ["LICENSE", "THIRD_PARTY_NOTICES.md"]
13
+ dependencies = ["numpy>=1.26", "scipy>=1.11", "nibabel>=5.2", "threadpoolctl>=3.1"]
14
+ classifiers = [
15
+ "Development Status :: 2 - Pre-Alpha",
16
+ "Programming Language :: Python :: 3",
17
+ "Topic :: Scientific/Engineering :: Medical Science Apps.",
18
+ ]
19
+
20
+ [tool.setuptools.packages.find]
21
+ where = ["src"]
22
+
23
+ [tool.setuptools]
24
+ include-package-data = true
25
+
26
+
27
+ [project.urls]
28
+ Source = "https://github.com/sonia1maslova/indi-net-extract"
29
+ Documentation = "https://github.com/sonia1maslova/indi-net-extract/blob/main/README.md"
30
+ Issues = "https://github.com/sonia1maslova/indi-net-extract/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+