NetworkInference is a package for inferring (undirected) networks, given a set of measurements for each node. The main output is the InferredNetwork
type, which represents a fully connected, weighted network, where an edge's weight indicates the relative confidence of that edge existing in the true network. See also Scope.
Some things to note:
- The package was originally written for inferring biological networks using gene expression data, hence the use of "network" instead of "graph". However, these methods could be applied to other types of data.
- Four network inference algorithms are currently implemented (MI, CLR, PUC and PIDC, explained in [1]), but we plan to include more.
- Networks are assumed to be undirected, since all the algorithms included so far infer undirected networks. Hence:
- in the
Edge
type, the order of the nodes is arbitrary - when a network is written to file, edges are written in both directions, becuase downstream analyses sometimes require this
- the
InferredNetwork
type contains a list of edges, with one edge for each pair of genes, in which the order of the genes is arbitrary
- in the
Pkg.add("NetworkInference")
First include the package at the start of your script or interactive session:
using NetworkInference
Given a data file and an inference algorithm, you can infer a network with a single function call:
infer_network(<path to data file>, PIDCNetworkInference())
This will return an InferredNetwork
type. You can also write the inferred network to file, using the out_file_path
keyword argument. See also Options.
First make an array of Node
s from your data:
nodes = get_nodes(<path to data file>)
Currently the package assumes the file is of the format:
- line 1: headers (these are discarded for now)
- other lines: NodeLabel value1 value2 value3 ...
Then infer a network:
inferred_network = InferredNetwork(PIDCNetworkInference(), nodes)
An InferredNetwork
has an array of nodes and an array of edges between all possible node pairs (sorted in descending order of edge weight, i.e. confidence of the edge existing in the true network).
You can write the network to file:
write_network_file(<path to output file>, inferred_network)
The following keyword arguments can be passed in to infer_network
:
delim (Union{Char,Bool}
) Column delimiter
false
(default) Delimiter is whitespace
discretizer (String
) Method for discretizing
"bayesian_blocks"
(default) Adaptive discretizer with varibale number of bins"uniform_width"
Use this if Bayesian blocks fails, or if constant number of bins is required"uniform_count"
estimator (String
) Estimator for estimating the probability distribution
"maximum_likelihood"
(default) Highly recommended for PUC and PIDC. (See inline comments for more information.)"dirichlet"
"shrinkage"
number_of_bins (Integer
)
10
(default) (This will be ignored when using Bayesian blocks discretization)
base (Number
) Base of the logarithm, i.e. the units for entropy
2
(default)
out_file_path (String
) Path to the output network file
""
(default) No file will be written
Defaults for discretizer and estimator are explained in [1]
This package is not designed for analysing networks/graphs or calculating network/graph metrics. In order to do such analyses, another package should be used (e.g. LightGraphs). Of course, the edge list or the InferredNetwork
will need to be parsed into the appropriate data structure first; the method get_adjacency_matrix
may help with this.
Note that the InferredNetwork
type contains a list of every possible edge, and the confidence of each edge existing in the true network. For analysing the properties of an inferred network, you may first want to define a partially connected, unweighted network by classifying each edge as "in the network" or "not in the network", based on the confidences. The simplest ways to do this are either to decide that the top x percent of edges are "in the network", or to define a threshold confidence, above which edges are "in the network".
You can pass a threshold into get_adjacency_matrix
to get the adjacency matrix of a thresholded network (as well as dictionaries to map the node labels to their numerical IDs within the matrix, and vice versa):
get_adjacency_matrix(inferred_network, 0.1) # Keeps top 10% edges with the largest weights
get_adjacency_matrix(inferred_network, 0.1, absolute = true) # Keeps all edges with weights >= 0.1
It may be possible to speed up an analysis, particularly for large datasets, by using multiple processes.
If multiple processes are available, NetworkInference will distribute the most costly calculations across the processes. (These are the for loops in get_mi_scores
and get_puc_scores
.)
Example
$ ./julia -p 3
julia> using NetworkInference
julia> infer_network(<path to data file>, PIDCNetworkInference())
This opens the Julia REPL with 3 extra processes (so 4 in total). NetworkInference may then be used as normal; it will handle distributing the calculations.
Note that the performance gain from distributing calculations is offset by communicating between the processes, so for small datasets it is more efficient to use one process. For the same reason, using too many processes will degrade performance, so it is a good idea to do some timing tests with different numbers of processes.
Bug reports, pull requests and other contributions are welcome!
[1] Chan, Stumpf and Babtie (2017) Gene Regulatory Network Inference from Single-Cell Data Using Multivariate Information Measures Cell Systems