napistu.network.net_propagation

Network propagation with null distribution testing.

This module provides functions for propagating vertex attributes over a network (e.g. personalized PageRank) and testing observed scores against null distributions. Supported null strategies include vertex permutation, edge permutation, parametric, and uniform, enabling network-based significance testing for gene prioritization and related analyses.

Public Functions

melt_propagation_results(propagation_results, index_name, attribute_name)

Melt results from network_propagation_with_null into a tall format.

net_propagate_attributes(graph, attributes, propagation_method, …)

Propagate multiple attributes over a network using a propagation method.

network_propagation_with_null(graph, attributes, null_strategy, …, quantile_method=…)

Apply network propagation and compare observed scores to a null distribution.

network_propagation_with_null_repeated(…, n_runs=…)

Run network_propagation_with_null multiple times and merge summaries (lower peak null RAM).

Functions

melt_propagation_results(propagation_results)

Melt results from network_propagation_with_null into a tall format.

net_propagate_attributes(graph, attributes)

Propagate multiple attributes over a network using a network propagation method.

network_propagation_with_null(graph, attributes)

Apply network propagation to attributes and compare against null distributions.

network_propagation_with_null_repeated(...)

Call network_propagation_with_null() several times with the same inputs and merge.

Classes

PropagationMethod(method, non_negative)

class napistu.network.net_propagation.PropagationMethod(method: <built-in function callable>, non_negative: bool)

Bases: object

__init__(method: callable, non_negative: bool) None
method: callable
non_negative: bool
napistu.network.net_propagation._allocate_samples_across_attributes(n_samples: int, n_attributes: int) List[int]

Distribute n_samples across n_attributes as evenly as possible.

Each attribute receives base = n_samples // n_attributes samples. The first (n_samples % n_attributes) attributes receive one additional sample, so the total returned matches n_samples exactly.

If n_samples < n_attributes, a warning is issued and only the first n_samples attributes contribute one sample each. The remainder receive zero samples.

Parameters:
  • n_samples (int) – Total samples to distribute.

  • n_attributes (int) – Number of attributes to distribute across.

Returns:

Per-attribute sample counts, summing to min(n_samples, n_attributes) in the underflow case or n_samples otherwise.

Return type:

List[int]

napistu.network.net_propagation._attr_pooled_vertex_permutation_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, mask: str | ndarray | List | Dict | None = 'attr', n_samples: int = 100, verbose: bool = False) DataFrame

Generate null distribution by permuting each attribute’s values within its mask, propagating, and pooling the resulting propagated vectors across attributes into a shared null distribution.

Each null sample is generated by selecting one attribute, permuting its masked values without replacement, propagating the resulting reset vector, and broadcasting the propagated result across all attribute columns. This preserves per-attribute sparsity and magnitude profile (each null draw inherits the exact non-zero pattern of its source attribute) while still pooling propagated outputs across attributes for variance reduction in the null estimate.

The total number of propagation calls is n_samples, matching the cost of pooled_vertex_permutation_null and avoiding the n_samples * n_attributes cost of plain vertex_permutation_null.

Sample allocation

n_samples is distributed across attributes as evenly as possible: base = n_samples // n_attributes samples per attribute, with the first (n_samples % n_attributes) attributes receiving one additional sample. The total number of samples returned exactly equals n_samples, which is important for p-value resolution downstream.

If n_samples < n_attributes, a warning is issued and only the first n_samples attributes contribute one sample each. Consider increasing n_samples or switching to vertex_permutation_null in this regime.

Assumptions

All attributes must share an identical mask. Attributes are assumed to occupy the same subgraph (same set of measurable vertices), so pooling propagated outputs across attributes produces a meaningful shared null. Unlike pooled_vertex_permutation_null, this method does not assume attributes are exchangeable in magnitude or sparsity — each null draw preserves the source attribute’s own profile.

When to prefer this over pooled_vertex_permutation_null

When attributes share a mask (same measurable subgraph) but differ in sparsity or magnitude profile. pooled_vertex_permutation_null mixes values across attributes indiscriminately, which causes systematic shifts in log2 enrichment for atypical attributes when propagation is nonlinear in reset concentration (as with personalized PageRank). This method eliminates that bias by keeping each null draw’s reset profile faithful to a real attribute, while still benefiting from cross-attribute pooling at the propagated-output stage.

param graph:

Input graph.

type graph:

ig.Graph

param attributes:

Attribute names to generate nulls for. All must share the same mask.

type attributes:

List[str]

param propagation_method:

Network propagation method to apply.

type propagation_method:

str or PropagationMethod

param additional_propagation_args:

Additional arguments to pass to the network propagation method.

type additional_propagation_args:

dict, optional

param mask:

Mask specification. Default is “attr” (use each attribute as its own mask). All attributes must resolve to the same mask.

type mask:

str, np.ndarray, List, Dict, or None

param n_samples:

Total number of null samples to generate, distributed across attributes.

type n_samples:

int

param verbose:

Extra reporting. Default is False.

type verbose:

bool, optional

returns:

Propagated null samples with shape (n_samples * n_nodes, n_attributes). Each block of n_nodes rows corresponds to one null sample, with the same propagated vector broadcast across all attribute columns.

rtype:

pd.DataFrame

napistu.network.net_propagation._build_pooled_universe(graph: Graph, attributes: List[str], mask: ndarray) ndarray

Collect all masked values across all attributes into a single array.

Includes zeros so that the pooled universe reflects the joint distribution of magnitude and sparsity across attributes. Sampling from this universe yields null reset vectors whose expected sparsity matches the pooled population average, rather than forcing every masked position to be non-zero.

napistu.network.net_propagation._compute_log2_enrichment(observed: DataFrame, null_df: DataFrame, epsilon: float = 1e-10) DataFrame

Compute log2 enrichment of observed scores relative to the mean null distribution.

Parameters:
  • observed (pd.DataFrame) – DataFrame with features as index and attributes as columns containing observed propagated scores.

  • null_df (pd.DataFrame) – Stacked null samples with features as index (multiple rows per feature) and attributes as columns. Same format as output of null generator functions.

  • epsilon (float) – Small value added to null mean to avoid division by zero (defaults to LOG2_ENRICHMENT_EPSILON).

Returns:

DataFrame with same structure as observed containing log2(observed / mean_null). Positive values indicate observed score exceeds the mean null; negative values indicate observed score is below mean null.

Return type:

pd.DataFrame

Notes

The interpretation of log2_enrichment depends on the null strategy used: - Vertex permutation null: enrichment relative to topology-matched baseline;

a value of 1.0 means the observed score is 2x the mean null score for a vertex with the same network position but randomized signal assignment.

  • Uniform null: enrichment relative to a flat baseline; more sensitive to

    topological biases since the null does not account for network structure.

napistu.network.net_propagation._edge_permutation_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, burn_in_ratio: float = 10, sampling_ratio: float = 0.1, n_samples: int = 100, verbose: bool = False) DataFrame

Generate null distribution by edge rewiring and apply propagation method.

Parameters:
  • graph (ig.Graph) – Input graph.

  • attributes (List[str]) – Attribute names to use (values unchanged by rewiring).

  • propagation_method (str or PropagationMethod) – Network propagation method to apply.

  • additional_propagation_args (dict, optional) – Additional arguments to pass to the network propagation method.

  • burn_in_ratio (float) – Multiplier for initial rewiring.

  • sampling_ratio (float) – Proportion of edges to rewire between samples.

  • n_samples (int) – Number of null samples to generate.

  • verbose (bool, optional) – Extra reporting. Default is False.

Returns:

Propagated null samples from rewired network. Shape: (n_samples * n_nodes, n_attributes)

Return type:

pd.DataFrame

napistu.network.net_propagation._ensure_propagation_method(propagation_method: str | PropagationMethod) PropagationMethod
napistu.network.net_propagation._fit_distribution_parameters(graph: Graph, attributes: List[str], masks: Dict[str, ndarray], distribution: Any, fit_kwargs: Dict[str, Any]) Dict[str, Dict[str, Any]]

Fit distribution parameters for each attribute using masked data.

napistu.network.net_propagation._generate_parametric_null_sample(null_graph: Graph, attributes: List[str], params: Dict[str, Dict[str, Any]], ensure_nonnegative: bool) None

Generate one null sample by modifying graph attributes in-place.

napistu.network.net_propagation._get_distribution_object(distribution: str | Any) Any

Get scipy.stats distribution object from string name or object.

napistu.network.net_propagation._get_null_generator(strategy: str)

Get null generator function by name.

napistu.network.net_propagation._merge_propagation_null_run_outputs(runs: List[DataFrame], *, log2_enrichment_epsilon: float = 1e-10) DataFrame

Merge multiple network_propagation_with_null results from independent RNG runs.

napistu.network.net_propagation._pagerank_wrapper(graph: Graph, attr_data: ndarray, **kwargs)
napistu.network.net_propagation._parametric_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', distribution: str | Any = 'norm', additional_propagation_args: dict | None = None, mask: str | ndarray | List | Dict | None = 'attr', n_samples: int = 100, fit_kwargs: dict | None = None, verbose: bool = False) DataFrame

Generate parametric null distribution by fitting scipy.stats distribution to observed values.

Parameters:
  • graph (ig.Graph) – Input graph.

  • attributes (List[str]) – Attribute names to generate nulls for.

  • propagation_method (str or PropagationMethod) – Network propagation method to apply.

  • distribution (str or scipy.stats distribution) – Distribution to fit. Can be: - String name (e.g., ‘norm’, ‘gamma’, ‘beta’, ‘expon’, ‘lognorm’) - SciPy stats distribution object (e.g., stats.gamma, stats.beta)

  • additional_propagation_args (dict, optional) – Additional arguments to pass to the network propagation method.

  • mask (str, np.ndarray, List, Dict, or None) – Mask specification. Default is “attr” (use each attribute as its own mask).

  • n_samples (int) – Number of null samples to generate.

  • fit_kwargs (dict, optional) – Additional arguments passed to distribution.fit() method. Common examples: - For gamma: {‘floc’: 0} to fix location at 0 - For beta: {‘floc’: 0, ‘fscale’: 1} to fix support to [0,1]

  • verbose (bool, optional) – Extra reporting. Default is False.

Returns:

Propagated null samples with specified parametric distribution over masked nodes. Shape: (n_samples * n_nodes, n_attributes)

Return type:

pd.DataFrame

Examples

>>> # Gaussian null (default)
>>> result = parametric_null(graph, ['gene_expression'])
>>> # Gamma null for positive-valued data
>>> result = parametric_null(graph, ['gene_expression'],
...                         distribution='gamma',
...                         fit_kwargs={'floc': 0})
>>> # Beta null for data in [0,1]
>>> result = parametric_null(graph, ['probabilities'],
...                         distribution='beta')
>>> # Custom scipy distribution
>>> result = parametric_null(graph, ['counts'],
...                         distribution=stats.poisson)
napistu.network.net_propagation._pooled_vertex_permutation_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, mask: str | ndarray | List | Dict | None = 'attr', n_samples: int = 100, verbose: bool = False) DataFrame

Generate null distribution by sampling from a pooled empirical universe across all attributes and applying the propagation method.

Rather than permuting each attribute independently (as in vertex_permutation_null), this strategy constructs a single empirical universe by merging all masked values (including zeros) across all attributes. Each null sample draws n_masked values from this universe with replacement, assigns them to masked vertices, and propagates the resulting synthetic attribute vector. The propagated result is broadcast across all attribute columns so that every attribute is compared against the same shared null distribution.

This reduces propagation calls from n_attributes * n_samples to n_samples, making it suitable for large attribute sets (e.g. 200+ patient-level summaries).

Assumptions

All attributes must share an identical mask. Attributes are assumed to be exchangeable in both magnitude and sparsity — the pooled universe mixes values across attributes indiscriminately, so the null implicitly treats any (value, zero/nonzero) pattern as equally likely for any attribute. This is a caller contract, validated only for mask equality.

When this assumption is appropriate

Use this strategy when attributes have similar magnitude profiles and similar sparsity (similar fraction of non-zero values per attribute). In that regime, pooled sampling provides variance reduction in the null estimate without introducing systematic bias.

When to prefer an alternative

If attributes differ meaningfully in sparsity, the pooled null’s expected sparsity is the population average and will not match attributes that are much sparser or denser than typical. For personalized PageRank specifically, this causes systematic shifts in log2 enrichment for atypical attributes (sparser attributes shift left, denser shift right) because PPR responds nonlinearly to reset concentration. In that case, prefer attr_pooled_vertex_permutation, which preserves per-attribute sparsity while still pooling propagated outputs across attributes for variance reduction.

param graph:

Input graph.

type graph:

ig.Graph

param attributes:

Attribute names to generate nulls for. All must share the same mask.

type attributes:

List[str]

param propagation_method:

Network propagation method to apply.

type propagation_method:

str or PropagationMethod

param additional_propagation_args:

Additional arguments to pass to the network propagation method.

type additional_propagation_args:

dict, optional

param mask:

Mask specification. Default is “attr” (use each attribute as its own mask). All attributes must resolve to the same mask.

type mask:

str, np.ndarray, List, Dict, or None

param n_samples:

Number of null samples to generate.

type n_samples:

int

param verbose:

Extra reporting. Default is False.

type verbose:

bool, optional

returns:

Propagated null samples with shape (n_samples * n_nodes, n_attributes). Each block of n_nodes rows corresponds to one null sample, with the same propagated vector broadcast across all attribute columns.

rtype:

pd.DataFrame

napistu.network.net_propagation._propagate_and_broadcast(null_graph: Graph, source_attr: str, n_attributes: int, propagation_method: PropagationMethod, additional_propagation_args: dict | None) ndarray

Propagate a single attribute on the null graph and broadcast across columns.

Used by null generators that produce one propagated vector per sample and share it across all attribute columns of the output null tensor.

Parameters:
  • null_graph (ig.Graph) – Graph with the source attribute already set to the null reset values.

  • source_attr (str) – Name of the attribute to propagate.

  • n_attributes (int) – Number of columns to broadcast across in the output.

  • propagation_method (PropagationMethod) – Normalized propagation method.

  • additional_propagation_args (dict, optional) – Forwarded to net_propagate_attributes.

Returns:

Array of shape (n_nodes, n_attributes) where every column is a copy of the propagated vector.

Return type:

np.ndarray

napistu.network.net_propagation._setup_vertex_permutation_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod, mask: str | ndarray | List | Dict | None, verbose: bool, require_shared_mask: bool) tuple

Shared setup for vertex-permutation-style null generators.

Validates the propagation method and attributes, parses masks, copies the graph, and resolves node names. Optionally enforces that all attributes share an identical mask, which is required by null generators that pool propagation outputs across attributes.

Parameters:
  • graph (ig.Graph) – Input graph.

  • attributes (List[str]) – Attribute names to validate and resolve masks for.

  • propagation_method (str or PropagationMethod) – Propagation method, normalized via _ensure_propagation_method.

  • mask (str, np.ndarray, List, Dict, or None) – Mask specification, parsed via _parse_mask_input.

  • verbose (bool) – Forwarded to _parse_mask_input.

  • require_shared_mask (bool) – If True, validate that all attribute masks are identical and return a single shared mask. If False, return the full per-attribute mask dictionary.

Returns:

  • propagation_method (PropagationMethod) – Normalized propagation method.

  • masks (np.ndarray or Dict[str, np.ndarray]) – If require_shared_mask is True, a single boolean array. Otherwise a dict mapping attribute names to their boolean masks.

  • node_names (list) – Vertex names from the graph, falling back to integer indices if the name attribute is absent.

  • null_graph (ig.Graph) – A fresh copy of the input graph for the caller to mutate.

napistu.network.net_propagation._uniform_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, mask: str | ndarray | List | Dict | None = 'attr', verbose: bool = False) DataFrame

Generate uniform null distribution over masked nodes and apply propagation method.

Parameters:
  • graph (ig.Graph) – Input graph.

  • attributes (List[str]) – Attribute names to generate nulls for.

  • propagation_method (str) – Network propagation method to apply.

  • additional_propagation_args (dict, optional) – Additional arguments to pass to the network propagation method.

  • mask (str, np.ndarray, List, Dict, or None) – Mask specification. Default is “attr” (use each attribute as its own mask).

  • verbose (bool, optional) – Extra reporting. Default is False.

Returns:

Propagated null sample with uniform distribution over masked nodes. Shape: (n_nodes, n_attributes)

Return type:

pd.DataFrame

napistu.network.net_propagation._validate_masks_identical(masks: Dict[str, ndarray], attributes: List[str]) None

Validate that all attribute masks are identical.

napistu.network.net_propagation._validate_vertex_attributes(graph: Graph, attributes: List[str], propagation_method: str) None

Validate vertex attributes for propagation method.

napistu.network.net_propagation._vertex_permutation_null(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, mask: str | ndarray | List | Dict | None = 'attr', replace: bool = False, n_samples: int = 100, verbose: bool = False) DataFrame

Generate null distribution by permuting vertex attribute values and apply propagation method.

Parameters:
  • graph (ig.Graph) – Input graph.

  • attributes (List[str]) – Attribute names to permute.

  • propagation_method (str or PropagationMethod) – Network propagation method to apply.

  • additional_propagation_args (dict, optional) – Additional arguments to pass to the network propagation method.

  • mask (str, np.ndarray, List, Dict, or None) – Mask specification. Default is “attr” (use each attribute as its own mask).

  • replace (bool) – Whether to sample with replacement.

  • n_samples (int) – Number of null samples to generate.

  • verbose (bool, optional) – Extra reporting. Default is False.

Returns:

Propagated null samples with permuted attribute values. Shape: (n_samples * n_nodes, n_attributes)

Return type:

pd.DataFrame

napistu.network.net_propagation.melt_propagation_results(propagation_results: DataFrame, index_name: str | None = None, attribute_name: str | None = None) DataFrame

Melt results from network_propagation_with_null into a tall format.

Parameters:
  • propagation_results (pd.DataFrame) – DataFrame with a 2-level MultiIndex on columns (metric, attribute) as returned by network_propagation_with_null.

  • index_name (str, optional) – Name of the index to use for the feature_id column. If None, the existing index name will be used and an error will be raised if propagation_results does not have an index name.

  • attribute_name (str, optional) – Name of the attribute column. If None, the existing attribute column will be used.

Returns:

Tall DataFrame with columns: - feature_id: node identifier (from index) - attribute: attribute name - observed: raw propagated score - log2_enrichment: log2(observed / mean_null) - quantile: proportion of null values <= observed (only present if in input)

Return type:

pd.DataFrame

napistu.network.net_propagation.net_propagate_attributes(graph: Graph, attributes: List[str], propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None) DataFrame

Propagate multiple attributes over a network using a network propagation method.

Parameters:
  • graph (ig.Graph) – The graph to propagate attributes over.

  • attributes (List[str]) – List of attribute names to propagate.

  • propagation_method (str) – The network propagation method to use (e.g., ‘personalized_pagerank’).

  • additional_propagation_args (dict, optional) – Additional arguments to pass to the network propagation method.

Returns:

DataFrame with node names as index and attributes as columns, containing the propagated attribute values.

Return type:

pd.DataFrame

napistu.network.net_propagation.network_propagation_with_null(graph: Graph, attributes: List[str], null_strategy: str = 'vertex_permutation', propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, n_samples: int = 100, quantile_method: str = 'dense', log2_enrichment_epsilon: float = 1e-10, verbose: bool = False, **null_kwargs) DataFrame

Apply network propagation to attributes and compare against null distributions.

This is the main orchestrator function that: 1. Calculates observed propagated scores 2. Generates null distribution using specified strategy 3. Returns a MultiIndex DataFrame with observed scores, quantiles, and log2 enrichment

Null Strategy Selection

Two main approaches are used in network biology:

Vertex permutation (‘vertex_permutation’): Permutes node labels/attributes while preserving network topology. This tests whether individual nodes are significant given the network structure. Standard approach for gene prioritization and network-based gene set enrichment analysis. Reference: Schulte-Sasse et al. (2019) BMC Bioinformatics 20:587

Edge permutation (‘edge_permutation’): Rewires network edges while preserving degree distribution. This tests whether network topology itself is significant. Used when testing subnetwork patterns or connectivity significance. Reference: Leiserson et al. (2015) Nature Genetics (HotNet2 methodology)

For vertex-level significance testing (gene prioritization), node permutation is the appropriate null model as it preserves network structure while randomizing signal assignment.

Other supported null strategies:

Uniform (‘uniform’): A quick, qualitative readout. Generates a uniform null distribution over masked nodes and takes the ratio of observed network propagation score.

Parametric (‘parametric’): Similar to vertex permutation but rather than sampling observed values, samples are drawn from a distribution fit to the observed values. First fits a parametric distribution to the observed scores and then samples n_samples null samples for each vertex to compare observed to null quantiles.

Pooled vertex permutation (‘pooled_vertex_permutation’): Constructs a single empirical universe by merging all masked values across attributes (including zeros) and draws null reset vectors from it. The propagated null is broadcast across all attribute columns, so every attribute is compared against the same shared null. This reduces the propagation cost from n_samples * n_attributes to n_samples, but assumes attributes are exchangeable in both magnitude and sparsity. Only supported when all attributes share an identical mask. When attributes differ meaningfully in sparsity, this strategy can introduce systematic shifts in log2 enrichment because propagation methods like personalized PageRank respond nonlinearly to reset concentration; in that case, prefer ‘attr_pooled_vertex_permutation’.

Attribute-pooled vertex permutation (‘attr_pooled_vertex_permutation’): Each null sample is generated by selecting one attribute, permuting its masked values without replacement, propagating, and broadcasting the result across all attribute columns. Total samples are distributed across attributes as evenly as possible (with the first n_samples % n_attributes attributes receiving one extra sample). This preserves each attribute’s own sparsity and magnitude profile in the null while still pooling propagated outputs across attributes for variance reduction. Total propagation cost is n_samples, matching pooled vertex permutation. Only supported when all attributes share an identical mask. Prefer this over ‘pooled_vertex_permutation’ when attributes share a measurable subgraph but differ in sparsity or magnitude profile.

Creating Masks

Most null strategies benefit from including a mask which indicates which nodes are being tested. For vertex permutation the parametric null only masked nodes will be considered for sampling. Using a mask with uniform null strategy means that numeric reset probabilities will be compared to constant ones by default. Masking is an important consideration for mitigating ascertainment bias. If we are only sampling a subset of vertices like metabolites, we’ll only consider those as sources of signals in the null.

param graph:

Input graph.

type graph:

ig.Graph

param attributes:

Attribute names to propagate and test.

type attributes:

List[str]

param null_strategy:

Null distribution strategy. One of: ‘uniform’, ‘parametric’, ‘vertex_permutation’, ‘pooled_vertex_permutation’, ‘attr_pooled_vertex_permutation’, ‘edge_permutation’.

type null_strategy:

str

param propagation_method:

Network propagation method to apply.

type propagation_method:

str or PropagationMethod

param additional_propagation_args:

Additional arguments to pass to the network propagation method.

type additional_propagation_args:

dict, optional

param n_samples:

Number of null samples to generate (ignored for uniform null).

type n_samples:

int

param quantile_method:

Quantile implementation passed to calculate_quantiles(). One of dense (default, vectorized; matches historical behavior) or per_feature (linear memory when the null table is huge). Ignored when null_strategy is uniform (quantiles are undefined there).

type quantile_method:

str

param log2_enrichment_epsilon:

Small value added to null mean to avoid division by zero (defaults to LOG2_ENRICHMENT_EPSILON).

type log2_enrichment_epsilon:

float

param verbose:

Extra reporting. Default is False.

type verbose:

bool, optional

param **null_kwargs:

Additional arguments to pass to the null generator (e.g., mask, burn_in_ratio, etc.).

returns:

DataFrame with a 2-level MultiIndex on columns (metric, attribute) where metric is one of [‘observed’, ‘quantile’, ‘log2_enrichment’].

  • ‘observed’: raw propagated scores for each attribute

  • ‘quantile’: proportion of null values <= observed values (NaN for uniform null)

  • ‘log2_enrichment’: log2(observed / mean_null). For vertex permutation null this

    is enrichment relative to a topology-matched baseline; for uniform null this is enrichment relative to a flat baseline.

Example access:

result[“observed”][“gene_score”] result[“quantile”][“gene_score”] result[“log2_enrichment”][“gene_score”]

rtype:

pd.DataFrame

Examples

>>> # Node permutation test with custom mask
>>> result = network_propagation_with_null(
...     graph, ['gene_score'],
...     null_strategy='vertex_permutation',
...     n_samples=1000,
...     mask='measured_genes'
... )
>>> # Edge permutation test
>>> result = network_propagation_with_null(
...     graph, ['pathway_score'],
...     null_strategy='edge_permutation',
...     n_samples=100,
...     burn_in_ratio=10,
...     sampling_ratio=0.1
... )
>>> # Attribute-pooled null for many patient-level signals with varying sparsity
>>> result = network_propagation_with_null(
...     graph, patient_attrs,
...     null_strategy='attr_pooled_vertex_permutation',
...     n_samples=1000,
...     mask='measured_features'
... )
>>> # Prefer memory-frugal quantile calculation on very large graphs
>>> result = network_propagation_with_null(
...     graph, ['gene_score'],
...     quantile_method='per_feature',
...     null_strategy='vertex_permutation',
... )
napistu.network.net_propagation.network_propagation_with_null_repeated(graph: Graph, attributes: List[str], null_strategy: str = 'vertex_permutation', propagation_method: str | PropagationMethod = 'personalized_pagerank', additional_propagation_args: dict | None = None, n_samples: int = 100, quantile_method: str = 'dense', verbose: bool = False, n_runs: int = 2, *, log2_enrichment_epsilon: float = 1e-10, **null_kwargs) DataFrame

Call network_propagation_with_null() several times with the same inputs and merge.

Each run draws an independent Monte Carlo null of n_samples (unless the chosen strategy ignores n_samples). This trims peak RAM versus one call with very large n_samples because intermediate null tables are not held simultaneously.

log2 enrichment is pooled from per-run summaries: inferred per-run mean-null values recovered from observed and log2_enrichment are averaged across runs, then log2(observed / (pooled_mean + epsilon)) is recomputed — equivalent to a single pooled null mean across all runs when each n_samples is equal.

Quantiles cannot be reconstructed from emitted scalars alone, so merged quantiles use the sample mean of run-wise quantiles. That is generally close to the fully pooled empirical midrank for large totals but is not identical to one run of n_samples * n_runs draws (ties are negligible in most regimes).

Parameters:
Returns:

Same MultiIndex column layout as network_propagation_with_null().

Return type:

pd.DataFrame