junifer/examples/run_junifer_julearn.py

123 lines
3.6 KiB
Python

"""
Run junifer and julearn.
========================
This example uses a ParcelAggregation marker to compute the mean of each parcel
using the Schaefer parcellation (100 rois, 7 Yeo networks) for a 3D nifti to
extract some features for machine learning using julearn to predict some other
data.
Authors: Leonard Sasse, Sami Hamdan, Nicolas Nieto, Synchon Mandal
License: BSD 3 clause
"""
import tempfile
import nilearn
import pandas as pd
from julearn import run_cross_validation, PipelineCreator
import junifer.testing.registry # noqa: F401
from junifer.api import collect, run
from junifer.storage import SQLiteFeatureStorage
from junifer.utils import configure_logging
###############################################################################
# Set the logging level to info to see extra information:
configure_logging(level="INFO")
###############################################################################
# Define the markers you want:
marker_dicts = [
{
"name": "Schaefer100x17_TrimMean80",
"kind": "ParcelAggregation",
"parcellation": "Schaefer100x17",
"method": "trim_mean",
"method_params": {"proportiontocut": 0.2},
},
{
"name": "Schaefer200x17_Mean",
"kind": "ParcelAggregation",
"parcellation": "Schaefer200x17",
"method": "mean",
},
]
###############################################################################
# Define target and confounds for julearn machine learning:
y = "age"
confound = "sex"
###############################################################################
# Load the VBM phenotype data for machine learning data:
# - Fetch the Oasis dataset
oasis_dataset = nilearn.datasets.fetch_oasis_vbm()
age = oasis_dataset.ext_vars[y][:10]
sex = (
pd.Series(oasis_dataset.ext_vars["mf"][:10])
.map(lambda x: 1 if x == "F" else 0)
.values
)
###############################################################################
# Create a temporary directory for junifer feature extraction:
with tempfile.TemporaryDirectory() as tmpdir:
storage = {"kind": "SQLiteFeatureStorage", "uri": f"{tmpdir}/test.sqlite"}
# run the defined junifer feature extraction pipeline
run(
workdir="/tmp",
datagrabber={"kind": "OasisVBMTestingDataGrabber"},
markers=marker_dicts,
storage=storage,
)
# read in extracted features and add confounds and targets
# for julearn run cross validation
collect(storage)
db = SQLiteFeatureStorage(uri=storage["uri"])
df_vbm = db.read_df(feature_name="VBM_GM_Schaefer200x17_Mean_aggregation")
oasis_subjects = [x[0] for x in df_vbm.index]
df_vbm.index = oasis_subjects
###############################################################################
# Using julearn for machine learning:
# We predict the age given our vbm features and sex as a confound.
X = list(df_vbm.columns)
df_vbm[y] = age
df_vbm[confound] = sex
X_types = {
"features": X,
"confound": confound,
}
creator = PipelineCreator(problem_type="regression", apply_to="features")
creator.add("zscore", apply_to=["features", "confound"])
creator.add("confound_removal", apply_to="features", confounds="confound")
creator.add("ridge")
scores = run_cross_validation(
X=X + [confound],
y=y,
X_types=X_types,
data=df_vbm,
model=creator,
cv=3,
)
print(scores)
###############################################################################
# Interpretation of results:
# Doing machine learning with only 10 datapoints is not meaningful.
# This explains the big variation in scores
# for different cross-validation folds.