| Title: | Inference of Pair-Copula Bayesian Networks |
|---|---|
| Description: | Creates, fits and samples Pair-Copula Bayesian Networks (PCBN) under some restrictions on the underlying Directed Acyclic Graph (DAG), that is, no active cycles nor interfering v-structures, following Derumigny, Horsman and Kurowicka (2025) <doi:10.48550/arXiv.2510.03518>. |
| Authors: | Alexis Derumigny [aut, cre] (ORCID: <https://orcid.org/0000-0002-6163-8097>), Niels Horsman [aut], Dorota Kurowicka [aut], Johan Larsson [ctb] (ORCID: <https://orcid.org/0000-0002-4029-5945>) |
| Maintainer: | Alexis Derumigny <[email protected]> |
| License: | GPL (>= 2) |
| Version: | 0.1.1 |
| Built: | 2026-10-15 17:32:58 UTC |
| Source: | https://github.com/alexisderumigny/pcbn |
Checks if a graph contains active cycles
active_cycles(DAG, early.stopping = FALSE, graph_backend = NULL) has_active_cycles(DAG, graph_backend = NULL) plot_active_cycles(DAG, active_cycles_list = NULL, graph_backend = NULL)active_cycles(DAG, early.stopping = FALSE, graph_backend = NULL) has_active_cycles(DAG, graph_backend = NULL) plot_active_cycles(DAG, active_cycles_list = NULL, graph_backend = NULL)
DAG |
Directed Acyclic |
early.stopping |
if |
graph_backend |
Graph backend, either |
active_cycles_list |
a list of active cycles as given by
|
active_cycles returns a list containing the active cycles.
Each active cycle is a character vector of the name of the nodes involved in
the active cycle. The first element of this vector is the converging node of
the active cycle.
has_active_cycles returns TRUE if at least 1 active cycle is
found. Otherwise, it returns FALSE.
plot_active_cycles is called for its side-effects only. It plots the
active cycles if any, and else prints a message.
the helper functions path_hasConvergingConnections,
path_hasChords that are used to find the active cycles.
is_restrictedDAG to check also whether the DAG contains
interfering v-structures.
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') active_cycles(DAG) # no active cycle DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') active_cycles(DAG) # 1 active cycle DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') active_cycles(DAG) # 2 active cycles active_cycles(DAG, early.stopping = TRUE) # The first active cycle # Plotting the active cycles plot_active_cycles(DAG) # which is the same as plot_active_cycles(DAG, active_cycles_list = active_cycles(DAG)) # We now fix the active cycles by adding the some arcs. fixedDAG = fix_active_cycles(DAG) # We can see that no active cycles is plotted anymore plot_active_cycles(fixedDAG) has_active_cycles(fixedDAG) # This is because two edges have been added, as can be seen on: plot(fixedDAG)DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') active_cycles(DAG) # no active cycle DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') active_cycles(DAG) # 1 active cycle DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') active_cycles(DAG) # 2 active cycles active_cycles(DAG, early.stopping = TRUE) # The first active cycle # Plotting the active cycles plot_active_cycles(DAG) # which is the same as plot_active_cycles(DAG, active_cycles_list = active_cycles(DAG)) # We now fix the active cycles by adding the some arcs. fixedDAG = fix_active_cycles(DAG) # We can see that no active cycles is plotted anymore plot_active_cycles(fixedDAG) has_active_cycles(fixedDAG) # This is because two edges have been added, as can be seen on: plot(fixedDAG)
Checks if the B-sets for a particular node form an increasing sequence.
B_sets_are_increasing(B_sets)B_sets_are_increasing(B_sets)
B_sets |
a boolean matrix with |
TRUE if the B-sets form an ordered sequence,
otherwise returns FALSE.
B_sets = matrix(c(FALSE, FALSE, FALSE, FALSE, TRUE , FALSE, FALSE, FALSE, TRUE , TRUE , FALSE, FALSE, TRUE , TRUE , TRUE , TRUE), nrow = 4, byrow = TRUE) B_sets_are_increasing(B_sets) B_sets = matrix(c(FALSE, FALSE, FALSE, FALSE, TRUE , FALSE, TRUE , FALSE, TRUE , TRUE , FALSE, FALSE, TRUE , TRUE , TRUE , TRUE), nrow = 4, byrow = TRUE) B_sets_are_increasing(B_sets)B_sets = matrix(c(FALSE, FALSE, FALSE, FALSE, TRUE , FALSE, FALSE, FALSE, TRUE , TRUE , FALSE, FALSE, TRUE , TRUE , TRUE , TRUE), nrow = 4, byrow = TRUE) B_sets_are_increasing(B_sets) B_sets = matrix(c(FALSE, FALSE, FALSE, FALSE, TRUE , FALSE, TRUE , FALSE, TRUE , TRUE , FALSE, FALSE, TRUE , TRUE , TRUE , TRUE), nrow = 4, byrow = TRUE) B_sets_are_increasing(B_sets)
Find the decomposition of B-sets
B_sets_cut_increments(B_sets)B_sets_cut_increments(B_sets)
B_sets |
matrix of B-sets, assumed to be increasing.
This means |
a list of vectors of characters. Each element of the list
corresponds to one .
B_sets = matrix(c(FALSE, FALSE, FALSE, FALSE, TRUE , FALSE, FALSE, FALSE, TRUE , TRUE , FALSE, FALSE, TRUE , TRUE , TRUE , TRUE), nrow = 4, byrow = TRUE) colnames(B_sets) <- c("U1", "U2", "U3", "U4") B_sets_cut_increments(B_sets)B_sets = matrix(c(FALSE, FALSE, FALSE, FALSE, TRUE , FALSE, FALSE, FALSE, TRUE , TRUE , FALSE, FALSE, TRUE , TRUE , TRUE , TRUE), nrow = 4, byrow = TRUE) colnames(B_sets) <- c("U1", "U2", "U3", "U4") B_sets_cut_increments(B_sets)
Compress a given collection of B-sets
B_sets_make_unique(B_sets)B_sets_make_unique(B_sets)
B_sets |
a boolean matrix with |
a 'data.frame' made of the unique rows of 'B_sets'.
An additional column 'nodes' is added at the start. It contains all the children
of v corresponding to this B-set.
DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U4', 'U5') B_sets = find_B_sets_v(DAG, v = 'U4') B_sets_make_unique(B_sets)DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U4', 'U5') B_sets = find_B_sets_v(DAG, v = 'U4') B_sets_make_unique(B_sets)
Complete an order and check whether these are valid orders on parents sets
complete_and_check_orders(DAG, order_hash, graph_backend = NULL)complete_and_check_orders(DAG, order_hash, graph_backend = NULL)
DAG |
the DAG |
order_hash |
the hashmaps of orders |
graph_backend |
Graph backend, either |
NULL. This function has only side-effects,
and modifies order_hash. It stops if the orders are not valid orders
on the parents sets.
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U3', 'U4') order_hash = r2r::hashmap() try({complete_and_check_orders(DAG, order_hash)}) # Error because the order of the parents on "U3" should be specified. order_hash[['U3']] = c("U1", "U2") complete_and_check_orders(DAG, order_hash) r2r::keys(order_hash) # We obtain "U3" and "U4" because they both have parentsDAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U3', 'U4') order_hash = r2r::hashmap() try({complete_and_check_orders(DAG, order_hash)}) # Error because the order of the parents on "U3" should be specified. order_hash[['U3']] = c("U1", "U2") complete_and_check_orders(DAG, order_hash) r2r::keys(order_hash) # We obtain "U3" and "U4" because they both have parents
Computes a conditional margin during sampling
compute_sample_margin( object, data, v, cond_set, check_PCBN = TRUE, verbose = 1 )compute_sample_margin( object, data, v, cond_set, check_PCBN = TRUE, verbose = 1 )
object |
PCBN object to sample from. This does not work if the PCBN does not abide by the B-sets. And in general, it does not work if the PCBN is outside of the class of restricted PCBNs. |
data |
data frame of observations of size |
v |
name of the node |
cond_set |
conditioning set. This is a vector containing the names of all the nodes in the conditioning set. |
check_PCBN |
check whether the given PCBN satisfies the restrictions.
If this is set to |
verbose |
if |
a vector of size of realizations
for .
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) # Initialize data frame N = 100 nodes = bnlearn::nodes(my_PCBN$DAG) data = data.frame(matrix(ncol = length(nodes), nrow = N)) colnames(data) <- nodes data[, "U1"] = stats::runif(N) data[, "U2"] = stats::runif(N) u_1_given2 = compute_sample_margin(object = my_PCBN, data = data, v = "U1", cond_set = c("U2")) identical(data[, "U1"], u_1_given2)DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) # Initialize data frame N = 100 nodes = bnlearn::nodes(my_PCBN$DAG) data = data.frame(matrix(ncol = length(nodes), nrow = N)) colnames(data) <- nodes data[, "U1"] = stats::runif(N) data[, "U2"] = stats::runif(N) u_1_given2 = compute_sample_margin(object = my_PCBN, data = data, v = "U1", cond_set = c("U2")) identical(data[, "U1"], u_1_given2)
This function creates a directed graph with a total of 'N_nodes' nodes and no arcs. The nodes are named 'U1', 'U2', etc.
create_empty_DAG(N_nodes, graph_backend = "bnlearn")create_empty_DAG(N_nodes, graph_backend = "bnlearn")
N_nodes |
A positive integer equal to the number of nodes |
graph_backend |
Graph backend, either |
A native graph for the selected backend, with 'N_nodes' nodes and no arcs.
bnlearn::empty.graph() and caugi::caugi().
create_empty_DAG(6) create_empty_DAG(10) if (requireNamespace("caugi", quietly = TRUE)) { DAG = create_empty_DAG(3, graph_backend = "caugi") DAG = set_arc(DAG, "U1", "U3") dsep_set(DAG, "U1", "U2") }create_empty_DAG(6) create_empty_DAG(10) if (requireNamespace("caugi", quietly = TRUE)) { DAG = create_empty_DAG(3, graph_backend = "caugi") DAG = set_arc(DAG, "U1", "U3") dsep_set(DAG, "U1", "U2") }
Turns a general graph into a restricted graph.
DAG_to_restrictedDAG(DAG, graph_backend = NULL) fix_active_cycles(DAG, active_cycles_list = NULL, graph_backend = NULL) fix_interfering_vstructs(DAG, all_B_sets = NULL, graph_backend = NULL)DAG_to_restrictedDAG(DAG, graph_backend = NULL) fix_active_cycles(DAG, active_cycles_list = NULL, graph_backend = NULL) fix_interfering_vstructs(DAG, all_B_sets = NULL, graph_backend = NULL)
DAG |
A bnlearn or caugi directed acyclic graph. |
graph_backend |
Graph backend, either |
active_cycles_list, all_B_sets
|
respective outputs of the functions
|
Restricted DAG.
is_restrictedDAG to check whether a given DAG is
restricted.
# DAG with an active cycle at node 5 DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') # Fixed graph has extra arcs 1 -> 5, 2 -> 5 fixed_DAG = DAG_to_restrictedDAG(DAG) # DAG with an interfering v-structures node 3 DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U3', 'U5') # Fixed graph has extra arc 1 -> 5 fixed_DAG = DAG_to_restrictedDAG(DAG)# DAG with an active cycle at node 5 DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') # Fixed graph has extra arcs 1 -> 5, 2 -> 5 fixed_DAG = DAG_to_restrictedDAG(DAG) # DAG with an interfering v-structures node 3 DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U3', 'U5') # Fixed graph has extra arc 1 -> 5 fixed_DAG = DAG_to_restrictedDAG(DAG)
Fits the copula joining w and v given cond_set abiding by the conditional independencies of the graph
default_envir() BiCopCondFit( data, DAG, v, w, cond_set, familyset, order_hash, e, verbose = 1, method, graph_backend = NULL ) ComputeCondMargin( data, DAG, v, cond_set, familyset, order_hash, e, verbose = 1, method, graph_backend = NULL )default_envir() BiCopCondFit( data, DAG, v, w, cond_set, familyset, order_hash, e, verbose = 1, method, graph_backend = NULL ) ComputeCondMargin( data, DAG, v, cond_set, familyset, order_hash, e, verbose = 1, method, graph_backend = NULL )
data |
data frame |
DAG |
Directed Acylic Graph |
v, w
|
nodes of the graph |
cond_set |
vector of nodes of DAG. They should all be parents of v. They should be ordered from the smallest to the biggest. |
familyset |
vector of copula families |
order_hash |
hashmap of parental orders |
e |
environment containing all the hashmaps |
verbose |
if |
method |
indicates the estimation method ( |
graph_backend |
Graph backend, either |
default_envir returns an environment to be passed
to BiCopCondFit or to ComputeCondMargin. BiCopCondFit
returns the fitted copula object of v, w given cond_set.
ComputeCondMargin returns the fitted conditional margins of v
given cond_set.
Both functions store all intermediary results in e to save computation
time.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 5) e = default_envir() ls(e) C_13 = BiCopCondFit(data = mydata, DAG = DAG, v = "U1", w = "U3", cond_set = c(), familyset = 1, order_hash = order_hash, e = e, method = "mle") C_23_1 = BiCopCondFit(data = mydata, DAG = DAG, v = "U2", w = "U3", cond_set = "U1", familyset = 1, order_hash = order_hash, e = e, method = "itau") U_2_13 = ComputeCondMargin(data = mydata, DAG = DAG, v = "U2", cond_set = c("U1", "U3"), familyset = 1, order_hash = order_hash, e = e, method = "mle")DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 5) e = default_envir() ls(e) C_13 = BiCopCondFit(data = mydata, DAG = DAG, v = "U1", w = "U3", cond_set = c(), familyset = 1, order_hash = order_hash, e = e, method = "mle") C_23_1 = BiCopCondFit(data = mydata, DAG = DAG, v = "U2", w = "U3", cond_set = "U1", familyset = 1, order_hash = order_hash, e = e, method = "itau") U_2_13 = ComputeCondMargin(data = mydata, DAG = DAG, v = "U2", cond_set = c("U1", "U3"), familyset = 1, order_hash = order_hash, e = e, method = "mle")
D-separation of two nodes given a set in a DAG
dsep_set(DAG, X, Y, Z = NULL, graph_backend = NULL)dsep_set(DAG, X, Y, Z = NULL, graph_backend = NULL)
DAG |
Directed Acyclic Graph |
X |
node |
Y |
node |
Z |
set |
graph_backend |
Graph backend, either |
TRUE if the sets are d-separated and FALSE if not
DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') dsep_set(DAG, 'U1', 'U5')DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') dsep_set(DAG, 'U1', 'U5')
Fills in all possible orders for the next node for each possible order
extend_orders(DAG, all_orders, node, graph_backend = NULL)extend_orders(DAG, all_orders, node, graph_backend = NULL)
DAG |
Directed Acyclic Graph |
all_orders |
list of orders |
node |
node |
graph_backend |
Graph backend, either |
list of order hashmaps
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') # Start with empty order order_hash = r2r::hashmap() all_orders_3 = find_all_orders_v(DAG, v = "U3", order_hash = order_hash) print(all_orders_3) # Two possible choices for node 3, let's use the first order_hash[['U3']] = all_orders_3[[1]] extended_orders = extend_orders(DAG, list(order_hash), node = 'U4') length(extended_orders) # We can extend this order in 4 ways: for (i in 1:length(extended_orders)){ print(extended_orders[[i]][['U4']]) } # We never pick U2 and U3 first, because their copula is not specifiedDAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') # Start with empty order order_hash = r2r::hashmap() all_orders_3 = find_all_orders_v(DAG, v = "U3", order_hash = order_hash) print(all_orders_3) # Two possible choices for node 3, let's use the first order_hash[['U3']] = all_orders_3[[1]] extended_orders = extend_orders(DAG, list(order_hash), node = 'U4') length(extended_orders) # We can extend this order in 4 ways: for (i in 1:length(extended_orders)){ print(extended_orders[[i]][['U4']]) } # We never pick U2 and U3 first, because their copula is not specified
Finds all possible copula assignments given a DAG
find_all_orders(DAG, graph_backend = NULL)find_all_orders(DAG, graph_backend = NULL)
DAG |
Directed Acyclic Graph |
graph_backend |
Graph backend, either |
a list of hashmaps containing the possible orders
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') all_orders = find_all_orders(DAG) length(all_orders) # 8 orders for (i in 1:length(all_orders)){ cat("Order ", i, ": \n") cat("U3:", all_orders[[i]][['U3']]) cat(" ; U4:", all_orders[[i]][['U4']], "\n") }DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') all_orders = find_all_orders(DAG) length(all_orders) # 8 orders for (i in 1:length(all_orders)){ cat("Order ", i, ": \n") cat("U3:", all_orders[[i]][['U3']]) cat(" ; U4:", all_orders[[i]][['U4']], "\n") }
Finds all possible orders of node v given previous copula assignments
find_all_orders_v(DAG, v, order_hash, graph_backend = NULL)find_all_orders_v(DAG, v, order_hash, graph_backend = NULL)
DAG |
Directed Acyclic Graph |
v |
node |
order_hash |
hashmap of orders |
graph_backend |
Graph backend, either |
list of vectors containing all possible orders for v
DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U1', 'U5') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') # Start with empty order order_hash = r2r::hashmap() all_orders_3 = find_all_orders_v(DAG, v = "U3", order_hash = order_hash) print(all_orders_3) # Two possible choices for node 3, let's use the first order_hash[['U3']] = all_orders_3[[1]] all_orders_4 = find_all_orders_v(DAG, v = "U4", order_hash = order_hash) print(all_orders_4) # Four possible choices for node 4, let's use the third order_hash[['U4']] = all_orders_4[[3]] all_orders_5 = find_all_orders_v(DAG, v = "U5", order_hash = order_hash) print(all_orders_5) # Eight possible orders for node 5; let's use the fourth order_hash[['U5']] = all_orders_5[[4]]DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U1', 'U5') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') # Start with empty order order_hash = r2r::hashmap() all_orders_3 = find_all_orders_v(DAG, v = "U3", order_hash = order_hash) print(all_orders_3) # Two possible choices for node 3, let's use the first order_hash[['U3']] = all_orders_3[[1]] all_orders_4 = find_all_orders_v(DAG, v = "U4", order_hash = order_hash) print(all_orders_4) # Four possible choices for node 4, let's use the third order_hash[['U4']] = all_orders_4[[3]] all_orders_5 = find_all_orders_v(DAG, v = "U5", order_hash = order_hash) print(all_orders_5) # Eight possible orders for node 5; let's use the fourth order_hash[['U5']] = all_orders_5[[4]]
Find all the B-sets of a given DAG
Find the B sets for a given node v
find_B_sets(DAG, graph_backend = NULL) find_B_sets_v(DAG, v, graph_backend = NULL)find_B_sets(DAG, graph_backend = NULL) find_B_sets_v(DAG, v, graph_backend = NULL)
DAG |
A bnlearn or caugi DAG. |
graph_backend |
Graph backend, either |
v |
node at which we want to find the B-sets |
find_B_sets returns a list with three elements
B_sets list of B-sets matrices for each node;
has_interfering_vstrucs a boolean specifying if the graph
contains interfering v-structures or not;
nodes_with_inter_vs a list containing nodes forming the
interfering v-structures.
find_B_sets_v returns a boolean matrix with (2 + length(children))
columns and length(parents) rows.
This is also true if length(parents) == 0 and length(parents) == 1.
DAG = create_empty_DAG(6) DAG = set_arc(DAG, 'U1', 'U5') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') DAG = set_arc(DAG, 'U1', 'U6') DAG = set_arc(DAG, 'U2', 'U6') DAG = set_arc(DAG, 'U5', 'U6') find_B_sets_v(DAG, v = 'U5') B_sets = find_B_sets(DAG) B_sets$B_setsDAG = create_empty_DAG(6) DAG = set_arc(DAG, 'U1', 'U5') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') DAG = set_arc(DAG, 'U1', 'U6') DAG = set_arc(DAG, 'U2', 'U6') DAG = set_arc(DAG, 'U5', 'U6') find_B_sets_v(DAG, v = 'U5') B_sets = find_B_sets(DAG) B_sets$B_sets
Find among parents of a node, the one that has a conditional copula specified
find_cond_copula_specified(DAG, order_hash, v, cond, graph_backend = NULL)find_cond_copula_specified(DAG, order_hash, v, cond, graph_backend = NULL)
DAG |
Directed Acyclic Graph object corresponding to the model |
order_hash |
hashmap of orders of the parental sets |
v |
node in DAG |
cond |
vector of nodes in DAG. This must not be empty.
It is assumed that conditionally independent nodes have already been
removed by the function |
graph_backend |
Graph backend, either |
a list with
a node w such that the conditional copula
has been specified in the model.
If no such node can be found, an error message is raised.
the set cond[-v]
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") find_cond_copula_specified(DAG = DAG, order_hash = order_hash, v = "U3", cond = c("U1")) # returns "U1" because the copula c_{1,3} is known find_cond_copula_specified(DAG = DAG, order_hash = order_hash, v = "U3", cond = c("U1", "U2")) # returns "U2" because the copula c_{2,3|1} is knownDAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") find_cond_copula_specified(DAG = DAG, order_hash = order_hash, v = "U3", cond = c("U1")) # returns "U1" because the copula c_{1,3} is known find_cond_copula_specified(DAG = DAG, order_hash = order_hash, v = "U3", cond = c("U1", "U2")) # returns "U2" because the copula c_{2,3|1} is known
Find all interfering v-structures for a given collection of B-sets
find_interfering_v_from_B_sets(B_sets)find_interfering_v_from_B_sets(B_sets)
B_sets |
a boolean matrix with |
NULL if there is no interfering v-structures.
Else, it returns a data.frame with 4 columns
A: a list of children of v
B: a list of children of v, disjoint from A
parents.A.but.not.parents.B: a list of common parents of
nodes of A, that are not parents of nodes of B
parents.B.but.not.parents.A: a list of common parents of
nodes of B, that are not parents of nodes of A
Each line correspond to 1 interfering v-structure.
DAG = create_empty_DAG(7) DAG = set_arc(DAG, 'U1', 'U5') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') DAG = set_arc(DAG, 'U1', 'U6') DAG = set_arc(DAG, 'U5', 'U6') DAG = set_arc(DAG, 'U2', 'U7') DAG = set_arc(DAG, 'U5', 'U7') B_sets = find_B_sets_v(DAG, v = 'U5') find_interfering_v_from_B_sets(B_sets) # Adding the missing arc DAG = set_arc(DAG, 'U1', 'U7') # Now no interfering v-structure B_sets = find_B_sets_v(DAG, v = 'U5') find_interfering_v_from_B_sets(B_sets)DAG = create_empty_DAG(7) DAG = set_arc(DAG, 'U1', 'U5') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') DAG = set_arc(DAG, 'U4', 'U5') DAG = set_arc(DAG, 'U1', 'U6') DAG = set_arc(DAG, 'U5', 'U6') DAG = set_arc(DAG, 'U2', 'U7') DAG = set_arc(DAG, 'U5', 'U7') B_sets = find_B_sets_v(DAG, v = 'U5') find_interfering_v_from_B_sets(B_sets) # Adding the missing arc DAG = set_arc(DAG, 'U1', 'U7') # Now no interfering v-structure B_sets = find_B_sets_v(DAG, v = 'U5') find_interfering_v_from_B_sets(B_sets)
Fit the copulas of a PCBN given data
Fit all possible orders given a DAG
fit_copulas( data, DAG, order_hash, familyset = c(1, 3, 4, 5, 6), familyMatrix = NULL, e, verbose = 1, method = "mle", graph_backend = NULL ) fit_all_orders( data, DAG, familyset = c(1, 3, 4, 5, 6), e, score_metric = "BIC", verbose = 1, graph_backend = NULL )fit_copulas( data, DAG, order_hash, familyset = c(1, 3, 4, 5, 6), familyMatrix = NULL, e, verbose = 1, method = "mle", graph_backend = NULL ) fit_all_orders( data, DAG, familyset = c(1, 3, 4, 5, 6), e, score_metric = "BIC", verbose = 1, graph_backend = NULL )
data |
data frame |
DAG |
Directed Acyclic Graph |
order_hash |
hashmap of parental orders |
familyset |
vector of copula families |
familyMatrix |
matrix of families, with named rows and columns.
This should be used if the copula families are known/fixed.
This overrides |
e |
environment containing all the hashmaps |
verbose |
if |
method |
indicates the estimation method ( |
graph_backend |
Graph backend, either |
score_metric |
name of the metric used to choose the best order.
Possible choices are |
fit_copulas returns the fitted PCBN, with an additional
element called metrics which is a named vector of length 3 with names
c("logLik", "BIC", "AIC"), where
and ,
for a sample size n and nparameters is the number of parameters.
fit_all_orders returns a list containing:
best_fit the PCBN which is the best according to the metric
score_metric.
fitted_list the list of all fitted PCBNs.
metrics the matrix of metrics (logLik, BIC, AIC).
Each row i of this matrix corresponds to a PCBN with a different set
of parents' orderings, and corresponds to element i of
fitted_list.
BiCopCondFit which this function wraps.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 5) e = default_envir() result = fit_copulas(data = mydata, DAG = DAG, order_hash = order_hash, familyset = 1, e = e) result_all_orders = fit_all_orders(data = mydata, DAG = DAG, familyset = 1, e = e) # The two fitted PCBNs are: print(result_all_orders$fitted_list[[1]]) print(result_all_orders$fitted_list[[2]]) # and the metrics matrix is: print(result_all_orders$metrics) # The PCBN corresponding to the true order U1 < U2 is usually better # than the second one. This Will be more clear with a bigger sample size.DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 5) e = default_envir() result = fit_copulas(data = mydata, DAG = DAG, order_hash = order_hash, familyset = 1, e = e) result_all_orders = fit_all_orders(data = mydata, DAG = DAG, familyset = 1, e = e) # The two fitted PCBNs are: print(result_all_orders$fitted_list[[1]]) print(result_all_orders$fitted_list[[2]]) # and the metrics matrix is: print(result_all_orders$metrics) # The PCBN corresponding to the true order U1 < U2 is usually better # than the second one. This Will be more clear with a bigger sample size.
Checks if graph has interfering v-structures
has_interfering_vstrucs(DAG, verbose = 0, graph_backend = NULL)has_interfering_vstrucs(DAG, verbose = 0, graph_backend = NULL)
DAG |
Directed Acyclic Graph |
verbose |
if |
graph_backend |
Graph backend, either |
TRUE if graph contains (at least) an interfering v-structure,
and FALSE if it does not contain any interfering v-structure.
DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') # There is one interfering v-structure has_interfering_vstrucs(DAG, verbose = 1) DAG = set_arc(DAG, 'U1', 'U5') # Now no interfering v-structure has_interfering_vstrucs(DAG)DAG = create_empty_DAG(5) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U2', 'U5') DAG = set_arc(DAG, 'U3', 'U5') # There is one interfering v-structure has_interfering_vstrucs(DAG, verbose = 1) DAG = set_arc(DAG, 'U1', 'U5') # Now no interfering v-structure has_interfering_vstrucs(DAG)
Checks if a given (conditional) copula has already been specified
is_cond_copula_specified(DAG, order_hash, w, v, cond, graph_backend = NULL)is_cond_copula_specified(DAG, order_hash, w, v, cond, graph_backend = NULL)
DAG |
Directed Acyclic Graph object corresponding to the model |
order_hash |
hashmap of orders of the parental sets |
w |
node in DAG |
v |
node in DAG |
cond |
vector of nodes in DAG. It is assumed to have been already sorted. |
graph_backend |
Graph backend, either |
TRUE if the conditional copula
has been specified in the model
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") is_cond_copula_specified(DAG = DAG, order_hash = order_hash, w = "U1", v = "U3", cond = c()) # returns TRUE because the copula c_{1,3} is known is_cond_copula_specified(DAG = DAG, order_hash = order_hash, w = "U2", v = "U3", cond = c()) # returns FALSE because the copula c_{2,3} is not known is_cond_copula_specified(DAG = DAG, order_hash = order_hash, w = "U2", v = "U3", cond = c("U1")) # returns TRUE because the copula c_{2,3 | 1} is knownDAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") is_cond_copula_specified(DAG = DAG, order_hash = order_hash, w = "U1", v = "U3", cond = c()) # returns TRUE because the copula c_{1,3} is known is_cond_copula_specified(DAG = DAG, order_hash = order_hash, w = "U2", v = "U3", cond = c()) # returns FALSE because the copula c_{2,3} is not known is_cond_copula_specified(DAG = DAG, order_hash = order_hash, w = "U2", v = "U3", cond = c("U1")) # returns TRUE because the copula c_{2,3 | 1} is known
Check whether a certain order abides by the B-sets
is_order_abiding_Bsets(DAG, order_hash, graph_backend = NULL) is_order_abiding_Bsets_v(B_sets, orderParents)is_order_abiding_Bsets(DAG, order_hash, graph_backend = NULL) is_order_abiding_Bsets_v(B_sets, orderParents)
DAG |
the considered DAG |
order_hash |
the hashmaps of parents ordering |
graph_backend |
Graph backend, either |
B_sets |
matrix of B-sets, assumed to be increasing.
This can be the output of |
orderParents |
a vector of characters, interpreted as the ordered parents |
It returns 'TRUE' if the order abides by the B-sets, and 'FALSE' else.
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U1', 'U4') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") order_hash[['U4']] = c("U1", "U3") is_order_abiding_Bsets(DAG, order_hash) order_hash[['U3']] = c("U2", "U1") is_order_abiding_Bsets(DAG, order_hash)DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U3', 'U4') DAG = set_arc(DAG, 'U1', 'U4') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") order_hash[['U4']] = c("U1", "U3") is_order_abiding_Bsets(DAG, order_hash) order_hash[['U3']] = c("U2", "U1") is_order_abiding_Bsets(DAG, order_hash)
This functions checks whether the DAG is restricted, i.e. whether it has no active cycles nor any interfering v-structures.
is_restrictedDAG(DAG, verbose = 2, check_both = TRUE, graph_backend = NULL)is_restrictedDAG(DAG, verbose = 2, check_both = TRUE, graph_backend = NULL)
DAG |
the DAG object |
verbose |
if |
check_both |
if |
graph_backend |
Graph backend, either |
TRUE if the PCBN satisfies both restrictions.
FALSE if at least one of the restrictions is not satisfies.
DAG_to_restrictedDAG for one way of making the DAG
to be restricted if it is not the case.
active_cycles to find all active cycles.
has_interfering_vstrucs to check only for interfering v-structures.
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') is_restrictedDAG(DAG) # 1 active cycleDAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') is_restrictedDAG(DAG) # 1 active cycle
This function computes the log-likelihood of the PCBN model given a dataset
of i.i.d. observations uniformly (or approximatively uniformly) distributed
on . This is the same as the logarithm of the density of the PCBN
at the observations.
## S3 method for class 'PCBN' logLik(object, data_uniform, ...)## S3 method for class 'PCBN' logLik(object, data_uniform, ...)
object |
the PCBN object |
data_uniform |
the dataset for which the log-likelihood is computed. It must have already been standardized to uniform margins. |
... |
other arguments, ignored for the moment |
the log-likelihood of the PCBN model for the given dataset
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 10) logLik(my_PCBN, mydata)DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 10) logLik(my_PCBN, mydata)
Initializes PCBN class
new_PCBN(DAG, order_hash, copula_mat, verbose = 0, graph_backend = NULL)new_PCBN(DAG, order_hash, copula_mat, verbose = 0, graph_backend = NULL)
DAG |
The corresponding bnlearn or caugi DAG. |
order_hash |
a hashmap of character vectors Each character vector corresponds to the order of the parents for the given node. |
copula_mat |
a list with at least two components:
They both should be matrices of size |
verbose |
If |
graph_backend |
Graph backend, either |
The new PCBN, with the selected native graph in DAG
and the resolved backend in graph_backend.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam))DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam))
Checks a path for converging connections and chords.
path_hasConvergingConnections(DAG, path, graph_backend = NULL) path_hasChords(DAG, path, graph_backend = NULL)path_hasConvergingConnections(DAG, path, graph_backend = NULL) path_hasChords(DAG, path, graph_backend = NULL)
DAG |
Directed Acyclic Graph. |
path |
character vector of nodes in the DAG forming a trail. |
graph_backend |
Graph backend, either |
path_hasConvergingConnections returns TRUE
if the path contains a converging connection.
path_hasChords returns TRUE if the path contains a chord.
active_cycles which uses these two functions.
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U3', 'U4') path_hasConvergingConnections(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE path_hasChords(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE DAG = set_arc(DAG, 'U1', 'U4') path_hasConvergingConnections(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE path_hasChords(DAG, c('U1', 'U2', 'U3', 'U4') ) # TRUE: has a chord DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U4', 'U3') path_hasConvergingConnections(DAG, c('U1', 'U2', 'U3', 'U4') ) # TRUE: has a converging connection path_hasChords(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSEDAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U3', 'U4') path_hasConvergingConnections(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE path_hasChords(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE DAG = set_arc(DAG, 'U1', 'U4') path_hasConvergingConnections(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE path_hasChords(DAG, c('U1', 'U2', 'U3', 'U4') ) # TRUE: has a chord DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U2') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U4', 'U3') path_hasConvergingConnections(DAG, c('U1', 'U2', 'U3', 'U4') ) # TRUE: has a converging connection path_hasChords(DAG, c('U1', 'U2', 'U3', 'U4') ) # FALSE
This function computes the Probability Density Function of a PCBN model.
PCBN_PDF(PCBN, newdata)PCBN_PDF(PCBN, newdata)
PCBN |
PCBN object |
newdata |
new data on which the PDF should be computed |
This is a wrapper to logLik.PCBN.
the probability density at newdata.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 10) PCBN_PDF(my_PCBN, mydata)DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 10) PCBN_PDF(my_PCBN, mydata)
Simulate data from a specified PCBN
PCBN_sim(object, N, check_PCBN = TRUE, verbose = 1)PCBN_sim(object, N, check_PCBN = TRUE, verbose = 1)
object |
PCBN object to simulate from. This does not work if the PCBN does not abide by the B-sets. And in general, it does not work if the PCBN is outside of the class of restricted PCBNs. |
N |
sample size |
check_PCBN |
check whether the given PCBN satisfies the restrictions.
If this is set to |
verbose |
if |
a data frame of N samples
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 5)DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) mydata = PCBN_sim(my_PCBN, N = 5)
Print and plot PCBN objects
## S3 method for class 'PCBN' plot(x, ...) ## S3 method for class 'PCBN' print(x, print.orders = "non-empty", ...)## S3 method for class 'PCBN' plot(x, ...) ## S3 method for class 'PCBN' print(x, print.orders = "non-empty", ...)
x |
PCBN object |
... |
Arguments passed to the backend plotting function by |
print.orders |
if |
No return value, both functions are called for side effects only.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) print(my_PCBN) plot(my_PCBN)DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") fam = matrix(c(0, 0, 1, 0, 0, 1, 0, 0, 0), byrow = TRUE, ncol = 3) tau = 0.2 * fam my_PCBN = new_PCBN( DAG, order_hash, copula_mat = list(tau = tau, fam = fam)) print(my_PCBN) plot(my_PCBN)
When given a partial order of a PCBN, one can complete it by adding one of the parents' node to the partial order. Some nodes can be added; they are then called "possible candidates".
possible_candidates( DAG, v, order_v, order_hash, B_minus_O, graph_backend = NULL ) possible_candidate_incoming_arc( DAG, w, v, order_v, order_hash, graph_backend = NULL ) possible_candidate_outgoing_arc( DAG, w, v, order_v, order_hash, graph_backend = NULL )possible_candidates( DAG, v, order_v, order_hash, B_minus_O, graph_backend = NULL ) possible_candidate_incoming_arc( DAG, w, v, order_v, order_hash, graph_backend = NULL ) possible_candidate_outgoing_arc( DAG, w, v, order_v, order_hash, graph_backend = NULL )
DAG |
Directed Acyclic Graph. |
order_v |
partial order for node v. |
order_hash |
hashmap of parental orders |
B_minus_O |
this is the current B-set, without the elements of
|
graph_backend |
Graph backend, either |
w, v
|
nodes in DAG. |
possible_candidate_incoming_arc returns a node o such w
is a parent of o, and w can be used as an incoming arc to
v by the node o. If no such o can be found, w
cannot be used as a potential candidate for the order of v by incoming
arc. Then, the function possible_candidate_incoming_arc returns
NULL.
In the same way, possible_candidate_outgoing_arc returns a node
o such o is a parent of w, and w can be used as
an outgoing arc to v by the node o.
possible_candidates returns a vector of possible candidates,
potentially empty.
Both possible_candidate_incoming_arc and
possible_candidate_outgoing_arc return either a node o, or
NULL if they could not find such a node.
dsep_set for checking whether two sets of nodes are d-separated
by another set.
find_B_sets to find the B-sets.
DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") # Node of interest v = "U4" # If we start by 1, then the arc 1 -> 3 cannot be used as an incoming arc # (it is actually an outgoing arc) possible_candidate_incoming_arc( DAG = DAG, w = "U3", v = v, order_v = c("U1"), order_hash = order_hash) possible_candidate_outgoing_arc( DAG = DAG, w = "U3", v = v, order_v = c("U1"), order_hash = order_hash) possible_candidates( DAG = DAG, v = v, order_v = c("U1"), order_hash = order_hash, B_minus_O = "U2")DAG = create_empty_DAG(4) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') DAG = set_arc(DAG, 'U1', 'U4') DAG = set_arc(DAG, 'U2', 'U4') DAG = set_arc(DAG, 'U3', 'U4') order_hash = r2r::hashmap() order_hash[['U3']] = c("U1", "U2") # Node of interest v = "U4" # If we start by 1, then the arc 1 -> 3 cannot be used as an incoming arc # (it is actually an outgoing arc) possible_candidate_incoming_arc( DAG = DAG, w = "U3", v = v, order_v = c("U1"), order_hash = order_hash) possible_candidate_outgoing_arc( DAG = DAG, w = "U3", v = v, order_v = c("U1"), order_hash = order_hash) possible_candidates( DAG = DAG, v = v, order_v = c("U1"), order_hash = order_hash, B_minus_O = "U2")
Remove elements from a conditioning set by using conditional independence
remove_CondInd(DAG, node, cond_set, graph_backend = NULL)remove_CondInd(DAG, node, cond_set, graph_backend = NULL)
DAG |
Directed Acyclic Graph |
node |
node |
cond_set |
vector of nodes in conditioning set |
graph_backend |
Graph backend, either |
a vector containing the nodes that cannot be removed from the conditioning set.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') remove_CondInd(DAG = DAG, node = "U1", cond_set = c("U2")) remove_CondInd(DAG = DAG, node = "U3", cond_set = c("U1"))DAG = create_empty_DAG(3) DAG = set_arc(DAG, 'U1', 'U3') DAG = set_arc(DAG, 'U2', 'U3') remove_CondInd(DAG = DAG, node = "U1", cond_set = c("U2")) remove_CondInd(DAG = DAG, node = "U3", cond_set = c("U1"))
Adds an arc from one node to another, using the graph's backend by default. An existing arc in the same direction is left unchanged. Both nodes must already exist in the graph. Arcs that would create a directed cycle are rejected.
set_arc(DAG, from, to, graph_backend = NULL)set_arc(DAG, from, to, graph_backend = NULL)
DAG |
A bnlearn or caugi directed acyclic graph. |
from |
Name of the node where the arc starts. |
to |
Name of the node where the arc ends. |
graph_backend |
Graph backend, either |
The updated graph in the resolved backend.
DAG = create_empty_DAG(3) DAG = set_arc(DAG, "U1", "U3") DAG = set_arc(DAG, "U2", "U3") if (requireNamespace("caugi", quietly = TRUE)) { DAG = create_empty_DAG(3, graph_backend = "caugi") DAG = set_arc(DAG, "U1", "U3") DAG = set_arc(DAG, "U2", "U3") }DAG = create_empty_DAG(3) DAG = set_arc(DAG, "U1", "U3") DAG = set_arc(DAG, "U2", "U3") if (requireNamespace("caugi", quietly = TRUE)) { DAG = create_empty_DAG(3, graph_backend = "caugi") DAG = set_arc(DAG, "U1", "U3") DAG = set_arc(DAG, "U2", "U3") }