Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NeDis: Network-based disruption analysis of biological coordination

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

Quickstart

Install

# 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 develop

You 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-publication

Load example data

random_state = 43
from 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);

png

Configure and fit correlation disruption

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)

Visualize disrupted modules

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_cluster
y_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()

png

png

png

Advanced usage

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_threshold and separation_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

Default behavior

# 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))

Knowledge-defined clustering

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))

Reproducing results and figures from the paper

If you want to run notebooks via nbconvert, install it:

conda activate nalab-cordis-publication
conda install -c conda-forge nbconvert

Prepare data

Healthy pregnancies

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 ..

Preeclamptic pregnancies

  • 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.rda file into the data/preeclampsia folder.
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 ../..

Experiments on real-world data

Notebooks:

  • notebooks/01_exp_regression.ipynb
  • notebooks/02_exp_classification.ipynb
  • notebooks/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.ipynb

Experiments on synthetic data

Notebooks:

  • 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.ipynb

Figure 1

Notebooks:

  • 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.ipynb

Supplement experiments

For the supplemental experiments, please also refer to the following notebooks:

  • 05.01_supplement_clustering.ipynb
  • 05.02_supplement_overlap.ipynb
  • 05.03_supplement_comparison.ipynb
  • 05.04_supplement_custom-clustering.ipynb

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages