Motivation. Biological systems comprise a vast amount of intricate processes that are deeply interconnected and carefully coordinated. These systems must adapt to stimuli and challenge – often through dynamic functional changes in how the corresponding processes interact. However, the associated complex disruption patterns are hard to capture, particularly when analyzing large amounts of measured biomarkers and focusing on individual markers without accounting for their dependencies.
Results. To address this, we provide NeDis , an easy to use and highly customizable open-source package that allows to capture disruption properties of biomarker networks across conditions and timepoints, and discover modules with exceptional disruption profiles. NeDis employs the notion of correlation disruption which quantifies functional disruptions and enables a novel perspective on the coordination and adaption of biological systems to stimuli and challenge. Our examples illustrate the scope of NeDis , by revealing coordinated functional adaptions of the immune system during pregnancy
# will be replaced by installing from PyPi upon publication
conda env create -f environment.yml --name nalab-cordis-publication
conda activate nalab-cordis-publication
python setup.py developYou can now run jupyter lab (by default a browser should open at http://localhost:8080) and play with the notebooks in the notebooks folder. For example, you can find this README as a notebook: notebooks/README.ipynb.
If you already have a Jupyter environment set up, you can
- register the current environment with Jupyter using the following command
- change the kernel of the notebooks accordingly within the corresponding Jupyter notebook.
# optionally register the current environment as a jupyter kernel
python -m ipykernel install --user --name=nalab-cordis-publicationrandom_state = 43from nedis.data.synthetic import load_example
from nedis.visualization import visualize_data# load data
X, y, entities, labels = load_example(random_state=random_state)
# visualize
fig, axes, correlation_matrices, coordinates = visualize_data(
X, y, entities, mode="network", random_state=random_state);from nedis.cordis.default \
import DefaultCorrelationDisruptionFeatureTransformer \
as DefaultCorrelationDisruptionTransformer# configure and fir correlation disruption transformer
disruption_transformer = DefaultCorrelationDisruptionTransformer(
default_optimization_separation_score="spearman",
default_derive_features_aggregation="mean")
disruption_transformer.fit(X, y, groups=entities, subset_masks="y");# transform samples
disruption_values = disruption_transformer.transform(X)# we get one aggregated disruption value per cluster for each sample
disruption_values.shape(500, 3)
import numpy as np
import scipy.stats
import matplotlib.pyplot as plt
import seaborn as sns
from nedis.visualization import plot_cordis_cluster as plot_clustery_unique = np.unique(y)
for i_cluster, cluster in enumerate(disruption_transformer.selected_clusters_):
values = disruption_values[:, i_cluster]
r, p = scipy.stats.spearmanr(values, y)
fig, axes = plt.subplots(
1, len(y_unique) + 1,
figsize=(4 * 1 * (len(y_unique) + 1), 4 * 1),
dpi=300)
# correlation disruption plot
ax = axes[0]
x_rank = scipy.stats.rankdata(y, method="dense")
sns.lineplot(x=x_rank, y=values, hue=entities, color="blue", alpha=0.1, ax=ax)
sns.lineplot(x=x_rank, y=values, ax=ax)
ax.set(
xlabel="timepoints",
xticks=np.unique(x_rank),
xticklabels= y_unique,
ylabel="disruption",
title=f"r={r:.02f}"
)
ax.get_legend().remove()
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
# cluster visualization
for i, yy in enumerate(y_unique):
ax = axes[i + 1]
ax.axis("off")
plot_cluster(
cluster,
coordinates,
correlation_matrices[yy],
correlation_threshold=0,
verbose=0,
ax=ax)
fig.suptitle(
f"Cluster: Reference data={cluster['reference_label']}, Id={cluster['id']}")
plt.show()DefaultCorrelationDisruptionFeatureTransformer used above is a simplified wrapper for CorrelationDisruption.
CorrelationDisruption has three main important steps that need to be configured:
- the clustering step (
cluster_step) - the optimization step (
optimization_step) - and the filtering behavior (
filter_coverage_thresholdandseparation_score_threshold)
from nedis.cluster.leidenalg import WeightedLeidenClustering
from nedis.cordis.clustering import ReferenceCorrelationMatrixClusteringStep
from nedis.cordis.optimization import GreedyRefinementOptimizationStep
from nedis.cordis.disruption import CorrelationDisruption# NOTE: you can use any cluster algorithm that assigns a cluster label to each feature
clustering_algorithm = WeightedLeidenClustering(random_state=random_state)
clustering_step = ReferenceCorrelationMatrixClusteringStep(
clustering_algorithm=clustering_algorithm,
# clustering_absolute_correlation=True,
# correlation_function="spearman",
# feature_filters=None
)
optimization_step = GreedyRefinementOptimizationStep(
separation_score="spearman",
# separation_score_comparison='all',
# refinement_mode="rows-and-columns",
# correlation_function="spearman",
# disruption_metric="direction",
# disruption_robustness='loo',
# disruption_aggregation='mean',
# max_runs=-1
)
codi = CorrelationDisruption(
clustering_step=clustering_step,
cluster_optimization_step=optimization_step,
# filtering
filter_coverage_threshold=0.5,
separation_score_threshold=("auto", 1)
)
codi.fit(X, y, subset_masks="y")CorrelationDisruption(cluster_optimization_step=<nedis.cordis.optimization.GreedyRefinementOptimizationStep object at 0x7fa55bf8f490>,
clustering_step=ReferenceCorrelationMatrixClusteringStep(clustering_algorithm=WeightedLeidenClustering(random_state=43)),
filter_coverage_threshold=0.5,
separation_score_threshold=('auto', 1))
This is an example of customization that allows to introduce knowledge-defined clustering and skip the optimization step, i.e., clustering pre-defined by the user rather than using a clustering algorithm.
from nedis.cordis.clustering import (
ListClusteringStep, ReferenceFeatureLabelClusteringStep, init_cluster)
from nedis.cordis.optimization import (
ReferenceScoreOptimizationStep)# use to define clusters by feature labels
# `labels` is defined in the data creation above
clustering_step = ReferenceFeatureLabelClusteringStep(labels)
# # ALTERNATIVE: completely custom clusters
# clustering_step = ListClusteringStep([
# init_cluster(reference_label=0, reference_shape=X.shape[1], rows=np.arange(0,5)),
# init_cluster(reference_label=4, reference_shape=X.shape[1], rows=np.arange(5,15)),
# init_cluster(reference_label=0, reference_shape=X.shape[1], rows=np.arange(15,25)),
# ])
# use this to prevent optimization
# ALTERNATIVE: use the GreedyRefinementOptimizationStep from above
optimization_step = ReferenceScoreOptimizationStep(
separation_score="spearman",
)
codi = CorrelationDisruption(
clustering_step=clustering_step,
cluster_optimization_step=optimization_step,
# filtering
filter_coverage_threshold=0.5,
separation_score_threshold=("auto", 1)
)
codi.fit(X, y, subset_masks="y")CorrelationDisruption(cluster_optimization_step=<nedis.cordis.optimization.ReferenceScoreOptimizationStep object at 0x7fa5680eda90>,
clustering_step=ReferenceFeatureLabelClusteringStep(feature_labels=array([ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1])),
filter_coverage_threshold=0.5,
separation_score_threshold=('auto', 1))
If you want to run notebooks via nbconvert, install it:
conda activate nalab-cordis-publication
conda install -c conda-forge nbconvert- For the healthy pregnancy dataset, download the data archive from: https://nalab.stanford.edu/multiomics-pregnancy/
- Extract the archive and put the
Data.Rdafile into thedata/multiomicsfolder.
mkdir -p data; cd data
wget https://nalab.stanford.edu/wp-content/uploads/termpregnancymultiomics.zip
unzip termpregnancymultiomics.zip; rm termpregnancymultiomics.zip
rm -rf multiomics
mv termpregnancymultiomics multiomics
cd ..- For the preeclampsia dataset, download the data archive from: https://nalab.stanford.edu/codi/
- Extract the archive and put the
2019-12-04_Preeclampsia-data.rdafile into thedata/preeclampsiafolder.
mkdir -p data/preeclampsia; cd data/preeclampsia
wget https://nalab.stanford.edu/wp-content/uploads/codi_preeclampsia-data.zip
unzip codi_preeclampsia-data.zip; rm codi_preeclampsia-data.zip
cd ../..Notebooks:
notebooks/01_exp_regression.ipynbnotebooks/02_exp_classification.ipynbnotebooks/07_perturbation.ipynb
The code for reproducing the results on the real world datasets are found in the above mentioned notebooks.
Please start Jupyter as outlined in Install and run the notebooks, or use nbconvert --execute or papermill.
The produced figures will be in _out/realworld.
# using nbconvert
jupyter nbconvert --stdout --ExecutePreprocessor.kernel_name=python --to notebook --execute notebooks/01_exp_regression.ipynb
jupyter nbconvert --stdout --ExecutePreprocessor.kernel_name=python --to notebook --execute notebooks/02_exp_classification.ipynbNotebooks:
notebooks/03_synthetic.ipynb
The code for reproducing the results on synthetic data that show the properties and characteristics of the proposed correlation disruption method are found in the above mentioned notebook.
Please start Jupyter as outlined in Install and run the notebook, or use nbconvert --execute or papermill.
The produced figures will be in _out/synthetic.
# using nbconvert
jupyter nbconvert --stdout --ExecutePreprocessor.kernel_name=python --to notebook --execute notebooks/03_synthetic.ipynbNotebooks:
notebooks/04_figure1.ipynb
The code for reproducing the panels in Figure 1 from the manuscript are found in the above mentioned notebook.
Please start Jupyter as outlined in Install and run the notebook, or use nbconvert --execute or papermill.
The produced figures will be in _out/figure1.
# using nbconvert
jupyter nbconvert --stdout --ExecutePreprocessor.kernel_name=python --to notebook --execute notebooks/04_figure1.ipynbFor the supplemental experiments, please also refer to the following notebooks:
05.01_supplement_clustering.ipynb05.02_supplement_overlap.ipynb05.03_supplement_comparison.ipynb05.04_supplement_custom-clustering.ipynb