Filters#
Examples in this module use nx.les_miserables_graph() and
nx.davis_southern_women_graph().
Complexity classes are provided in each function docstring.
From a hairball to a backbone, end to end shows how to choose the
threshold and the multiple-testing correction (mtc).
Filtering utilities for backbone extraction.
After a backbone method annotates edges (or nodes) with scores or p-values, these functions extract the final subgraph.
- nx_backbone.multigraph_to_weighted(G, weight='weight', edge_type_attr=None, aggregate='count')[source]#
Convert a MultiGraph/MultiDiGraph into a weighted simple graph.
Parallel edges between the same node pair are collapsed into a single weighted edge.
- Parameters:
- Ggraph
A NetworkX graph. If
Gis aMultiGraphorMultiDiGraph, parallel edges are aggregated. For simple graphs, a copy is returned with missing weights filled as 1.- weightstring, optional (default=”weight”)
Edge attribute name used to store the aggregated weight.
- edge_type_attrstring or None, optional (default=None)
If provided, weight is the count of distinct values of this edge attribute among parallel edges. If missing on all parallel edges, falls back to the number of parallel edges. Only used with
aggregate="count".- aggregate{“count”, “sum”, “max”, “min”, “mean”}, optional (default=”count”)
How parallel edges are combined.
"count"sets the weight to the number of parallel edges (or of distinct edge types). The other options combine the existing weight attribute of the parallel edges, treating a missing weight as 1.
- Returns:
- Hgraph
nx.Graphfor undirected input andnx.DiGraphfor directed input. Each collapsed edge includes:weight: aggregated weight"edge_count": number of parallel edges collapsed"edge_type_count": number of distinct edge types (only whenedge_type_attris provided)
- Raises:
- ValueError
If aggregate is not recognized.
Examples
>>> import networkx as nx >>> from nx_backbone import multigraph_to_weighted >>> B = nx.davis_southern_women_graph() >>> MG = nx.MultiGraph() >>> MG.add_nodes_from(B.nodes(data=True)) >>> u, v = next(iter(B.edges())) >>> _ = MG.add_edge(u, v, edge_type="attendance_a") >>> _ = MG.add_edge(u, v, edge_type="attendance_b") >>> H = multigraph_to_weighted(MG, edge_type_attr="edge_type") >>> H[u][v]["weight"] 2
Sum existing weights instead of counting edges:
>>> M = nx.MultiGraph([(0, 1, {"weight": 10}), (0, 1, {"weight": 20})]) >>> multigraph_to_weighted(M, aggregate="sum")[0][1]["weight"] 30
Computational complexity estimate is
O(m)time andO(n + m)space.
- nx_backbone.threshold_filter(G, score, threshold, mode='below', filter_on='edges', include_all_nodes=True, mtc='none')[source]#
Retain edges or nodes whose score passes a threshold test.
- Parameters:
- Ggraph
A NetworkX graph with a computed score attribute on edges or nodes.
- scorestring
Attribute name to filter on.
- thresholdfloat
Cutoff value.
- mode{“below”, “above”}, optional (default=”below”)
"below"keeps elements withscore < threshold(typical for p-values)."above"keeps elements withscore >= threshold(typical for salience or importance scores).- filter_on{“edges”, “nodes”}, optional (default=”edges”)
Whether to filter edges or nodes.
- include_all_nodesbool, optional (default=True)
Controls isolate retention in the output.
If
filter_on="edges"andTrue, all input nodes are kept. IfFalse, only nodes incident to retained edges are kept.If
filter_on="nodes"andTrue, all retained nodes are kept even if isolated in the induced subgraph. IfFalse, retained nodes with degree 0 are removed.
- mtcstring, optional (default=”none”)
Multiple-testing correction applied to score values before thresholding (see
adjust_pvalues()). Only valid withmode="below"(p-values). Default"none"leaves scores unchanged.
- Returns:
- Hgraph
Filtered subgraph of the same type as G. When filtering edges, all original nodes are preserved by default. When filtering nodes, only retained nodes and their mutual edges are preserved. Graph, node, and edge attributes are copied (as are edge keys of multigraphs). Elements without the score attribute (or with a NaN score) are dropped.
- Raises:
- ValueError
If mode is not
"below"or"above", if filter_on is not"edges"or"nodes", or if mtc is used withmode="above".
See also
fraction_filterKeep a fixed share of elements instead.
boolean_filterKeep edges flagged by a
*_keepattribute.adjust_pvaluesThe multiple-testing corrections behind
mtc.
Examples
>>> import networkx as nx
>>> from nx_backbone import disparity_filter, threshold_filter >>> G = nx.les_miserables_graph() >>> H = disparity_filter(G) >>> filtered = threshold_filter(H, "disparity_pvalue", 0.5) >>> filtered.number_of_edges() <= H.number_of_edges() True
Computational complexity estimate is
O(n + m)time andO(n + m)space.
- nx_backbone.fraction_filter(G, score, fraction, ascending=True, filter_on='edges')[source]#
Retain the top or bottom fraction of edges or nodes by score.
- Parameters:
- Ggraph
A NetworkX graph with a computed score attribute.
- scorestring
Attribute name to sort on.
- fractionfloat
Fraction of elements to retain, in (0, 1].
- ascendingbool, optional (default=True)
If
True, keep the elements with the smallest scores (e.g. lowest p-values). IfFalse, keep the largest.- filter_on{“edges”, “nodes”}, optional (default=”edges”)
Whether to filter edges or nodes.
- Returns:
- Hgraph
Filtered subgraph of the same type as G. Elements without the score attribute are never kept; the fraction is taken of the scored elements. Ties are broken by input order.
- Raises:
- ValueError
If fraction is not in (0, 1] or filter_on is invalid.
See also
threshold_filterKeep elements passing a fixed cutoff instead.
Examples
>>> import networkx as nx
>>> from nx_backbone import disparity_filter, fraction_filter >>> G = nx.les_miserables_graph() >>> H = disparity_filter(G) >>> filtered = fraction_filter(H, "disparity_pvalue", 0.5) >>> filtered.number_of_edges() <= H.number_of_edges() True
Computational complexity estimate is
O(m log m)time andO(n + m)space.
- nx_backbone.boolean_filter(G, score)[source]#
Retain edges whose boolean score attribute is truthy.
- Parameters:
- Ggraph
A NetworkX graph.
- scorestring
Edge attribute name (should contain boolean values).
- Returns:
- Hgraph
A new graph of the same type as G containing only edges for which
data[score]is truthy. All original nodes are preserved, along with graph, node, and edge attributes.
See also
threshold_filterFilter on a numeric score.
Examples
>>> import networkx as nx
>>> from nx_backbone import boolean_filter, global_threshold_filter >>> G = nx.les_miserables_graph() >>> scored = global_threshold_filter(G, threshold=2) >>> H = boolean_filter(scored, "global_threshold_keep") >>> H.number_of_edges() <= scored.number_of_edges() True
Computational complexity estimate is
O(n + m)time andO(n + m)space.
- nx_backbone.consensus_backbone(*backbones)[source]#
Return the intersection of multiple backbone graphs.
An edge is in the consensus backbone if and only if it appears in every input backbone. Only nodes that are endpoints of consensus edges are retained.
- Parameters:
- *backbonesgraph
Two or more backbone graphs (must share the same node identifiers).
- Returns:
- Hgraph
A new graph of the same type as the first backbone, containing only edges present in every input, with the edge, node, and graph attributes of the first backbone. Edges keep the order of the first backbone. Parallel edges of multigraphs are matched by node pair.
- Raises:
- ValueError
If fewer than 2 backbones are provided.
Examples
>>> import networkx as nx
>>> from nx_backbone import ( ... consensus_backbone, ... jaccard_backbone, ... cosine_backbone, ... fraction_filter, ... ) >>> G = nx.les_miserables_graph() >>> B1 = fraction_filter(jaccard_backbone(G), "jaccard", 0.3, ascending=False) >>> B2 = fraction_filter(cosine_backbone(G), "cosine", 0.3, ascending=False) >>> H = consensus_backbone(B1, B2) >>> H.number_of_edges() <= min(B1.number_of_edges(), B2.number_of_edges()) True
Computational complexity estimate is
O(km)time andO(m)space.
- nx_backbone.adjust_pvalues(pvalues, method='bh')[source]#
Apply a multiple-testing correction to a collection of p-values.
Reproduces R’s
p.adjustfor the methods used by Neal’s Backbone 3.0mtcoption, so statistical backbone p-values can be corrected for the number of edges tested before thresholding.- Parameters:
- pvaluesiterable of float
The raw p-values.
- methodstring, optional (default=”bh”)
One of
"none","bonferroni","holm"(step-down),"hochberg"(step-up),"bh"/"fdr"(Benjamini-Hochberg), or"by"(Benjamini-Yekutieli).
- Returns:
- adjustedlist of float
Adjusted p-values in the same order as the input, each in
[0, 1]. Missing values (NaN) stay NaN and, as in R’sp.adjust, do not count toward the number of tests.
- Raises:
- ValueError
If method is not recognized.
References
[1]Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65-70.
[2]Hochberg, Y. (1988). A sharper Bonferroni procedure for multiple tests of significance. Biometrika, 75(4), 800-802.
[3]Benjamini, Y., & Hochberg, Y. (1995). Controlling the false discovery rate. J. Royal Statistical Society B, 57(1), 289-300.
[4]Benjamini, Y., & Yekutieli, D. (2001). The control of the false discovery rate in multiple testing under dependency. Annals of Statistics, 29(4), 1165-1188.
Examples
>>> from nx_backbone import adjust_pvalues >>> adjust_pvalues([0.01, 0.02, 0.5], method="bonferroni") [0.03, 0.06, 1.0]
- nx_backbone.transform_weights(G, transformer, weight='weight', out=None)[source]#
Return a copy of G with transformed edge weights.
Applies transformer to the edge weights before scoring, for example a log, power, or Box-Cox transform. Transforming weights changes the hypothesis a statistical method tests: the disparity filter applied to
log1p(w)tests whether the log-weights’ shares are uniform, not whether the weights’ shares are. Some methods give the same result for every increasing transform, some only for rescaling, and some for neither; see Weights, Units, and Transforms.- Parameters:
- Gnetworkx.Graph or networkx.DiGraph
A weighted graph. Every edge needs a finite, real weight.
- transformercallable or object with
fit_transformortransform Either an object with a scikit-learn style
fit_transformmethod (or onlytransform, for one that is already fitted), which is called once with the weights as a column of shape(m, 1)inG.edgesorder and must returnmvalues; or a plain callable such asmath.log1p()ornumpy.sqrt, which is called on each weight in turn. scikit-learn is not needed: any object with these methods works, and a plain callable needs neither NumPy nor scikit-learn.- weightstring, optional (default=”weight”)
Edge attribute holding the weights to transform.
- outstring or None, optional (default=None)
Edge attribute that receives the transformed weights.
Noneoverwrites weight; another name keeps the original weights.
- Returns:
- Hgraph
A copy of G (same type) with the transformed weights in out. The neighbor order of every node is the same as in G, so methods that break ties by neighbor order behave as on G. The transform is appended to the list
H.graph["weight_transforms"]as a dict with keys"transform"(a description of transformer),"weight"and"out";describe_backbone()reports it.
- Raises:
- NetworkXError
If an edge has a missing, non-numeric, or non-finite weight.
- NetworkXNotImplemented
If G is a multigraph. Collapse parallel edges first with
multigraph_to_weighted().- TypeError
If transformer is neither callable nor has
fit_transformortransform.- ValueError
If the transformer returns the wrong number of values, a non-finite value, or the same value for every edge although the weights differ (for example scikit-learn’s
Normalizer, which scales each row, maps a column of weights to all ones).
- Warns:
- UserWarning
If the transform does not preserve the order of the weights (a larger weight gets a smaller value, or equal weights get different values), or if it maps different weights to the same value. Methods that only use the ranks of the weights change in either case.
See also
marginal_likelihood_filterCount models take
unit=for a change of unit instead of a transform.
Notes
The transformed weights are not checked for positivity; the statistical scorers reject non-positive weights themselves. Transforms that center or standardize (
StandardScaler,PowerTransformerwith its defaultstandardize=True,QuantileTransformerwith a normal output) produce negative weights.Count-based null models (
marginal_likelihood_filter(),ecm_filter(),noise_corrected_filter(),polya_filter()) treat weights as numbers of events, which a continuous transform does not preserve, and binning (for exampleKBinsDiscretizer) gives ordinal labels, not counts. To change the size of one count use theirunit=argument instead.Examples
>>> import math >>> import networkx as nx >>> from nx_backbone import disparity_filter, transform_weights >>> G = nx.les_miserables_graph() >>> H = transform_weights(G, math.log1p) >>> round(H["Valjean"]["Javert"]["weight"], 4) 2.8904 >>> H.graph["weight_transforms"] [{'transform': 'math.log1p', 'weight': 'weight', 'out': 'weight'}] >>> scored = disparity_filter(H)
Any object with a scikit-learn style
fit_transformworks, such as a Box-Cox power transform without standardization:>>> from sklearn.preprocessing import PowerTransformer >>> pt = PowerTransformer(method="box-cox", standardize=False) >>> H = transform_weights(G, pt, out="boxcox")
Computational complexity estimate is
O(n + m log m)time andO(n + m)space.