def model_average(X, penalization): """Run ModelAverage in default mode (QuicGraphicalLassoCV) to obtain proportion matrix. NOTE: This returns precision_ proportions, not cov, prec estimates, so we return the raw proportions for "cov" and the threshold support estimate for prec. """ n_trials = 100 print("ModelAverage with:") print(" estimator: QuicGraphicalLasso (default)") print(" n_trials: {}".format(n_trials)) print(" penalization: {}".format(penalization)) # if penalization is random, first find a decent scalar lam_ to build # random perturbation matrix around. lam doesn't matter for fully-random. lam = 0.5 if penalization == "random": cv_model = QuicGraphicalLassoCV(cv=2, n_refinements=6, n_jobs=1, init_method="cov", score_metric=metric) cv_model.fit(X) lam = cv_model.lam_ print(" lam: {}".format(lam)) model = ModelAverage(n_trials=n_trials, penalization=penalization, lam=lam, n_jobs=1) model.fit(X) print(" lam_: {}".format(model.lam_)) return model.proportion_, model.support_, model.lam_
def est_connectivity(X, gm="Glasso", assume_centered=False): if gm == "QuicGlasso-CV": quic = QuicGraphicalLassoCV(cv=5) quic.fit(X) return quic.covariance_, quic.precision_, quic.lam_ elif gm == "QuicGlasso-BIC": quic_bic = QuicGraphicalLassoEBIC(gamma=0) quic_bic.fit(X) return quic_bic.covariance_, quic_bic.precision_, quic_bic.lam_ else: # Default: Glasso glasso = GraphicalLassoCV(assume_centered=assume_centered, cv=5).fit(X) return glasso.covariance_, glasso.get_precision(), glasso.alpha_
def adaptive_graph_lasso(X, model_selector, method): """Run QuicGraphicalLassoCV or QuicGraphicalLassoEBIC as a two step adaptive fit with method of choice (currently: 'binary', 'inverse', 'inverse_squared'). Compare the support and values to the model-selection estimator. """ metric = "log_likelihood" print("Adaptive {} with:".format(model_selector)) print(" adaptive-method: {}".format(method)) if model_selector == "QuicGraphicalLassoCV": print(" metric: {}".format(metric)) model = AdaptiveGraphicalLasso( estimator=QuicGraphicalLassoCV( cv=2, # cant deal w more folds at small size n_refinements=6, init_method="cov", score_metric=metric, sc=spark.sparkContext, # NOQA ), method=method, ) elif model_selector == "QuicGraphicalLassoEBIC": model = AdaptiveGraphicalLasso(estimator=QuicGraphicalLassoEBIC(), method=method) model.fit(X) lam_norm_ = np.linalg.norm(model.estimator_.lam_) print(" ||lam_||_2: {}".format(lam_norm_)) return model.estimator_.covariance_, model.estimator_.precision_, lam_norm_
def quic_graph_lasso_cv(X, metric): """Run QuicGraphicalLassoCV on data with metric of choice. Compare results with GridSearchCV + quic_graph_lasso. The number of lambdas tested should be much lower with similar final lam_ selected. """ print("QuicGraphicalLassoCV with:") print(" metric: {}".format(metric)) model = QuicGraphicalLassoCV( cv=2, # cant deal w more folds at small size n_refinements=6, sc=spark.sparkContext, # NOQA init_method="cov", score_metric=metric, ) model.fit(X) print(" len(cv_lams): {}".format(len(model.cv_lams_))) print(" lam_scale_: {}".format(model.lam_scale_)) print(" lam_: {}".format(model.lam_)) return model.covariance_, model.precision_, model.lam_
def adaptive_model_average(X, penalization, method): """Run ModelAverage in default mode (QuicGraphicalLassoCV) to obtain proportion matrix. NOTE: Only method = 'binary' really makes sense in this case. """ n_trials = 100 print("Adaptive ModelAverage with:") print(" estimator: QuicGraphicalLasso (default)") print(" n_trials: {}".format(n_trials)) print(" penalization: {}".format(penalization)) print(" adaptive-method: {}".format(method)) # if penalization is random, first find a decent scalar lam_ to build # random perturbation matrix around. lam doesn't matter for fully-random. lam = 0.5 if penalization == "random": cv_model = QuicGraphicalLassoCV( cv=2, n_refinements=6, sc=spark.sparkContext, # NOQA init_method="cov", score_metric=metric, ) cv_model.fit(X) lam = cv_model.lam_ print(" lam: {}".format(lam)) model = AdaptiveGraphicalLasso( estimator=ModelAverage(n_trials=n_trials, penalization=penalization, lam=lam, sc=spark.sparkContext), # NOQA method=method, ) model.fit(X) lam_norm_ = np.linalg.norm(model.estimator_.lam_) print(" ||lam_||_2: {}".format(lam_norm_)) return model.estimator_.covariance_, model.estimator_.precision_, lam_norm_
def test_integration_quic_graphical_lasso_cv(self, params_in, expected): """ Just tests inputs/outputs (not validity of result). """ X = datasets.load_diabetes().data ic = QuicGraphicalLassoCV(**params_in) ic.fit(X) result_vec = [ np.linalg.norm(ic.covariance_), np.linalg.norm(ic.precision_), np.linalg.norm(ic.opt_), np.linalg.norm(ic.duality_gap_), ] if isinstance(ic.lam_, float): result_vec.append(ic.lam_) elif isinstance(ic.lam_, np.ndarray): assert ic.lam_.shape == params_in["lam"].shape print(result_vec) assert_allclose(expected, result_vec, atol=1e-1, rtol=1e-1) assert len(ic.grid_scores_) == len(ic.cv_lams_)
def get_conn_matrix(time_series, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, roi, min_span_tree, disp_filt, parc, prune, atlas_select, uatlas_select, label_names, coords, c_boot, norm, binary): from nilearn.connectome import ConnectivityMeasure from sklearn.covariance import GraphicalLassoCV conn_matrix = None if conn_model == 'corr' or conn_model == 'cor' or conn_model == 'correlation': # credit: nilearn print('\nComputing correlation matrix...\n') conn_measure = ConnectivityMeasure(kind='correlation') conn_matrix = conn_measure.fit_transform([time_series])[0] elif conn_model == 'partcorr' or conn_model == 'parcorr' or conn_model == 'partialcorrelation': # credit: nilearn print('\nComputing partial correlation matrix...\n') conn_measure = ConnectivityMeasure(kind='partial correlation') conn_matrix = conn_measure.fit_transform([time_series])[0] elif conn_model == 'cov' or conn_model == 'covariance' or conn_model == 'covar' or conn_model == 'sps' or conn_model == 'sparse' or conn_model == 'precision': # Fit estimator to matrix to get sparse matrix estimator_shrunk = None estimator = GraphicalLassoCV(cv=5) try: print('\nComputing covariance...\n') estimator.fit(time_series) except: print( 'Unstable Lasso estimation--Attempting to re-run by first applying shrinkage...' ) try: from sklearn.covariance import GraphicalLasso, empirical_covariance, shrunk_covariance emp_cov = empirical_covariance(time_series) for i in np.arange(0.8, 0.99, 0.01): shrunk_cov = shrunk_covariance(emp_cov, shrinkage=i) alphaRange = 10.0**np.arange(-8, 0) for alpha in alphaRange: try: estimator_shrunk = GraphicalLasso(alpha) estimator_shrunk.fit(shrunk_cov) print( "Retrying covariance matrix estimate with alpha=%s" % alpha) if estimator_shrunk is None: pass else: break except: print( "Covariance estimation failed with shrinkage at alpha=%s" % alpha) continue except ValueError: print( 'Unstable Lasso estimation! Shrinkage failed. A different connectivity model may be needed.' ) if estimator is None and estimator_shrunk is None: raise RuntimeError('\nERROR: Covariance estimation failed.') if conn_model == 'sps' or conn_model == 'sparse' or conn_model == 'precision': if estimator_shrunk is None: print( '\nFetching precision matrix from covariance estimator...\n' ) conn_matrix = -estimator.precision_ else: print( '\nFetching shrunk precision matrix from covariance estimator...\n' ) conn_matrix = -estimator_shrunk.precision_ elif conn_model == 'cov' or conn_model == 'covariance' or conn_model == 'covar': if estimator_shrunk is None: print( '\nFetching covariance matrix from covariance estimator...\n' ) conn_matrix = estimator.covariance_ else: conn_matrix = estimator_shrunk.covariance_ elif conn_model == 'QuicGraphicalLasso': try: from inverse_covariance import QuicGraphicalLasso except ImportError: print('Cannot run QuicGraphLasso. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLasso # credit: skggm model = QuicGraphicalLasso(init_method='cov', lam=0.5, mode='default', verbose=1) print('\nCalculating QuicGraphLasso precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'QuicGraphLassoCV': try: from inverse_covariance import QuicGraphicalLassoCV except ImportError: print('Cannot run QuicGraphLassoCV. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLassoCV # credit: skggm model = QuicGraphicalLassoCV(init_method='cov', verbose=1) print( '\nCalculating QuicGraphLassoCV precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'QuicGraphicalLassoEBIC': try: from inverse_covariance import QuicGraphicalLassoEBIC except ImportError: print('Cannot run QuicGraphLassoEBIC. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLassoEBIC # credit: skggm model = QuicGraphicalLassoEBIC(init_method='cov', verbose=1) print( '\nCalculating QuicGraphLassoEBIC precision matrix using skggm...\n' ) model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'AdaptiveQuicGraphLasso': try: from inverse_covariance import AdaptiveQuicGraphicalLasso, QuicGraphicalLassoEBIC except ImportError: print('Cannot run AdaptiveGraphLasso. Skggm not installed!') # Compute the sparse inverse covariance via # AdaptiveGraphLasso + QuicGraphLassoEBIC + method='binary' # credit: skggm model = AdaptiveQuicGraphicalLasso( estimator=QuicGraphicalLassoEBIC(init_method='cov', ), method='binary', ) print( '\nCalculating AdaptiveQuicGraphLasso precision matrix using skggm...\n' ) model.fit(time_series) conn_matrix = -model.estimator_.precision_ else: raise ValueError( '\nERROR! No connectivity model specified at runtime. Select a valid estimator using the ' '-mod flag.') if conn_matrix.shape < (2, 2): raise RuntimeError( '\nERROR! Matrix estimation selection yielded an empty or 1-dimensional graph. ' 'Check time-series for errors or try using a different atlas') coords = np.array(coords) label_names = np.array(label_names) return conn_matrix, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, roi, min_span_tree, disp_filt, parc, prune, atlas_select, uatlas_select, label_names, coords, c_boot, norm, binary
class TestModelAverage(object): @pytest.mark.parametrize( "params_in", [ ({ "estimator": QuicGraphicalLasso(), "n_trials": 10, "normalize": True, "subsample": 0.3, "penalization": "random", }), ({ "estimator": QuicGraphicalLasso(lam=0.5, mode="trace"), "n_trials": 10, "normalize": False, "subsample": 0.6, "penalization": "fully-random", }), ({ "estimator": QuicGraphicalLassoCV(cv=(2, 1)), "n_trials": 2, "normalize": True, "subsample": 0.9, "lam": 0.1, "lam_perturb": 0.1, "penalization": "random", }), ({ "estimator": GraphLassoCV(cv=2), "n_trials": 2, "normalize": True, "subsample": 0.9, "penalization": "subsampling", "penalty_name": "alpha", }), ({ "estimator": QuicGraphicalLasso(), "n_trials": 10, "normalize": True, "subsample": 0.3, "lam": 0.1, "lam_perturb": 0.1, "penalization": "random", "n_jobs": 2, }), ], ) def test_integration_quic_graph_lasso_cv(self, params_in): """ Just tests inputs/outputs (not validity of result). """ n_features = 30 n_samples = 30 cov, prec, adj = ClusterGraph(n_blocks=1, chain_blocks=False, seed=1).create(n_features, 0.8) prng = np.random.RandomState(2) X = prng.multivariate_normal(np.zeros(n_features), cov, size=n_samples) ma = ModelAverage(**params_in) ma.fit(X) n_examples, n_features = X.shape assert ma.proportion_.shape == (n_features, n_features) assert len(ma.estimators_) == ma.n_trials assert len(ma.subsets_) == ma.n_trials if not ma.penalization == "subsampling": assert len(ma.lams_) == ma.n_trials else: assert len(ma.lams_) == ma.n_trials assert ma.lams_[0] is None for eidx, e in enumerate(ma.estimators_): assert isinstance(e, params_in["estimator"].__class__) # sklearn doesnt have this but ours do if hasattr(e, "is_fitted"): assert e.is_fitted is True # check that all lambdas used where different if not ma.penalization == "subsampling" and eidx > 0: if hasattr(e, "lam"): prev_e = ma.estimators_[eidx - 1] assert np.linalg.norm((prev_e.lam - e.lam).flat) > 0 if ma.normalize is True: assert np.max(ma.proportion_) <= 1.0 else: assert np.max(ma.proportion_) <= ma.n_trials assert np.min(ma.proportion_) >= 0.0 assert np.max(ma.proportion_) > 0.0
def get_conn_matrix( time_series, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, roi, min_span_tree, disp_filt, parc, prune, atlas, uatlas, labels, coords, norm, binary, hpass, extract_strategy, ): """ Computes a functional connectivity matrix based on a node-extracted time-series array. Includes a library of routines across Nilearn, scikit-learn, and skggm packages, among others. Parameters ---------- time_series : array 2D m x n array consisting of the time-series signal for each ROI node where m = number of scans and n = number of ROI's. conn_model : str Connectivity estimation model (e.g. corr for correlation, cov for covariance, sps for precision covariance, partcorr for partial correlation). sps type is used by default. dir_path : str Path to directory containing subject derivative data for given run. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's. smooth : int Smoothing width (mm fwhm) to apply to time-series when extracting signal from ROI's. dens_thresh : bool Indicates whether a target graph density is to be used as the basis for thresholding. network : str Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default') used to filter nodes in the study of brain subgraphs. ID : str A subject id or other unique identifier. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. min_span_tree : bool Indicates whether local thresholding from the Minimum Spanning Tree should be used. disp_filt : bool Indicates whether local thresholding using a disparity filter and 'backbone network' should be used. parc : bool Indicates whether to use parcels instead of coordinates as ROI nodes. prune : bool Indicates whether to prune final graph of disconnected nodes/isolates. atlas : str Name of atlas parcellation used. uatlas : str File path to atlas parcellation Nifti1Image in MNI template space. labels : list List of string labels corresponding to ROI nodes. coords : list List of (x, y, z) tuples corresponding to a coordinate atlas used or which represent the center-of-mass of each parcellation node. norm : int Indicates method of normalizing resulting graph. binary : bool Indicates whether to binarize resulting graph edges to form an unweighted graph. hpass : bool High-pass filter values (Hz) to apply to node-extracted time-series. extract_strategy : str The name of a valid function used to reduce the time-series region extraction. Returns ------- conn_matrix : array Adjacency matrix stored as an m x n array of nodes and edges. conn_model : str Connectivity estimation model (e.g. corr for correlation, cov for covariance, sps for precision covariance, partcorr for partial correlation). sps type is used by default. dir_path : str Path to directory containing subject derivative data for given run. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's for tracking. smooth : int Smoothing width (mm fwhm) to apply to time-series when extracting signal from ROI's. dens_thresh : bool Indicates whether a target graph density is to be used as the basis for thresholding. network : str Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default') used to filter nodes in the study of brain subgraphs. ID : str A subject id or other unique identifier. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. min_span_tree : bool Indicates whether local thresholding from the Minimum Spanning Tree should be used. disp_filt : bool Indicates whether local thresholding using a disparity filter and 'backbone network' should be used. parc : bool Indicates whether to use parcels instead of coordinates as ROI nodes. prune : bool Indicates whether to prune final graph of disconnected nodes/isolates. atlas : str Name of atlas parcellation used. uatlas : str File path to atlas parcellation Nifti1Image in MNI template space. labels : list List of string labels corresponding to graph nodes. coords : list List of (x, y, z) tuples corresponding to a coordinate atlas used or which represent the center-of-mass of each parcellation node. norm : int Indicates method of normalizing resulting graph. binary : bool Indicates whether to binarize resulting graph edges to form an unweighted graph. hpass : bool High-pass filter values (Hz) to apply to node-extracted time-series. extract_strategy : str The name of a valid function used to reduce the time-series region extraction. References ---------- .. [1] Varoquaux, G., & Craddock, R. C. (2013). Learning and comparing functional connectomes across subjects. NeuroImage. https://doi.org/10.1016/j.neuroimage.2013.04.007 .. [2] Jason Laska, Manjari Narayan, 2017. skggm 0.2.7: A scikit-learn compatible package for Gaussian and related Graphical Models. doi:10.5281/zenodo.830033 """ import sys from pynets.fmri.estimation import get_optimal_cov_estimator from nilearn.connectome import ConnectivityMeasure nilearn_kinds = [ "cov", "covariance", "covar", "corr", "cor", "correlation", "partcorr", "parcorr", "partialcorrelation", "cov", "covariance", "covar", "sps", "sparse", "precision" ] conn_matrix = None estimator = get_optimal_cov_estimator(time_series) def fallback_covariance(time_series): from sklearn.ensemble import IsolationForest from sklearn import covariance # Remove gross outliers model = IsolationForest(contamination=0.02) model.fit(time_series) outlier_mask = model.predict(time_series) outlier_mask[outlier_mask == -1] = 0 time_series = time_series[outlier_mask.astype('bool')] # Fall back to LedoitWolf print('Matrix estimation failed with Lasso and shrinkage due to ' 'ill conditions. Removing potential anomalies from the ' 'time-series using IsolationForest...') try: print("Trying Ledoit-Wolf Estimator...") conn_measure = ConnectivityMeasure( cov_estimator=covariance.LedoitWolf(store_precision=True, assume_centered=True), kind=kind) conn_matrix = conn_measure.fit_transform([time_series])[0] except (np.linalg.linalg.LinAlgError, FloatingPointError): print("Trying Oracle Approximating Shrinkage Estimator...") conn_measure = ConnectivityMeasure( cov_estimator=covariance.OAS(assume_centered=True), kind=kind) try: conn_matrix = conn_measure.fit_transform([time_series])[0] except (np.linalg.linalg.LinAlgError, FloatingPointError): raise ValueError('All covariance estimators failed to ' 'converge...') return conn_matrix if conn_model in nilearn_kinds: if conn_model == "corr" or conn_model == "cor" or conn_model == "correlation": print("\nComputing correlation matrix...\n") kind = "correlation" elif conn_model == "partcorr" or conn_model == "parcorr" or conn_model == "partialcorrelation": print("\nComputing partial correlation matrix...\n") kind = "partial correlation" elif conn_model == "sps" or conn_model == "sparse" or conn_model == "precision": print("\nComputing precision matrix...\n") kind = "precision" elif conn_model == "cov" or conn_model == "covariance" or conn_model == "covar": print("\nComputing covariance matrix...\n") kind = "covariance" else: try: raise ValueError( "\nERROR! No connectivity model specified at runtime. Select a" " valid estimator using the -mod flag.") except ValueError: sys.exit(1) # Try with the best-fitting Lasso estimator if estimator: conn_measure = ConnectivityMeasure(cov_estimator=estimator, kind=kind) try: conn_matrix = conn_measure.fit_transform([time_series])[0] except (np.linalg.linalg.LinAlgError, FloatingPointError): conn_matrix = fallback_covariance(time_series) else: conn_matrix = fallback_covariance(time_series) else: if conn_model == "QuicGraphicalLasso": try: from inverse_covariance import QuicGraphicalLasso except ImportError as e: print(e, "Cannot run QuicGraphLasso. Skggm not installed!") sys.exit(1) # Compute the sparse inverse covariance via QuicGraphLasso # credit: skggm model = QuicGraphicalLasso(init_method="cov", lam=0.5, mode="default", verbose=1) print( "\nCalculating QuicGraphLasso precision matrix using skggm...\n" ) model.fit(time_series) conn_matrix = model.precision_ elif conn_model == "QuicGraphicalLassoCV": try: from inverse_covariance import QuicGraphicalLassoCV except ImportError as e: print(e, "Cannot run QuicGraphLassoCV. Skggm not installed!") sys.exit(1) # Compute the sparse inverse covariance via QuicGraphLassoCV # credit: skggm model = QuicGraphicalLassoCV(init_method="cov", verbose=1) print("\nCalculating QuicGraphLassoCV precision matrix using" " skggm...\n") model.fit(time_series) conn_matrix = model.precision_ elif conn_model == "QuicGraphicalLassoEBIC": try: from inverse_covariance import QuicGraphicalLassoEBIC except ImportError as e: print(e, "Cannot run QuicGraphLassoEBIC. Skggm not installed!") sys.exit(1) # Compute the sparse inverse covariance via QuicGraphLassoEBIC # credit: skggm model = QuicGraphicalLassoEBIC(init_method="cov", verbose=1) print("\nCalculating QuicGraphLassoEBIC precision matrix using" " skggm...\n") model.fit(time_series) conn_matrix = model.precision_ elif conn_model == "AdaptiveQuicGraphicalLasso": try: from inverse_covariance import ( AdaptiveQuicGraphicalLasso, QuicGraphicalLassoEBIC, ) except ImportError as e: print(e, "Cannot run AdaptiveGraphLasso. Skggm not installed!") sys.exit(1) # Compute the sparse inverse covariance via # AdaptiveGraphLasso + QuicGraphLassoEBIC + method='binary' # credit: skggm model = AdaptiveQuicGraphicalLasso( estimator=QuicGraphicalLassoEBIC(init_method="cov", ), method="binary", ) print("\nCalculating AdaptiveQuicGraphLasso precision matrix using" " skggm...\n") model.fit(time_series) conn_matrix = model.estimator_.precision_ else: try: raise ValueError( "\nNo connectivity model specified at runtime. " "Select a valid estimator using the -mod flag.") except ValueError: import sys sys.exit(1) # Enforce symmetry conn_matrix = np.nan_to_num(np.maximum(conn_matrix, conn_matrix.T)) if conn_matrix.shape < (2, 2): raise RuntimeError( "\nMatrix estimation selection yielded an empty or" " 1-dimensional graph. " "Check time-series for errors or try using a different atlas") coords = np.array(coords) labels = np.array(labels) # assert coords.shape[0] == labels.shape[0] == conn_matrix.shape[0] del time_series return ( conn_matrix, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, roi, min_span_tree, disp_filt, parc, prune, atlas, uatlas, labels, coords, norm, binary, hpass, extract_strategy, )
def get_conn_matrix(time_series, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, roi, min_span_tree, disp_filt, parc, prune, atlas, uatlas, labels, coords, norm, binary, hpass, extract_strategy): """ Computes a functional connectivity matrix based on a node-extracted time-series array. Includes a library of routines across Nilearn, scikit-learn, and skggm packages, among others. Parameters ---------- time_series : array 2D m x n array consisting of the time-series signal for each ROI node where m = number of scans and n = number of ROI's. conn_model : str Connectivity estimation model (e.g. corr for correlation, cov for covariance, sps for precision covariance, partcorr for partial correlation). sps type is used by default. dir_path : str Path to directory containing subject derivative data for given run. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's. smooth : int Smoothing width (mm fwhm) to apply to time-series when extracting signal from ROI's. dens_thresh : bool Indicates whether a target graph density is to be used as the basis for thresholding. network : str Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default') used to filter nodes in the study of brain subgraphs. ID : str A subject id or other unique identifier. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. min_span_tree : bool Indicates whether local thresholding from the Minimum Spanning Tree should be used. disp_filt : bool Indicates whether local thresholding using a disparity filter and 'backbone network' should be used. parc : bool Indicates whether to use parcels instead of coordinates as ROI nodes. prune : bool Indicates whether to prune final graph of disconnected nodes/isolates. atlas : str Name of atlas parcellation used. uatlas : str File path to atlas parcellation Nifti1Image in MNI template space. labels : list List of string labels corresponding to ROI nodes. coords : list List of (x, y, z) tuples corresponding to a coordinate atlas used or which represent the center-of-mass of each parcellation node. norm : int Indicates method of normalizing resulting graph. binary : bool Indicates whether to binarize resulting graph edges to form an unweighted graph. hpass : bool High-pass filter values (Hz) to apply to node-extracted time-series. extract_strategy : str The name of a valid function used to reduce the time-series region extraction. Returns ------- conn_matrix : array Adjacency matrix stored as an m x n array of nodes and edges. conn_model : str Connectivity estimation model (e.g. corr for correlation, cov for covariance, sps for precision covariance, partcorr for partial correlation). sps type is used by default. dir_path : str Path to directory containing subject derivative data for given run. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's for tracking. smooth : int Smoothing width (mm fwhm) to apply to time-series when extracting signal from ROI's. dens_thresh : bool Indicates whether a target graph density is to be used as the basis for thresholding. network : str Resting-state network based on Yeo-7 and Yeo-17 naming (e.g. 'Default') used to filter nodes in the study of brain subgraphs. ID : str A subject id or other unique identifier. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. min_span_tree : bool Indicates whether local thresholding from the Minimum Spanning Tree should be used. disp_filt : bool Indicates whether local thresholding using a disparity filter and 'backbone network' should be used. parc : bool Indicates whether to use parcels instead of coordinates as ROI nodes. prune : bool Indicates whether to prune final graph of disconnected nodes/isolates. atlas : str Name of atlas parcellation used. uatlas : str File path to atlas parcellation Nifti1Image in MNI template space. labels : list List of string labels corresponding to graph nodes. coords : list List of (x, y, z) tuples corresponding to a coordinate atlas used or which represent the center-of-mass of each parcellation node. norm : int Indicates method of normalizing resulting graph. binary : bool Indicates whether to binarize resulting graph edges to form an unweighted graph. hpass : bool High-pass filter values (Hz) to apply to node-extracted time-series. extract_strategy : str The name of a valid function used to reduce the time-series region extraction. References ---------- .. [1] Varoquaux, G., & Craddock, R. C. (2013). Learning and comparing functional connectomes across subjects. NeuroImage. https://doi.org/10.1016/j.neuroimage.2013.04.007 .. [2] Jason Laska, Manjari Narayan, 2017. skggm 0.2.7: A scikit-learn compatible package for Gaussian and related Graphical Models. doi:10.5281/zenodo.830033 """ from nilearn.connectome import ConnectivityMeasure from sklearn.covariance import GraphicalLassoCV conn_matrix = None if conn_model == 'corr' or conn_model == 'cor' or conn_model == 'correlation': # credit: nilearn print('\nComputing correlation matrix...\n') conn_measure = ConnectivityMeasure(kind='correlation') conn_matrix = conn_measure.fit_transform([time_series])[0] elif conn_model == 'partcorr' or conn_model == 'parcorr' or conn_model == 'partialcorrelation': # credit: nilearn print('\nComputing partial correlation matrix...\n') conn_measure = ConnectivityMeasure(kind='partial correlation') conn_matrix = conn_measure.fit_transform([time_series])[0] elif conn_model == 'cov' or conn_model == 'covariance' or conn_model == 'covar' or conn_model == 'sps' or \ conn_model == 'sparse' or conn_model == 'precision': # Fit estimator to matrix to get sparse matrix estimator_shrunk = None estimator = GraphicalLassoCV(cv=5) try: print('\nComputing covariance...\n') estimator.fit(time_series) except: print('Unstable Lasso estimation--Attempting to re-run by first applying shrinkage...') try: from sklearn.covariance import GraphicalLasso, empirical_covariance, shrunk_covariance emp_cov = empirical_covariance(time_series) for i in np.arange(0.8, 0.99, 0.01): shrunk_cov = shrunk_covariance(emp_cov, shrinkage=i) alphaRange = 10.0 ** np.arange(-8, 0) for alpha in alphaRange: try: estimator_shrunk = GraphicalLasso(alpha) estimator_shrunk.fit(shrunk_cov) print(f"Retrying covariance matrix estimate with alpha={alpha}") if estimator_shrunk is None: pass else: break except: print(f"Covariance estimation failed with shrinkage at alpha={alpha}") continue except ValueError: print('Unstable Lasso estimation! Shrinkage failed. A different connectivity model may be needed.') if estimator is None and estimator_shrunk is None: raise RuntimeError('\nERROR: Covariance estimation failed.') if conn_model == 'sps' or conn_model == 'sparse' or conn_model == 'precision': if estimator_shrunk is None: print('\nFetching precision matrix from covariance estimator...\n') conn_matrix = -estimator.precision_ else: print('\nFetching shrunk precision matrix from covariance estimator...\n') conn_matrix = -estimator_shrunk.precision_ elif conn_model == 'cov' or conn_model == 'covariance' or conn_model == 'covar': if estimator_shrunk is None: print('\nFetching covariance matrix from covariance estimator...\n') conn_matrix = estimator.covariance_ else: conn_matrix = estimator_shrunk.covariance_ elif conn_model == 'QuicGraphicalLasso': try: from inverse_covariance import QuicGraphicalLasso except ImportError: print('Cannot run QuicGraphLasso. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLasso # credit: skggm model = QuicGraphicalLasso( init_method='cov', lam=0.5, mode='default', verbose=1) print('\nCalculating QuicGraphLasso precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'QuicGraphicalLassoCV': try: from inverse_covariance import QuicGraphicalLassoCV except ImportError: print('Cannot run QuicGraphLassoCV. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLassoCV # credit: skggm model = QuicGraphicalLassoCV( init_method='cov', verbose=1) print('\nCalculating QuicGraphLassoCV precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'QuicGraphicalLassoEBIC': try: from inverse_covariance import QuicGraphicalLassoEBIC except ImportError: print('Cannot run QuicGraphLassoEBIC. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLassoEBIC # credit: skggm model = QuicGraphicalLassoEBIC( init_method='cov', verbose=1) print('\nCalculating QuicGraphLassoEBIC precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'AdaptiveQuicGraphicalLasso': try: from inverse_covariance import AdaptiveQuicGraphicalLasso, QuicGraphicalLassoEBIC except ImportError: print('Cannot run AdaptiveGraphLasso. Skggm not installed!') # Compute the sparse inverse covariance via # AdaptiveGraphLasso + QuicGraphLassoEBIC + method='binary' # credit: skggm model = AdaptiveQuicGraphicalLasso( estimator=QuicGraphicalLassoEBIC( init_method='cov', ), method='binary', ) print('\nCalculating AdaptiveQuicGraphLasso precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.estimator_.precision_ else: raise ValueError('\nERROR! No connectivity model specified at runtime. Select a valid estimator using the ' '-mod flag.') # Enforce symmetry conn_matrix = np.maximum(conn_matrix, conn_matrix.T) if conn_matrix.shape < (2, 2): raise RuntimeError('\nERROR! Matrix estimation selection yielded an empty or 1-dimensional graph. ' 'Check time-series for errors or try using a different atlas') coords = np.array(coords) labels = np.array(labels) del time_series return (conn_matrix, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, roi, min_span_tree, disp_filt, parc, prune, atlas, uatlas, labels, coords, norm, binary, hpass, extract_strategy)
def get_conn_matrix(time_series, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, mask, min_span_tree, disp_filt, parc, prune, atlas_select, uatlas_select, label_names, coords, vox_array): from nilearn.connectome import ConnectivityMeasure from sklearn.covariance import GraphLassoCV conn_matrix = None if conn_model == 'corr': # credit: nilearn print('\nComputing correlation matrix...\n') conn_measure = ConnectivityMeasure(kind='correlation') conn_matrix = conn_measure.fit_transform([time_series])[0] elif conn_model == 'partcorr': # credit: nilearn print('\nComputing partial correlation matrix...\n') conn_measure = ConnectivityMeasure(kind='partial correlation') conn_matrix = conn_measure.fit_transform([time_series])[0] elif conn_model == 'cov' or conn_model == 'sps': # Fit estimator to matrix to get sparse matrix estimator_shrunk = None estimator = GraphLassoCV() try: print('\nComputing covariance...\n') estimator.fit(time_series) except: print( 'Unstable Lasso estimation--Attempting to re-run by first applying shrinkage...' ) try: from sklearn.covariance import GraphLasso, empirical_covariance, shrunk_covariance emp_cov = empirical_covariance(time_series) for i in np.arange(0.8, 0.99, 0.01): shrunk_cov = shrunk_covariance(emp_cov, shrinkage=i) alphaRange = 10.0**np.arange(-8, 0) for alpha in alphaRange: try: estimator_shrunk = GraphLasso(alpha) estimator_shrunk.fit(shrunk_cov) print( "Retrying covariance matrix estimate with alpha=%s" % alpha) if estimator_shrunk is None: pass else: break except: print( "Covariance estimation failed with shrinkage at alpha=%s" % alpha) continue except ValueError: print( 'Unstable Lasso estimation! Shrinkage failed. A different connectivity model may be needed.' ) if estimator is None and estimator_shrunk is None: raise RuntimeError('ERROR: Covariance estimation failed.') if conn_model == 'sps': if estimator_shrunk is None: print( '\nFetching precision matrix from covariance estimator...\n' ) conn_matrix = -estimator.precision_ else: print( '\nFetching shrunk precision matrix from covariance estimator...\n' ) conn_matrix = -estimator_shrunk.precision_ elif conn_model == 'cov': if estimator_shrunk is None: print( '\nFetching covariance matrix from covariance estimator...\n' ) conn_matrix = estimator.covariance_ else: conn_matrix = estimator_shrunk.covariance_ elif conn_model == 'QuicGraphicalLasso': try: from inverse_covariance import QuicGraphicalLasso except ImportError: print('Cannot run QuicGraphLasso. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLasso # credit: skggm model = QuicGraphicalLasso(init_method='cov', lam=0.5, mode='default', verbose=1) print('\nCalculating QuicGraphLasso precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'QuicGraphLassoCV': try: from inverse_covariance import QuicGraphicalLassoCV except ImportError: print('Cannot run QuicGraphLassoCV. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLassoCV # credit: skggm model = QuicGraphicalLassoCV(init_method='cov', verbose=1) print( '\nCalculating QuicGraphLassoCV precision matrix using skggm...\n') model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'QuicGraphicalLassoEBIC': try: from inverse_covariance import QuicGraphicalLassoEBIC except ImportError: print('Cannot run QuicGraphLassoEBIC. Skggm not installed!') # Compute the sparse inverse covariance via QuicGraphLassoEBIC # credit: skggm model = QuicGraphicalLassoEBIC(init_method='cov', verbose=1) print( '\nCalculating QuicGraphLassoEBIC precision matrix using skggm...\n' ) model.fit(time_series) conn_matrix = -model.precision_ elif conn_model == 'AdaptiveQuicGraphLasso': try: from inverse_covariance import AdaptiveQuicGraphicalLasso, QuicGraphicalLassoEBIC except ImportError: print('Cannot run AdaptiveGraphLasso. Skggm not installed!') # Compute the sparse inverse covariance via # AdaptiveGraphLasso + QuicGraphLassoEBIC + method='binary' # credit: skggm model = AdaptiveQuicGraphicalLasso( estimator=QuicGraphicalLassoEBIC(init_method='cov', ), method='binary', ) print( '\nCalculating AdaptiveQuicGraphLasso precision matrix using skggm...\n' ) model.fit(time_series) conn_matrix = -model.estimator_.precision_ # Weight reuslting matrix by voxels in each label if using parcels as nodes # if parc is True: # norm_parcels = (vox_array - min(vox_array)) / (max(vox_array) - min(vox_array)) # conn_matrix_norm = normalize(conn_matrix) # conn_matrix = norm_parcels * conn_matrix_norm coords = np.array(coords) label_names = np.array(label_names) return conn_matrix, conn_model, dir_path, node_size, smooth, dens_thresh, network, ID, mask, min_span_tree, disp_filt, parc, prune, atlas_select, uatlas_select, label_names, coords
############################################################################### # Extract and plot sparse inverse covariance estimator_type = "QuicGraphicalLasso" if estimator_type == "QuicGraphicalLasso": # Compute the sparse inverse covariance via QuicGraphicalLasso estimator = QuicGraphicalLasso(init_method="cov", lam=0.5, mode="default", verbose=1) estimator.fit(timeseries) elif estimator_type == "QuicGraphicalLassoCV": # Compute the sparse inverse covariance via QuicGraphicalLassoCV estimator = QuicGraphicalLassoCV(init_method="cov", verbose=1) estimator.fit(timeseries) elif estimator_type == "QuicGraphicalLassoEBIC": # Compute the sparse inverse covariance via QuicGraphicalLassoEBIC estimator = QuicGraphicalLassoEBIC(init_method="cov", verbose=1) estimator.fit(timeseries) elif estimator_type == "AdaptiveQuicGraphicalLasso": # Compute the sparse inverse covariance via # AdaptiveGraphicalLasso + QuicGraphicalLassoEBIC + method='binary' model = AdaptiveGraphicalLasso( estimator=QuicGraphicalLassoEBIC(init_method="cov"), method="binary") model.fit(timeseries) estimator = model.estimator_
class TestAdaptiveGraphicalLasso(object): @pytest.mark.parametrize( "params_in", [ ({ "estimator": QuicGraphicalLassoCV( cv=2, n_refinements=6, init_method="cov", score_metric="log_likelihood", ), "method": "binary", }), ({ "estimator": QuicGraphicalLassoCV( cv=2, n_refinements=6, init_method="cov", score_metric="log_likelihood", ), "method": "inverse", }), ({ "estimator": QuicGraphicalLassoCV( cv=2, n_refinements=6, init_method="cov", score_metric="log_likelihood", ), "method": "inverse_squared", }), ({ "estimator": QuicGraphicalLassoEBIC(), "method": "binary" }), ({ "estimator": QuicGraphicalLassoEBIC(), "method": "inverse" }), ({ "estimator": QuicGraphicalLassoEBIC(), "method": "inverse_squared" }), ], ) def test_integration_adaptive_graphical_lasso(self, params_in): """ Just tests inputs/outputs (not validity of result). """ n_features = 20 n_samples = 25 cov, prec, adj = ClusterGraph(n_blocks=1, chain_blocks=False, seed=1).create(n_features, 0.8) prng = np.random.RandomState(2) X = prng.multivariate_normal(np.zeros(n_features), cov, size=n_samples) model = AdaptiveGraphicalLasso(**params_in) model.fit(X) assert model.estimator_ is not None assert model.lam_ is not None assert np.sum(model.lam_[np.diag_indices(n_features)]) == 0 if params_in["method"] == "binary": uvals = set(model.lam_.flat) assert len(uvals) == 2 assert 0 in uvals assert 1 in uvals elif (params_in["method"] == "inverse" or params_in["method"] == "inverse_squared"): uvals = set(model.lam_.flat[model.lam_.flat != 0]) assert len(uvals) > 0