junifer 0.0.7.dev105__py3-none-any.whl → 0.0.7.dev111__py3-none-any.whl
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.
- junifer/_version.py +2 -2
- junifer/onthefly/read_transform.py +70 -4
- junifer/onthefly/tests/test_read_transform.py +84 -0
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/METADATA +1 -1
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/RECORD +10 -10
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/WHEEL +0 -0
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/licenses/AUTHORS.rst +0 -0
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/licenses/LICENSE.md +0 -0
- {junifer-0.0.7.dev105.dist-info → junifer-0.0.7.dev111.dist-info}/top_level.txt +0 -0
junifer/_version.py
CHANGED
@@ -17,5 +17,5 @@ __version__: str
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
18
18
|
version_tuple: VERSION_TUPLE
|
19
19
|
|
20
|
-
__version__ = version = '0.0.7.
|
21
|
-
__version_tuple__ = version_tuple = (0, 0, 7, '
|
20
|
+
__version__ = version = '0.0.7.dev111'
|
21
|
+
__version_tuple__ = version_tuple = (0, 0, 7, 'dev111')
|
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
from typing import Optional
|
7
7
|
|
8
|
+
import numpy as np
|
8
9
|
import pandas as pd
|
9
10
|
|
10
11
|
from ..typing import StorageLike
|
@@ -19,6 +20,7 @@ def read_transform(
|
|
19
20
|
transform: str,
|
20
21
|
feature_name: Optional[str] = None,
|
21
22
|
feature_md5: Optional[str] = None,
|
23
|
+
nan_policy: Optional[str] = "bypass",
|
22
24
|
transform_args: Optional[tuple] = None,
|
23
25
|
transform_kw_args: Optional[dict] = None,
|
24
26
|
) -> pd.DataFrame:
|
@@ -35,6 +37,16 @@ def read_transform(
|
|
35
37
|
Name of the feature to read (default None).
|
36
38
|
feature_md5 : str, optional
|
37
39
|
MD5 hash of the feature to read (default None).
|
40
|
+
nan_policy : str, optional
|
41
|
+
The policy to handle NaN values (default "ignore").
|
42
|
+
Options are:
|
43
|
+
|
44
|
+
* "bypass": Do nothing and pass NaN values to the transform function.
|
45
|
+
* "drop_element": Drop (skip) elements with NaN values.
|
46
|
+
* "drop_rows": Drop (skip) rows with NaN values.
|
47
|
+
* "drop_columns": Drop (skip) columns with NaN values.
|
48
|
+
* "drop_symmetric": Drop (skip) symmetric pairs with NaN values.
|
49
|
+
|
38
50
|
transform_args : tuple, optional
|
39
51
|
The positional arguments for the callable of ``transform``
|
40
52
|
(default None).
|
@@ -47,6 +59,18 @@ def read_transform(
|
|
47
59
|
pandas.DataFrame
|
48
60
|
The transformed feature as a dataframe.
|
49
61
|
|
62
|
+
Raises
|
63
|
+
------
|
64
|
+
ValueError
|
65
|
+
If ``nan_policy`` is invalid or
|
66
|
+
if *package* is invalid.
|
67
|
+
RuntimeError
|
68
|
+
If *package* is ``bctpy`` and stored data kind is not ``matrix``.
|
69
|
+
ImportError
|
70
|
+
If ``bctpy`` cannot be imported.
|
71
|
+
AttributeError
|
72
|
+
If *function* to be invoked in invalid.
|
73
|
+
|
50
74
|
Notes
|
51
75
|
-----
|
52
76
|
This function has been only tested for:
|
@@ -63,6 +87,18 @@ def read_transform(
|
|
63
87
|
transform_args = transform_args or ()
|
64
88
|
transform_kw_args = transform_kw_args or {}
|
65
89
|
|
90
|
+
if nan_policy not in [
|
91
|
+
"bypass",
|
92
|
+
"drop_element",
|
93
|
+
"drop_rows",
|
94
|
+
"drop_columns",
|
95
|
+
"drop_symmetric",
|
96
|
+
]:
|
97
|
+
raise_error(
|
98
|
+
f"Unknown nan_policy: {nan_policy}",
|
99
|
+
klass=ValueError,
|
100
|
+
)
|
101
|
+
|
66
102
|
# Read storage
|
67
103
|
stored_data = storage.read(
|
68
104
|
feature_name=feature_name, feature_md5=feature_md5
|
@@ -106,22 +142,52 @@ def read_transform(
|
|
106
142
|
except AttributeError as err:
|
107
143
|
raise_error(msg=str(err), klass=AttributeError)
|
108
144
|
|
109
|
-
# Apply function and store
|
145
|
+
# Apply function and store element-wise
|
110
146
|
output_list = []
|
147
|
+
element_list = []
|
111
148
|
logger.debug(
|
112
149
|
f"Computing '{package}.{func_str}' for feature "
|
113
150
|
f"{feature_name or feature_md5} ..."
|
114
151
|
)
|
115
|
-
for
|
152
|
+
for i_element, element in enumerate(stored_data["element"]):
|
153
|
+
t_data = stored_data["data"][:, :, i_element]
|
154
|
+
has_nan = np.isnan(np.min(t_data))
|
155
|
+
if nan_policy == "drop_element" and has_nan:
|
156
|
+
logger.debug(
|
157
|
+
f"Skipping element {element} due to NaN values ..."
|
158
|
+
)
|
159
|
+
continue
|
160
|
+
elif nan_policy == "drop_rows" and has_nan:
|
161
|
+
logger.debug(
|
162
|
+
f"Skipping rows with NaN values in element {element} ..."
|
163
|
+
)
|
164
|
+
t_data = t_data[~np.isnan(t_data).any(axis=1)]
|
165
|
+
elif nan_policy == "drop_columns" and has_nan:
|
166
|
+
logger.debug(
|
167
|
+
f"Skipping columns with NaN values in element {element} "
|
168
|
+
"..."
|
169
|
+
)
|
170
|
+
t_data = t_data[:, ~np.isnan(t_data).any(axis=0)]
|
171
|
+
elif nan_policy == "drop_symmetric":
|
172
|
+
logger.debug(
|
173
|
+
f"Skipping pairs of rows/columns with NaN values in "
|
174
|
+
f"element {element}..."
|
175
|
+
)
|
176
|
+
good_rows = ~np.isnan(t_data).any(axis=1)
|
177
|
+
good_columns = ~np.isnan(t_data).any(axis=0)
|
178
|
+
good_idx = np.logical_and(good_rows, good_columns)
|
179
|
+
t_data = t_data[good_idx][:, good_idx]
|
180
|
+
|
116
181
|
output = func(
|
117
|
-
|
182
|
+
t_data,
|
118
183
|
*transform_args,
|
119
184
|
**transform_kw_args,
|
120
185
|
)
|
121
186
|
output_list.append(output)
|
187
|
+
element_list.append(element)
|
122
188
|
|
123
189
|
# Create dataframe for index
|
124
|
-
idx_df = pd.DataFrame(data=
|
190
|
+
idx_df = pd.DataFrame(data=element_list)
|
125
191
|
# Create multiindex from dataframe
|
126
192
|
logger.debug(
|
127
193
|
"Generating pandas.MultiIndex for feature "
|
@@ -64,6 +64,36 @@ def matrix_storage(tmp_path: Path) -> HDF5FeatureStorage:
|
|
64
64
|
return storage
|
65
65
|
|
66
66
|
|
67
|
+
@pytest.fixture
|
68
|
+
def matrix_storage_with_nan(tmp_path: Path) -> HDF5FeatureStorage:
|
69
|
+
"""Return a HDF5FeatureStorage with matrix data.
|
70
|
+
|
71
|
+
Parameters
|
72
|
+
----------
|
73
|
+
tmp_path : pathlib.Path
|
74
|
+
The path to the test directory.
|
75
|
+
|
76
|
+
"""
|
77
|
+
storage = HDF5FeatureStorage(tmp_path / "matrix_store_nan.hdf5")
|
78
|
+
data = np.arange(36).reshape(3, 3, 4).astype(float)
|
79
|
+
data[1, 1, 2] = np.nan
|
80
|
+
data[1, 2, 2] = np.nan
|
81
|
+
for i in range(4):
|
82
|
+
storage.store(
|
83
|
+
kind="matrix",
|
84
|
+
meta={
|
85
|
+
"element": {"subject": f"test{i + 1}"},
|
86
|
+
"dependencies": [],
|
87
|
+
"marker": {"name": "matrix"},
|
88
|
+
"type": "BOLD",
|
89
|
+
},
|
90
|
+
data=data[:, :, i],
|
91
|
+
col_names=["f1", "f2", "f3"],
|
92
|
+
row_names=["g1", "g2", "g3"],
|
93
|
+
)
|
94
|
+
return storage
|
95
|
+
|
96
|
+
|
67
97
|
def test_incorrect_package(matrix_storage: HDF5FeatureStorage) -> None:
|
68
98
|
"""Test error check for incorrect package name.
|
69
99
|
|
@@ -176,3 +206,57 @@ def test_bctpy_function(
|
|
176
206
|
)
|
177
207
|
assert "Computing" in caplog.text
|
178
208
|
assert "Generating" in caplog.text
|
209
|
+
|
210
|
+
|
211
|
+
@pytest.mark.parametrize(
|
212
|
+
"nan_policy, error_msg",
|
213
|
+
[
|
214
|
+
("drop_element", None),
|
215
|
+
("drop_rows", "square"),
|
216
|
+
("drop_columns", "square"),
|
217
|
+
("drop_symmetric", None),
|
218
|
+
("bypass", "NaNs"),
|
219
|
+
("wrong", "Unknown"),
|
220
|
+
],
|
221
|
+
)
|
222
|
+
def test_bctpy_nans(
|
223
|
+
matrix_storage_with_nan: HDF5FeatureStorage,
|
224
|
+
caplog: pytest.LogCaptureFixture,
|
225
|
+
nan_policy: str,
|
226
|
+
error_msg: str,
|
227
|
+
) -> None:
|
228
|
+
"""Test working function of bctpy.
|
229
|
+
|
230
|
+
Parameters
|
231
|
+
----------
|
232
|
+
matrix_storage_with_nan : HDF5FeatureStorage
|
233
|
+
The HDF5FeatureStorage with matrix data, as fixture.
|
234
|
+
caplog : pytest.LogCaptureFixture
|
235
|
+
The pytest.LogCaptureFixture object.
|
236
|
+
nan_policy : str
|
237
|
+
The NAN policy to test.
|
238
|
+
error_msg : str
|
239
|
+
The expected error message snippet. If None, no error should be raised.
|
240
|
+
|
241
|
+
"""
|
242
|
+
# Skip test if import fails
|
243
|
+
pytest.importorskip("bct")
|
244
|
+
|
245
|
+
with caplog.at_level(logging.DEBUG):
|
246
|
+
if error_msg is None:
|
247
|
+
read_transform(
|
248
|
+
storage=matrix_storage_with_nan, # type: ignore
|
249
|
+
feature_name="BOLD_matrix",
|
250
|
+
transform="bctpy_eigenvector_centrality_und",
|
251
|
+
nan_policy=nan_policy,
|
252
|
+
)
|
253
|
+
assert "Computing" in caplog.text
|
254
|
+
assert "Generating" in caplog.text
|
255
|
+
else:
|
256
|
+
with pytest.raises(ValueError, match=error_msg):
|
257
|
+
read_transform(
|
258
|
+
storage=matrix_storage_with_nan, # type: ignore
|
259
|
+
feature_name="BOLD_matrix",
|
260
|
+
transform="bctpy_eigenvector_centrality_und",
|
261
|
+
nan_policy=nan_policy,
|
262
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: junifer
|
3
|
-
Version: 0.0.7.
|
3
|
+
Version: 0.0.7.dev111
|
4
4
|
Summary: JUelich NeuroImaging FEature extractoR
|
5
5
|
Author-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
Maintainer-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
junifer/__init__.py,sha256=2McgH1yNue6Z1V26-uN_mfMjbTcx4CLhym-DMBl5xA4,266
|
2
2
|
junifer/__init__.pyi,sha256=SsTvgq2Dod6UqJN96GH1lCphH6hJQQurEJHGNhHjGUI,508
|
3
|
-
junifer/_version.py,sha256=
|
3
|
+
junifer/_version.py,sha256=LnYX032f40evsucLrn5L758qPtoWuq5rSV96EwT5oTA,528
|
4
4
|
junifer/conftest.py,sha256=PWYkkRDU8ly2lYwv7VBKMHje4et6HX7Yey3Md_I2KbA,613
|
5
5
|
junifer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
junifer/stats.py,sha256=e9aaagMGtgpRfW3Wdpz9ocpnYld1IWylCDcjFUgX9Mk,6225
|
@@ -237,8 +237,8 @@ junifer/markers/tests/test_parcel_aggregation.py,sha256=04OqtY_Z-KW4W1jU5K6GeWnL
|
|
237
237
|
junifer/markers/tests/test_sphere_aggregation.py,sha256=HPaLD6xKdewTt0iANz3nYOD7ZI-g7BqMTiRdV-4sM8M,10669
|
238
238
|
junifer/onthefly/__init__.py,sha256=TA6tPuw54ynDlumb9Ii-2p59hw2rGoCMe1-vQ89JzZ8,238
|
239
239
|
junifer/onthefly/_brainprint.py,sha256=-BswaAV9SLHU8mmWJ2KbPL7FgERJzIQIbSdV-NYiiYI,3802
|
240
|
-
junifer/onthefly/read_transform.py,sha256=
|
241
|
-
junifer/onthefly/tests/test_read_transform.py,sha256=
|
240
|
+
junifer/onthefly/read_transform.py,sha256=pUwwsO4oBwq6u4ybRpnQ5s6MujtwD_1AOMv-RdavAFg,6690
|
241
|
+
junifer/onthefly/tests/test_read_transform.py,sha256=U8BwImmgH9e2eA_WXVWyKgGzFQNEoD0teCNv2Udlhok,7246
|
242
242
|
junifer/pipeline/__init__.py,sha256=rxKQGRwc6_sts1KhVIcVVpuXeiFABf11mQQ2h5jgA3U,194
|
243
243
|
junifer/pipeline/__init__.pyi,sha256=hhcvNcABhtLaUQiZdTjo5sMWC3rtDkwVshL0sxD5JAE,399
|
244
244
|
junifer/pipeline/marker_collection.py,sha256=1Kmf5f0E2MFhDpO9OBui046b_6h1u9U64AdEqrxso-o,5377
|
@@ -324,10 +324,10 @@ junifer/utils/tests/test_config.py,sha256=7ltIXuwb_W4Mv_1dxQWyiyM10XgUAfsWKV6D_i
|
|
324
324
|
junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
|
325
325
|
junifer/utils/tests/test_helpers.py,sha256=k5qqfxK8dFyuewTJyR1Qn6-nFaYNuVr0ysc18bfPjyU,929
|
326
326
|
junifer/utils/tests/test_logging.py,sha256=W4tFKmaf8_CxnWZ-o_-XxM7DQbhGG18RsLZJk8bZelI,8163
|
327
|
-
junifer-0.0.7.
|
328
|
-
junifer-0.0.7.
|
329
|
-
junifer-0.0.7.
|
330
|
-
junifer-0.0.7.
|
331
|
-
junifer-0.0.7.
|
332
|
-
junifer-0.0.7.
|
333
|
-
junifer-0.0.7.
|
327
|
+
junifer-0.0.7.dev111.dist-info/licenses/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
|
328
|
+
junifer-0.0.7.dev111.dist-info/licenses/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
|
329
|
+
junifer-0.0.7.dev111.dist-info/METADATA,sha256=ZPvs0K5JekuTwe2VzukElpA4wD4nwWpYjOFqENx3AcQ,8388
|
330
|
+
junifer-0.0.7.dev111.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
331
|
+
junifer-0.0.7.dev111.dist-info/entry_points.txt,sha256=6O8ru0BP-SP7YMUZiizFNoaZ2HvJpadO2G7nKk4PwjI,48
|
332
|
+
junifer-0.0.7.dev111.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
|
333
|
+
junifer-0.0.7.dev111.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|