ergodicDocs
Products: switch from ergodic to another product
Get started

GuidesWork with edge probabilities

Work with edge probabilities

Hold a model's directed-edge probabilities over named variables, read them in the form a decoder needs, and see where they disagree with any single graph. You'll also turn bootstrap frequencies into the same object.

You'll need

  • ergodic, installed with pip install "ergodic".
  • A square matrix of edge probabilities, rows the source and columns the target. AVICI and CDFM on Welt return one; so does any model that scores edges.

Run the program#

The matrix below is made up for four variables. Read values[i, j] as "how likely is an edge from names[i] to names[j]".

edge_probabilities.pyDownload
import numpy as np

from ergodic import EdgeProbabilities, tabular
from ergodic.discovery import bootstrap

# 1. Scores a model returned for four variables: rows the source, columns the target.
names = ("rain", "sprinkler", "wet", "slippery")
values = np.array(
    [
        [0.00, 0.45, 0.91, 0.06],
        [0.40, 0.00, 0.83, 0.05],
        [0.04, 0.07, 0.00, 0.88],
        [0.58, 0.02, 0.10, 0.00],
    ]
)
probs = EdgeProbabilities(names, values, kind="independent", provenance={"model": "example"})
print(probs)

# 2. Every edge above 0.5, as a diagnostic graph.
print(probs.threshold(0.5))

# 3. Three exclusive states per pair: no edge, one way, the other way.
pair = probs.to_pair_states()
print(pair.to_frame().round(3))

# 4. The chance each pair is adjacent, either way.
print(probs.existence().round(3))

# 5. Bootstrap frequencies of a discovery method, as edge probabilities.
rng = np.random.default_rng(0)
x = rng.normal(size=500)
y = 0.8 * x + rng.normal(size=500)
z = 0.8 * y + rng.normal(size=500)
data = tabular({"x": x, "y": y, "z": z})
freq = EdgeProbabilities.from_bootstrap(bootstrap(data, method="ges", n_bootstrap=20, seed=0))
print(freq)
print(freq.to_frame())
Recorded output
EdgeProbabilities(independent, 4 variables, 4 directed cells above 0.5, uncalibrated)
MixedGraph(kind=mixed, nodes=4, edges=[rain <-- slippery, rain --> wet, slippery <-- wet, sprinkler --> wet])
target      rain  sprinkler    wet  slippery
source
rain       0.000      0.329  0.907     0.026
sprinkler  0.268      0.000  0.820     0.049
wet        0.004      0.013  0.000     0.868
slippery   0.565      0.019  0.013     0.000
[[0.    0.598 0.91  0.591]
 [0.598 0.    0.832 0.068]
 [0.91  0.832 0.    0.882]
 [0.591 0.068 0.882 0.   ]]
EdgeProbabilities(frequency, 3 variables, 0 directed cells above 0.5, uncalibrated)
target      x    y      z
source
x       0.000  0.5  0.025
y       0.500  0.0  0.500
z       0.025  0.5  0.000

Read the object#

Field or method What it gives
variables The names, in row and column order.
values The read-only (d, d) matrix, source rows and target columns.
kind "independent", "pair_state" or "frequency".
calibrated False unless you state the numbers are calibrated. ergodic never sets it.
provenance Read-only metadata, such as the model, its version and the job.
to_pair_states() The three-state view a decoder reads.
existence() Skeleton probabilities, symmetric.
threshold(t) Edges with value above t, as a diagnostic mixed graph.
to_frame(), from_frame(frame, kind=...) A dataframe round trip, index source and columns target.
from_bootstrap(result, undirected="split") Directed-edge frequencies from a bootstrap run.

The three kinds read the numbers differently:

Not a graph posterior

Edge probabilities are per-edge numbers. They ignore acyclicity and how edges depend on each other, and a model's scores are usually uncalibrated. Turning them into a DAG is a modelling choice you make with a decoder, not something the model claims.

threshold draws a pair whose two directions both pass as an undirected X --- Y edge, because a graph holds one edge per pair. Read it as "adjacent, direction unresolved".

from_bootstrap drops bidirected and circle-marked glyphs, which say something other than "this direction", and records the dropped share in provenance["dropped_frequency"]. Pass undirected="drop" to drop undirected edges too. It reads results over a table's variables; a window-graph bootstrap from PCMCI is refused.

Next steps#

Documentation

Search ergodic 0.2.1

Search ergodic by task, function or error.