From 0f7bf62cbe01cf87f8468183d5e591965baf5d48 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 10:14:24 -0800 Subject: [PATCH 01/11] WIP: Object-oriented interface for parameteric tests. --- afqinsight/datasets.py | 2 +- afqinsight/parametric.py | 70 ++++++++++++++++++++++++++++++++-------- setup.py | 8 +++-- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/afqinsight/datasets.py b/afqinsight/datasets.py index 275b1267..e4d915cd 100755 --- a/afqinsight/datasets.py +++ b/afqinsight/datasets.py @@ -662,7 +662,7 @@ def from_study(study, verbose=None): dataset_kwargs = { "sarica": { "dwi_metrics": ["md", "fa"], - "target_cols": ["class"], + "target_cols": ["class", "age"], "label_encode_cols": ["class"], }, "weston-havens": {"dwi_metrics": ["md", "fa"], "target_cols": ["Age"]}, diff --git a/afqinsight/parametric.py b/afqinsight/parametric.py index 0eef914f..9332135e 100644 --- a/afqinsight/parametric.py +++ b/afqinsight/parametric.py @@ -1,4 +1,4 @@ -"""Perform linear modeling at leach node along the tract.""" +"""Perform linear modeling at each node along the tract.""" import numpy as np import pandas as pd @@ -11,11 +11,11 @@ def node_wise_regression( afq_dataset, tract, - metric, formula, group="group", lme=False, rand_eff="subjectID", + impute="median", ): """Model group differences using node-wise regression along the length of the tract. @@ -29,10 +29,6 @@ def node_wise_regression( tract: str String specifying the tract to model - metric: str - String specifying which diffusion metric to use as an outcome - eg. 'fa' - formula: str An R-style formula specifying the regression model to fit at each node. This can take the form @@ -46,6 +42,9 @@ def node_wise_regression( mixed-effects models. If using anything other than the default value, this column must be present in the 'target_cols' of the AFQDataset object + impute: str or None, default='median' + String specifying the imputation strategy to use for missing data. + Returns ------- @@ -53,13 +52,13 @@ def node_wise_regression( A dictionary with the following key-value pairs: {'tract': tract, - 'reference_coefs': coefs_default, - 'group_coefs': coefs_treat, - 'reference_CI': cis_default, - 'group_CI': cis_treat, - 'pvals': pvals, - 'reject_idx': reject_idx, - 'model_fits': fits} + 'reference_coefs': coefs_default, + 'group_coefs': coefs_treat, + 'reference_CI': cis_default, + 'group_CI': cis_treat, + 'pvals': pvals, + 'reject_idx': reject_idx, + 'model_fits': fits} tract: str The tract described by this dictionary @@ -96,8 +95,10 @@ def node_wise_regression( A list of the statsmodels object fit along the length of the nodes """ - X = SimpleImputer(strategy="median").fit_transform(afq_dataset.X) + if impute is not None: + X = SimpleImputer(strategy=impute).fit_transform(afq_dataset.X) afq_dataset.target_cols[0] = group + metric = formula.split("~")[0].strip() tract_data = ( pd.DataFrame(columns=afq_dataset.feature_names, data=X) @@ -158,8 +159,49 @@ def node_wise_regression( "reference_CI": cis_default, "group_CI": cis_treat, "pvals": pvals, + "pvals_corrected": pval_corrected, "reject_idx": reject_idx, "model_fits": fits, } return tract_dict + + +class RegressionResults(object): + def __init__(self, kwargs): + self.tract = kwargs.get("tract", None) + self.reference_coefs = kwargs.get("reference_coefs", None) + self.group_coefs = kwargs.get("group_coefs", None) + self.reference_ci = kwargs.get("reference_ci", None) + self.group_ci = kwargs.get("group_ci", None) + self.pvals = kwargs.get("pvals", None) + self.pvals_corrected = kwargs.get("pvals_corrected", None) + self.reject_idx = kwargs.get("reject_idx", None) + self.model_fits = kwargs.get("model_fits", None) + + +class NodeWiseRegression(object): + def __init__(self, formula, lme=False): + self.formula = formula + self.lme = lme + + def fit(self, dataset, tracts, group="group", rand_eff="subjectID"): + self.result_ = {} + for tract in tracts: + self.result_[tract] = node_wise_regression( + dataset, + tract, + self.formula, + lme=self.lme, + group=group, + rand_eff=rand_eff, + ) + self.is_fitted = True + return self + + def predict(self, dataset, tract, metric, group="group", rand_eff="subjectID"): + if not self.is_fitted: + raise ValueError("Model not fitted yet. Please call fit() method first.") + result = self.result_.get(tract, None) + if result is None: + raise ValueError(f"Tract {tract} not found in the fitted model.") diff --git a/setup.py b/setup.py index 6f9aca82..df2be906 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,9 @@ def local_version(version): - """Patch in a version that can be uploaded to test PyPI.""" + """ + Patch in a version that can be uploaded to test PyPI + """ scm_version = get_version() if "dev" in scm_version: gh_in_int = [] @@ -22,7 +24,9 @@ def local_version(version): opts = { "use_scm_version": { - "write_to": op.join("afqinsight", "_version.py"), + "root": ".", + "relative_to": __file__, + "write_to": op.join("afqinsight", "version.py"), "local_scheme": local_version, } } From 497ce315d25f1ac8b2601b62a57849cc65507de3 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 10:49:03 -0800 Subject: [PATCH 02/11] DOC: Use new API (no need to specify metric separately). --- examples/plot_als_comparison.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/plot_als_comparison.py b/examples/plot_als_comparison.py index 2e804f33..64b967db 100644 --- a/examples/plot_als_comparison.py +++ b/examples/plot_als_comparison.py @@ -74,7 +74,7 @@ # Loop through the data and generate plots for i, tract in enumerate(tracts): # fit node-wise regression for each tract based on model formula - tract_dict = node_wise_regression(afqdata, tract, "fa", "fa ~ C(group)") + tract_dict = node_wise_regression(afqdata, tract, "fa ~ C(group)") row = i // num_cols col = i % num_cols From fc5044fd59f90f1ac005caf576e0d0005e57d9e0 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 11:02:03 -0800 Subject: [PATCH 03/11] Adds tests for parameteric module. --- afqinsight/tests/test_parametric.py | 20 ++++++++++++++++++++ examples/plot_als_comparison.py | 6 +++--- 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 afqinsight/tests/test_parametric.py diff --git a/afqinsight/tests/test_parametric.py b/afqinsight/tests/test_parametric.py new file mode 100644 index 00000000..bdbfdb59 --- /dev/null +++ b/afqinsight/tests/test_parametric.py @@ -0,0 +1,20 @@ +from afqinsight import AFQDataset +from afqinsight.parametric import NodeWiseRegression, node_wise_regression + + +def test_node_wise_regression(): + data = AFQDataset.from_study("sarica") + tracts = ["Left Corticospinal", "Left SLF"] + for tract in tracts: + for lme in [True, False]: + tract_dict = node_wise_regression( # noqa F841 + data, tract, "fa ~ C(group) + age", lme=lme + ) + + +def test_NodeWiseRegression(): + data = AFQDataset.from_study("sarica") + tracts = ["Left Corticospinal", "Left SLF"] + for lme in [True, False]: + model = NodeWiseRegression("fa ~ C(group) + age", lme=lme) + model.fit(data, tracts) diff --git a/examples/plot_als_comparison.py b/examples/plot_als_comparison.py index 64b967db..a5cfcef8 100644 --- a/examples/plot_als_comparison.py +++ b/examples/plot_als_comparison.py @@ -72,12 +72,12 @@ # Loop through the data and generate plots -for i, tract in enumerate(tracts): +for ii, tract in enumerate(tracts): # fit node-wise regression for each tract based on model formula tract_dict = node_wise_regression(afqdata, tract, "fa ~ C(group)") - row = i // num_cols - col = i % num_cols + row = ii // num_cols + col = ii % num_cols axes[row][col].set_title(tract) From f1ad2fcf5cbeeebbe634b759a7b8d732f62f5067 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 11:19:04 -0800 Subject: [PATCH 04/11] Add assertions to the tests. --- afqinsight/tests/test_parametric.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/afqinsight/tests/test_parametric.py b/afqinsight/tests/test_parametric.py index bdbfdb59..030ba49f 100644 --- a/afqinsight/tests/test_parametric.py +++ b/afqinsight/tests/test_parametric.py @@ -1,15 +1,40 @@ +import numpy as np + from afqinsight import AFQDataset from afqinsight.parametric import NodeWiseRegression, node_wise_regression def test_node_wise_regression(): + # Store results + group_dict = {} + group_age_dict = {} + age_dict = {} + data = AFQDataset.from_study("sarica") - tracts = ["Left Corticospinal", "Left SLF"] + tracts = ["Right Corticospinal", "Right SLF"] for tract in tracts: for lme in [True, False]: - tract_dict = node_wise_regression( # noqa F841 + # Run different versions of this: with age, without age, only with + # age: + + group_dict[tract] = node_wise_regression( # noqa F841 + data, tract, "fa ~ C(group)", lme=lme + ) + group_age_dict[tract] = node_wise_regression( # noqa F841 data, tract, "fa ~ C(group) + age", lme=lme ) + age_dict[tract] = node_wise_regression( # noqa F841 + data, tract, "fa ~ age", lme=lme + ) + + assert age_dict[tract]["pval"].shape == (100,) + assert group_age_dict[tract]["pval"].shape == (100,) + assert age_dict[tract]["pval"].shape == (100,) + + assert np.any(group_dict["Right Corticospintal"]["pval_corrected"] < 0.05) + assert np.all(group_dict["Right SLF"]["pval_corrected"] > 0.05) + assert np.any(group_age_dict["Right Corticospintal"]["pval_corrected"] < 0.05) + assert np.all(group_age_dict["Right SLF"]["pval_corrected"] > 0.05) def test_NodeWiseRegression(): From 2178c223d2f5c7e58c1acc771fbe72d29918f74d Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 14:19:26 -0800 Subject: [PATCH 05/11] Adjust test to new dataset definition (to include age) --- afqinsight/tests/test_datasets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/afqinsight/tests/test_datasets.py b/afqinsight/tests/test_datasets.py index e5cf31bb..6e957884 100644 --- a/afqinsight/tests/test_datasets.py +++ b/afqinsight/tests/test_datasets.py @@ -358,7 +358,7 @@ def test_from_study(study): "n_subjects": 48, "n_features": 4000, "n_groups": 40, - "target_cols": ["class"], + "target_cols": ["class", "age"], }, "weston-havens": { "n_subjects": 77, From 9b985792679fe0ad8e743f7f8dd97012a86c6188 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 15:04:50 -0800 Subject: [PATCH 06/11] Apply changes to example that follow from change to the dataset. Age is now also a feature, but we're not using it here. --- examples/plot_als_classification.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/plot_als_classification.py b/examples/plot_als_classification.py index 8277cf02..ca2b2e4b 100644 --- a/examples/plot_als_classification.py +++ b/examples/plot_als_classification.py @@ -54,6 +54,7 @@ X = afqdata.X y = afqdata.y.astype(float) # SGL expects float targets +is_als = y[:, 0] groups = afqdata.groups feature_names = afqdata.feature_names group_names = afqdata.group_names @@ -117,7 +118,7 @@ # scikit-learn functions scores = cross_validate( - pipe, X, y, cv=5, return_train_score=True, return_estimator=True + pipe, X, is_als, cv=5, return_train_score=True, return_estimator=True ) # Display results From 80df035a7a76d596f169eedf4c5d5f173b2372d3 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 16:13:58 -0800 Subject: [PATCH 07/11] Reinstate setup.py to the state on main right now. --- setup.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index df2be906..6f9aca82 100644 --- a/setup.py +++ b/setup.py @@ -6,9 +6,7 @@ def local_version(version): - """ - Patch in a version that can be uploaded to test PyPI - """ + """Patch in a version that can be uploaded to test PyPI.""" scm_version = get_version() if "dev" in scm_version: gh_in_int = [] @@ -24,9 +22,7 @@ def local_version(version): opts = { "use_scm_version": { - "root": ".", - "relative_to": __file__, - "write_to": op.join("afqinsight", "version.py"), + "write_to": op.join("afqinsight", "_version.py"), "local_scheme": local_version, } } From 3876ed500c73ae3a063a348e407aece9bfab2925 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 16:43:01 -0800 Subject: [PATCH 08/11] Move towards making group optional. --- afqinsight/parametric.py | 37 ++++++++++++++++++----------- afqinsight/tests/test_parametric.py | 32 ++++++++++++------------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/afqinsight/parametric.py b/afqinsight/parametric.py index 9332135e..cc4c634c 100644 --- a/afqinsight/parametric.py +++ b/afqinsight/parametric.py @@ -12,7 +12,7 @@ def node_wise_regression( afq_dataset, tract, formula, - group="group", + group=None, lme=False, rand_eff="subjectID", impute="median", @@ -26,6 +26,7 @@ def node_wise_regression( ---------- afq_dataset: AFQDataset Loaded AFQDataset object + tract: str String specifying the tract to model @@ -71,7 +72,7 @@ def node_wise_regression( group_coefs: list of floats A list of beta-weights representing the average group effect metric for the treatment group on a diffusion metric at a given location - along the tract + along the tract, if group None this will be a list of zeros. reference_CI: np.array of np.array A numpy array containing a series of numpy arrays indicating the @@ -81,7 +82,8 @@ def node_wise_regression( group_CI: np.array of np.array A numpy array containing a series of numpy arrays indicating the 95% confidence interval around the estimated beta-weight of the - treatment effect at a given location along the tract + treatment effect at a given location along the tract. If group is + None, this will be an array of zeros. pvals: list of floats A list of p-values testing whether or not the beta-weight of the @@ -97,7 +99,10 @@ def node_wise_regression( """ if impute is not None: X = SimpleImputer(strategy=impute).fit_transform(afq_dataset.X) - afq_dataset.target_cols[0] = group + + if group is not None: + afq_dataset.target_cols[0] = group + metric = formula.split("~")[0].strip() tract_data = ( @@ -140,17 +145,21 @@ def node_wise_regression( # pull out coefficients, CIs, and p-values from our model coefs_default[ii] = fit.params.filter(regex="Intercept", axis=0).iloc[0] - coefs_treat[ii] = fit.params.filter(regex=group, axis=0).iloc[0] - cis_default[ii] = ( - fit.conf_int(alpha=0.05).filter(regex="Intercept", axis=0).values - ) - cis_treat[ii] = fit.conf_int(alpha=0.05).filter(regex=group, axis=0).values - pvals[ii] = fit.pvalues.filter(regex=group, axis=0).iloc[0] + if group is not None: + coefs_treat[ii] = fit.params.filter(regex=group, axis=0).iloc[0] - # Correct p-values for multiple comparisons - reject, pval_corrected, _, _ = multipletests(pvals, alpha=0.05, method="fdr_bh") - reject_idx = np.where(reject) + cis_default[ii] = ( + fit.conf_int(alpha=0.05).filter(regex="Intercept", axis=0).values + ) + cis_treat[ii] = fit.conf_int(alpha=0.05).filter(regex=group, axis=0).values + pvals[ii] = fit.pvalues.filter(regex=group, axis=0).iloc[0] + + # Correct p-values for multiple comparisons + reject, pval_corrected, _, _ = multipletests( + pvals, alpha=0.05, method="fdr_bh" + ) + reject_idx = np.where(reject) tract_dict = { "tract": tract, @@ -185,7 +194,7 @@ def __init__(self, formula, lme=False): self.formula = formula self.lme = lme - def fit(self, dataset, tracts, group="group", rand_eff="subjectID"): + def fit(self, dataset, tracts, group=None, rand_eff="subjectID"): self.result_ = {} for tract in tracts: self.result_[tract] = node_wise_regression( diff --git a/afqinsight/tests/test_parametric.py b/afqinsight/tests/test_parametric.py index 030ba49f..a1db0e62 100644 --- a/afqinsight/tests/test_parametric.py +++ b/afqinsight/tests/test_parametric.py @@ -8,7 +8,7 @@ def test_node_wise_regression(): # Store results group_dict = {} group_age_dict = {} - age_dict = {} + age_dict = {} # noqa F841 data = AFQDataset.from_study("sarica") tracts = ["Right Corticospinal", "Right SLF"] @@ -17,24 +17,24 @@ def test_node_wise_regression(): # Run different versions of this: with age, without age, only with # age: - group_dict[tract] = node_wise_regression( # noqa F841 - data, tract, "fa ~ C(group)", lme=lme + group_dict[tract] = node_wise_regression( + data, tract, "fa ~ C(group)", lme=lme, group="group" ) - group_age_dict[tract] = node_wise_regression( # noqa F841 - data, tract, "fa ~ C(group) + age", lme=lme - ) - age_dict[tract] = node_wise_regression( # noqa F841 - data, tract, "fa ~ age", lme=lme + group_age_dict[tract] = node_wise_regression( + data, tract, "fa ~ C(group) + age", lme=lme, group="group" ) + # age_dict[tract] = node_wise_regression( + # data, tract, "fa ~ age", lme=lme + # ) - assert age_dict[tract]["pval"].shape == (100,) - assert group_age_dict[tract]["pval"].shape == (100,) - assert age_dict[tract]["pval"].shape == (100,) + assert group_dict[tract]["pvals"].shape == (100,) + assert group_age_dict[tract]["pvals"].shape == (100,) + # assert age_dict[tract]["pval"].shape == (100,) - assert np.any(group_dict["Right Corticospintal"]["pval_corrected"] < 0.05) - assert np.all(group_dict["Right SLF"]["pval_corrected"] > 0.05) - assert np.any(group_age_dict["Right Corticospintal"]["pval_corrected"] < 0.05) - assert np.all(group_age_dict["Right SLF"]["pval_corrected"] > 0.05) + assert np.any(group_dict["Right Corticospinal"]["pvals_corrected"] < 0.05) + assert np.all(group_dict["Right SLF"]["pvals_corrected"] > 0.05) + assert np.any(group_age_dict["Right Corticospinal"]["pvals_corrected"] < 0.05) + assert np.all(group_age_dict["Right SLF"]["pvals_corrected"] > 0.05) def test_NodeWiseRegression(): @@ -42,4 +42,4 @@ def test_NodeWiseRegression(): tracts = ["Left Corticospinal", "Left SLF"] for lme in [True, False]: model = NodeWiseRegression("fa ~ C(group) + age", lme=lme) - model.fit(data, tracts) + model.fit(data, tracts, group="group") From f14fe2b61a0747bdc41ce745f4e2c17ac6529e33 Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 16:46:40 -0800 Subject: [PATCH 09/11] One more step towards flexibility wrt group assignment. --- afqinsight/parametric.py | 9 ++++++--- afqinsight/tests/test_parametric.py | 8 +++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/afqinsight/parametric.py b/afqinsight/parametric.py index cc4c634c..3e232f87 100644 --- a/afqinsight/parametric.py +++ b/afqinsight/parametric.py @@ -112,10 +112,12 @@ def node_wise_regression( ) pvals = np.zeros(tract_data.shape[-1]) + pvals_corrected = np.zeros(tract_data.shape[-1]) coefs_default = np.zeros(tract_data.shape[-1]) coefs_treat = np.zeros(tract_data.shape[-1]) cis_default = np.zeros((tract_data.shape[-1], 2)) cis_treat = np.zeros((tract_data.shape[-1], 2)) + reject = np.zeros(tract_data.shape[-1], dtype=bool) fits = {} # Loop through each node and fit model @@ -156,10 +158,11 @@ def node_wise_regression( pvals[ii] = fit.pvalues.filter(regex=group, axis=0).iloc[0] # Correct p-values for multiple comparisons - reject, pval_corrected, _, _ = multipletests( + reject, pvals_corrected, _, _ = multipletests( pvals, alpha=0.05, method="fdr_bh" ) - reject_idx = np.where(reject) + + reject_idx = np.where(reject) tract_dict = { "tract": tract, @@ -168,7 +171,7 @@ def node_wise_regression( "reference_CI": cis_default, "group_CI": cis_treat, "pvals": pvals, - "pvals_corrected": pval_corrected, + "pvals_corrected": pvals_corrected, "reject_idx": reject_idx, "model_fits": fits, } diff --git a/afqinsight/tests/test_parametric.py b/afqinsight/tests/test_parametric.py index a1db0e62..8c5e8fe2 100644 --- a/afqinsight/tests/test_parametric.py +++ b/afqinsight/tests/test_parametric.py @@ -8,7 +8,7 @@ def test_node_wise_regression(): # Store results group_dict = {} group_age_dict = {} - age_dict = {} # noqa F841 + age_dict = {} data = AFQDataset.from_study("sarica") tracts = ["Right Corticospinal", "Right SLF"] @@ -23,13 +23,11 @@ def test_node_wise_regression(): group_age_dict[tract] = node_wise_regression( data, tract, "fa ~ C(group) + age", lme=lme, group="group" ) - # age_dict[tract] = node_wise_regression( - # data, tract, "fa ~ age", lme=lme - # ) + age_dict[tract] = node_wise_regression(data, tract, "fa ~ age", lme=lme) assert group_dict[tract]["pvals"].shape == (100,) assert group_age_dict[tract]["pvals"].shape == (100,) - # assert age_dict[tract]["pval"].shape == (100,) + assert age_dict[tract]["pvals"].shape == (100,) assert np.any(group_dict["Right Corticospinal"]["pvals_corrected"] < 0.05) assert np.all(group_dict["Right SLF"]["pvals_corrected"] > 0.05) From 0f7584229364c02cb4718e613e08880b32796acd Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 6 Dec 2024 17:17:21 -0800 Subject: [PATCH 10/11] Adjust the example accordingly. --- examples/plot_als_comparison.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/plot_als_comparison.py b/examples/plot_als_comparison.py index a5cfcef8..7c78b565 100644 --- a/examples/plot_als_comparison.py +++ b/examples/plot_als_comparison.py @@ -74,7 +74,7 @@ # Loop through the data and generate plots for ii, tract in enumerate(tracts): # fit node-wise regression for each tract based on model formula - tract_dict = node_wise_regression(afqdata, tract, "fa ~ C(group)") + tract_dict = node_wise_regression(afqdata, tract, "fa ~ C(group)", group="group") row = ii // num_cols col = ii % num_cols From 0192b3c73e4371b606bd1c88264694577b106bed Mon Sep 17 00:00:00 2001 From: Ariel Rokem Date: Fri, 20 Dec 2024 16:07:36 -0800 Subject: [PATCH 11/11] Use pandas df instead of dict. --- afqinsight/parametric.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/afqinsight/parametric.py b/afqinsight/parametric.py index 3e232f87..aceac8c9 100644 --- a/afqinsight/parametric.py +++ b/afqinsight/parametric.py @@ -119,7 +119,6 @@ def node_wise_regression( cis_treat = np.zeros((tract_data.shape[-1], 2)) reject = np.zeros(tract_data.shape[-1], dtype=bool) fits = {} - # Loop through each node and fit model for ii, column in enumerate(tract_data.columns): # fit linear mixed-effects model @@ -133,7 +132,6 @@ def node_wise_regression( model = smf.mixedlm(formula, this, groups=rand_eff) fit = model.fit() - fits[column] = fit # fit OLS model else: @@ -143,8 +141,7 @@ def node_wise_regression( model = OLS.from_formula(formula, this) fit = model.fit() - fits[column] = fit - + fits[ii] = fit # pull out coefficients, CIs, and p-values from our model coefs_default[ii] = fit.params.filter(regex="Intercept", axis=0).iloc[0] @@ -162,21 +159,21 @@ def node_wise_regression( pvals, alpha=0.05, method="fdr_bh" ) - reject_idx = np.where(reject) - - tract_dict = { - "tract": tract, - "reference_coefs": coefs_default, - "group_coefs": coefs_treat, - "reference_CI": cis_default, - "group_CI": cis_treat, - "pvals": pvals, - "pvals_corrected": pvals_corrected, - "reject_idx": reject_idx, - "model_fits": fits, - } - - return tract_dict + reject = np.where(reject, 1, 0) + + return pd.DataFrame( + { + "reference_coefs": coefs_default, + "group_coefs": coefs_treat, + "reference_CI_lb": cis_default[:, 0], + "reference_CI_ub": cis_default[:, 1], + "group_CI_lb": cis_treat[:, 0], + "group_CI_ub": cis_treat[:, 1], + "pvals": pvals, + "pvals_corrected": pvals_corrected, + "reject_idx": reject, + } + ), fits class RegressionResults(object):