Skip to content

Commit cc2bd4f

Browse files
committed
update FCI test, refactor minor parts, update doc
1 parent 9bb1aa3 commit cc2bd4f

File tree

15 files changed

+78
-63
lines changed

15 files changed

+78
-63
lines changed

causallearn/search/ConstraintBased/FCI.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ def ruleR4B(graph, maxPathLength, data, independence_test_method, alpha, sep_set
553553

554554

555555
def fci(dataset, independence_test_method = fisherz, alpha=0.05, depth=-1, max_path_length=-1,
556-
verbose=False, knowledge=None):
556+
verbose=False, background_knowledge=None):
557557
'''
558558
Causal Discovery with Fast Causal Inference
559559
@@ -565,7 +565,7 @@ def fci(dataset, independence_test_method = fisherz, alpha=0.05, depth=-1, max_p
565565
depth: The depth for the fast adjacency search, or -1 if unlimited
566566
max_path_length: the maximum length of any discriminating path, or -1 if unlimited.
567567
verbose: True is verbose output should be printed or logged
568-
knowledge: background knowledge
568+
background_knowledge: background knowledge
569569
570570
Returns
571571
-------
@@ -576,8 +576,8 @@ def fci(dataset, independence_test_method = fisherz, alpha=0.05, depth=-1, max_p
576576
## ------- check parameters ------------
577577
if (depth is None) or type(depth) != int:
578578
raise TypeError("'depth' must be 'int' type!")
579-
if (knowledge is not None) and type(knowledge) != BackgroundKnowledge:
580-
raise TypeError("'knowledge' must be 'BackgroundKnowledge' type!")
579+
if (background_knowledge is not None) and type(background_knowledge) != BackgroundKnowledge:
580+
raise TypeError("'background_knowledge' must be 'BackgroundKnowledge' type!")
581581
if (max_path_length is not None) and type(max_path_length) != int:
582582
raise TypeError("'max_path_length' must be 'int' type!")
583583
## ------- end check parameters ------------
@@ -588,7 +588,7 @@ def fci(dataset, independence_test_method = fisherz, alpha=0.05, depth=-1, max_p
588588
node.add_attribute("id", i)
589589
nodes.append(node)
590590

591-
graph, sep_sets = fas(dataset, nodes, independence_test_method=independence_test_method, alpha=alpha, knowledge=knowledge, depth=depth, verbose=verbose)
591+
graph, sep_sets = fas(dataset, nodes, independence_test_method=independence_test_method, alpha=alpha, knowledge=background_knowledge, depth=depth, verbose=verbose)
592592

593593
# reorient all edges with CIRCLE Endpoint
594594
ori_edges = graph.get_graph_edges()
@@ -598,9 +598,9 @@ def fci(dataset, independence_test_method = fisherz, alpha=0.05, depth=-1, max_p
598598
ori_edge.set_endpoint2(Endpoint.CIRCLE)
599599
graph.add_edge(ori_edge)
600600

601-
sp = SepsetsPossibleDsep(dataset, graph, independence_test_method, alpha, knowledge, depth, max_path_length, verbose)
601+
sp = SepsetsPossibleDsep(dataset, graph, independence_test_method, alpha, background_knowledge, depth, max_path_length, verbose)
602602

603-
rule0(graph, nodes, sep_sets, knowledge, verbose)
603+
rule0(graph, nodes, sep_sets, background_knowledge, verbose)
604604

605605
waiting_to_deleted_edges = []
606606

@@ -626,21 +626,21 @@ def fci(dataset, independence_test_method = fisherz, alpha=0.05, depth=-1, max_p
626626
print(message)
627627

628628
reorientAllWith(graph, Endpoint.CIRCLE)
629-
rule0(graph, nodes, sep_sets, knowledge, verbose)
629+
rule0(graph, nodes, sep_sets, background_knowledge, verbose)
630630

631631
changeFlag = True
632632
firstTime = True
633633

634634
while changeFlag:
635635
changeFlag = False
636-
changeFlag = rulesR1R2cycle(graph, knowledge, changeFlag, verbose)
637-
changeFlag = ruleR3(graph, sep_sets, knowledge, changeFlag, verbose)
638-
639-
if changeFlag or (firstTime and knowledge is not None and
640-
len(knowledge.forbidden_rules_specs) > 0 and
641-
len(knowledge.required_rules_specs) > 0 and
642-
len(knowledge.tier_map.keys()) > 0):
643-
changeFlag = ruleR4B(graph, max_path_length, dataset, independence_test_method, alpha, sep_sets, changeFlag, knowledge, verbose)
636+
changeFlag = rulesR1R2cycle(graph, background_knowledge, changeFlag, verbose)
637+
changeFlag = ruleR3(graph, sep_sets, background_knowledge, changeFlag, verbose)
638+
639+
if changeFlag or (firstTime and background_knowledge is not None and
640+
len(background_knowledge.forbidden_rules_specs) > 0 and
641+
len(background_knowledge.required_rules_specs) > 0 and
642+
len(background_knowledge.tier_map.keys()) > 0):
643+
changeFlag = ruleR4B(graph, max_path_length, dataset, independence_test_method, alpha, sep_sets, changeFlag, background_knowledge, verbose)
644644

645645
firstTime = False
646646

causallearn/search/FCMBased/lingam/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def _estimate_adjacency_matrix(self, X, prior_knowledge=None):
124124
Training data, where n_samples is the number of samples
125125
and n_features is the number of features.
126126
prior_knowledge : array-like, shape (n_variables, n_variables), optional (default=None)
127-
Prior knowledge matrix.
127+
Prior background_knowledge matrix.
128128
129129
Returns
130130
-------
@@ -140,7 +140,7 @@ def _estimate_adjacency_matrix(self, X, prior_knowledge=None):
140140
target = self._causal_order[i]
141141
predictors = self._causal_order[:i]
142142

143-
# Exclude variables specified in no_path with prior knowledge
143+
# Exclude variables specified in no_path with prior background_knowledge
144144
if prior_knowledge is not None:
145145
predictors = [p for p in predictors if pk[target, p] != 0]
146146

causallearn/search/FCMBased/lingam/bottom_up_parce_lingam.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ def __init__(self, random_state=None, alpha=0.1, regressor=None, prior_knowledge
3939
Regressor to compute residuals.
4040
This regressor object must have ``fit``method and ``predict`` function like scikit-learn's model.
4141
prior_knowledge : array-like, shape (n_features, n_features), optional (default=None)
42-
Prior knowledge used for causal discovery, where ``n_features`` is the number of features.
42+
Prior background_knowledge used for causal discovery, where ``n_features`` is the number of features.
4343
44-
The elements of prior knowledge matrix are defined as follows [1]_:
44+
The elements of prior background_knowledge matrix are defined as follows [1]_:
4545
4646
* ``0`` : :math:`x_i` does not have a directed path to :math:`x_j`
4747
* ``1`` : :math:`x_i` has a directed path to :math:`x_j`
48-
* ``-1`` : No prior knowledge is available to know if either of the two cases above (0 or 1) is true.
48+
* ``-1`` : No prior background_knowledge is available to know if either of the two cases above (0 or 1) is true.
4949
"""
5050
# Check parameters
5151
if regressor is not None:
@@ -66,7 +66,7 @@ def __init__(self, random_state=None, alpha=0.1, regressor=None, prior_knowledge
6666
self._Aknw = check_array(self._Aknw)
6767
self._Aknw = np.where(self._Aknw < 0, np.nan, self._Aknw)
6868

69-
# Extract all partial orders in prior knowledge matrix
69+
# Extract all partial orders in prior background_knowledge matrix
7070
self._partial_orders = self._extract_partial_orders(self._Aknw)
7171

7272
def fit(self, X):
@@ -90,11 +90,11 @@ def fit(self, X):
9090
X = check_array(X)
9191
n_features = X.shape[1]
9292

93-
# Check prior knowledge
93+
# Check prior background_knowledge
9494
if self._Aknw is not None:
9595
if (n_features, n_features) != self._Aknw.shape:
9696
raise ValueError(
97-
'The shape of prior knowledge must be (n_features, n_features)')
97+
'The shape of prior background_knowledge must be (n_features, n_features)')
9898

9999
# Center variables for each group
100100
X = X - np.tile(np.mean(X, axis=0), (X.shape[0], 1))
@@ -118,7 +118,7 @@ def fit(self, X):
118118
return self._estimate_adjacency_matrix(X, prior_knowledge=self._Aknw)
119119

120120
def _extract_partial_orders(self, pk):
121-
""" Extract partial orders from prior knowledge."""
121+
""" Extract partial orders from prior background_knowledge."""
122122
path_pairs = np.array(np.where(pk == 1)).transpose()
123123
no_path_pairs = np.array(np.where(pk == 0)).transpose()
124124

@@ -128,7 +128,7 @@ def _extract_partial_orders(self, pk):
128128
pairs, counts = np.unique(check_pairs, axis=0, return_counts=True)
129129
if len(pairs[counts > 1]) > 0:
130130
raise ValueError(
131-
f'The prior knowledge contains inconsistencies at the following indices: {pairs[counts > 1].tolist()}')
131+
f'The prior background_knowledge contains inconsistencies at the following indices: {pairs[counts > 1].tolist()}')
132132

133133
# Check for inconsistencies in pairs without path
134134
# If there are duplicate pairs without path, they cancel out and are not ordered.
@@ -141,8 +141,8 @@ def _extract_partial_orders(self, pk):
141141

142142
check_pairs = np.concatenate([path_pairs, no_path_pairs[:, [1, 0]]])
143143
if len(check_pairs) == 0:
144-
# If no pairs are extracted from the specified prior knowledge,
145-
# discard the prior knowledge.
144+
# If no pairs are extracted from the specified prior background_knowledge,
145+
# discard the prior background_knowledge.
146146
self._Aknw = None
147147
return None
148148

@@ -151,7 +151,7 @@ def _extract_partial_orders(self, pk):
151151

152152
def _search_candidate(self, U):
153153
""" Search for candidate features """
154-
# If no prior knowledge is specified, nothing to do.
154+
# If no prior background_knowledge is specified, nothing to do.
155155
if self._Aknw is None:
156156
return U
157157

@@ -283,7 +283,7 @@ def _estimate_adjacency_matrix(self, X, prior_knowledge=None):
283283
Training data, where n_samples is the number of samples
284284
and n_features is the number of features.
285285
prior_knowledge : array-like, shape (n_variables, n_variables), optional (default=None)
286-
Prior knowledge matrix.
286+
Prior background_knowledge matrix.
287287
288288
Returns
289289
-------
@@ -301,7 +301,7 @@ def _estimate_adjacency_matrix(self, X, prior_knowledge=None):
301301
# Flatten the array into one dimension
302302
predictors = self._flatten(self._causal_order[:i])
303303

304-
# Exclude variables specified in no_path with prior knowledge
304+
# Exclude variables specified in no_path with prior background_knowledge
305305
if prior_knowledge is not None:
306306
predictors = [p for p in predictors if pk[target, p] != 0]
307307

causallearn/search/FCMBased/lingam/direct_lingam.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ def __init__(self, random_state=None, prior_knowledge=None, apply_prior_knowledg
2929
random_state : int, optional (default=None)
3030
``random_state`` is the seed used by the random number generator.
3131
prior_knowledge : array-like, shape (n_features, n_features), optional (default=None)
32-
Prior knowledge used for causal discovery, where ``n_features`` is the number of features.
32+
Prior background_knowledge used for causal discovery, where ``n_features`` is the number of features.
3333
34-
The elements of prior knowledge matrix are defined as follows [1]_:
34+
The elements of prior background_knowledge matrix are defined as follows [1]_:
3535
3636
* ``0`` : :math:`x_i` does not have a directed path to :math:`x_j`
3737
* ``1`` : :math:`x_i` has a directed path to :math:`x_j`
38-
* ``-1`` : No prior knowledge is available to know if either of the two cases above (0 or 1) is true.
38+
* ``-1`` : No prior background_knowledge is available to know if either of the two cases above (0 or 1) is true.
3939
apply_prior_knowledge_softly : boolean, optional (default=False)
40-
If True, apply prior knowledge softly.
40+
If True, apply prior background_knowledge softly.
4141
measure : {'pwling', 'kernel'}, optional (default='pwling')
4242
Measure to evaluate independence: 'pwling' [2]_ or 'kernel' [1]_.
4343
"""
@@ -50,7 +50,7 @@ def __init__(self, random_state=None, prior_knowledge=None, apply_prior_knowledg
5050
self._Aknw = check_array(self._Aknw)
5151
self._Aknw = np.where(self._Aknw < 0, np.nan, self._Aknw)
5252

53-
# Extract all partial orders in prior knowledge matrix
53+
# Extract all partial orders in prior background_knowledge matrix
5454
if not self._apply_prior_knowledge_softly:
5555
self._partial_orders = self._extract_partial_orders(self._Aknw)
5656

@@ -74,7 +74,7 @@ def fit(self, X):
7474
if self._Aknw is not None:
7575
if (n_features, n_features) != self._Aknw.shape:
7676
raise ValueError(
77-
'The shape of prior knowledge must be (n_features, n_features)')
77+
'The shape of prior background_knowledge must be (n_features, n_features)')
7878

7979
# Causal discovery
8080
U = np.arange(n_features)
@@ -101,7 +101,7 @@ def fit(self, X):
101101
return self._estimate_adjacency_matrix(X, prior_knowledge=self._Aknw)
102102

103103
def _extract_partial_orders(self, pk):
104-
""" Extract partial orders from prior knowledge."""
104+
""" Extract partial orders from prior background_knowledge."""
105105
path_pairs = np.array(np.where(pk == 1)).transpose()
106106
no_path_pairs = np.array(np.where(pk == 0)).transpose()
107107

@@ -111,7 +111,7 @@ def _extract_partial_orders(self, pk):
111111
pairs, counts = np.unique(check_pairs, axis=0, return_counts=True)
112112
if len(pairs[counts > 1]) > 0:
113113
raise ValueError(
114-
f'The prior knowledge contains inconsistencies at the following indices: {pairs[counts > 1].tolist()}')
114+
f'The prior background_knowledge contains inconsistencies at the following indices: {pairs[counts > 1].tolist()}')
115115

116116
# Check for inconsistencies in pairs without path.
117117
# If there are duplicate pairs without path, they cancel out and are not ordered.
@@ -124,8 +124,8 @@ def _extract_partial_orders(self, pk):
124124

125125
check_pairs = np.concatenate([path_pairs, no_path_pairs[:, [1, 0]]])
126126
if len(check_pairs) == 0:
127-
# If no pairs are extracted from the specified prior knowledge,
128-
# discard the prior knowledge.
127+
# If no pairs are extracted from the specified prior background_knowledge,
128+
# discard the prior background_knowledge.
129129
self._Aknw = None
130130
return None
131131

@@ -152,11 +152,11 @@ def _diff_mutual_info(self, xi_std, xj_std, ri_j, rj_i):
152152

153153
def _search_candidate(self, U):
154154
""" Search for candidate features """
155-
# If no prior knowledge is specified, nothing to do.
155+
# If no prior background_knowledge is specified, nothing to do.
156156
if self._Aknw is None:
157157
return U, []
158158

159-
# Apply prior knowledge in a strong way
159+
# Apply prior background_knowledge in a strong way
160160
if not self._apply_prior_knowledge_softly:
161161
Uc = [i for i in U if i not in self._partial_orders[:, 1]]
162162
return Uc, []

causallearn/search/FCMBased/lingam/multi_group_direct_lingam.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ def __init__(self, random_state=None, prior_knowledge=None, apply_prior_knowledg
3131
random_state : int, optional (default=None)
3232
``random_state`` is the seed used by the random number generator.
3333
prior_knowledge : array-like, shape (n_features, n_features), optional (default=None)
34-
Prior knowledge used for causal discovery, where ``n_features`` is the number of features.
34+
Prior background_knowledge used for causal discovery, where ``n_features`` is the number of features.
3535
36-
The elements of prior knowledge matrix are defined as follows [1]_:
36+
The elements of prior background_knowledge matrix are defined as follows [1]_:
3737
3838
* ``0`` : :math:`x_i` does not have a directed path to :math:`x_j`
3939
* ``1`` : :math:`x_i` has a directed path to :math:`x_j`
40-
* ``-1`` : No prior knowledge is available to know if either of the two cases above (0 or 1) is true.
40+
* ``-1`` : No prior background_knowledge is available to know if either of the two cases above (0 or 1) is true.
4141
apply_prior_knowledge_softly : boolean, optional (default=False)
42-
If True, apply prior knowledge softly.
42+
If True, apply prior background_knowledge softly.
4343
"""
4444
super().__init__(random_state, prior_knowledge, apply_prior_knowledge_softly)
4545

@@ -64,7 +64,7 @@ def fit(self, X_list):
6464
if self._Aknw is not None:
6565
if (self._n_features, self._n_features) != self._Aknw.shape:
6666
raise ValueError(
67-
'The shape of prior knowledge must be (n_features, n_features)')
67+
'The shape of prior background_knowledge must be (n_features, n_features)')
6868

6969
# Causal discovery
7070
U = np.arange(self._n_features)

causallearn/search/FCMBased/lingam/utils/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,29 @@ def print_dagc(dagc, n_sampling, labels=None):
6161

6262

6363
def make_prior_knowledge(n_variables, exogenous_variables=None, sink_variables=None, paths=None, no_paths=None):
64-
""" Make matrix of prior knowledge.
64+
""" Make matrix of prior background_knowledge.
6565
6666
Parameters
6767
----------
6868
n_variables : int
6969
Number of variables.
7070
exogenous_variables : array-like, shape (index, ...), optional (default=None)
7171
List of exogenous variables(index).
72-
Prior knowledge is created with the specified variables as exogenous variables.
72+
Prior background_knowledge is created with the specified variables as exogenous variables.
7373
sink_variables : array-like, shape (index, ...), optional (default=None)
7474
List of sink variables(index).
75-
Prior knowledge is created with the specified variables as sink variables.
75+
Prior background_knowledge is created with the specified variables as sink variables.
7676
paths : array-like, shape ((index, index), ...), optional (default=None)
7777
List of variables(index) pairs with directed path.
78-
If ``(i, j)``, prior knowledge is created that xi has a directed path to xj.
78+
If ``(i, j)``, prior background_knowledge is created that xi has a directed path to xj.
7979
no_paths : array-like, shape ((index, index), ...), optional (default=None)
8080
List of variables(index) pairs without directed path.
81-
If ``(i, j)``, prior knowledge is created that xi does not have a directed path to xj.
81+
If ``(i, j)``, prior background_knowledge is created that xi does not have a directed path to xj.
8282
8383
Returns
8484
-------
8585
prior_knowledge : array-like, shape (n_variables, n_variables)
86-
Return matrix of prior knowledge used for causal discovery.
86+
Return matrix of prior background_knowledge used for causal discovery.
8787
"""
8888
prior_knowledge = np.full((n_variables, n_variables), -1)
8989
if no_paths:

causallearn/utils/Fas.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def forbiddenEdge(node_x, node_y, knowledge):
3434
if knowledge is None:
3535
return False
3636
elif knowledge.is_forbidden(node_x, node_y) and knowledge.is_forbidden(node_y, node_x):
37-
print(node_x.get_name() + " --- " + node_y.get_name() + " because it was forbidden by background knowledge.")
37+
print(node_x.get_name() + " --- " + node_y.get_name() + " because it was forbidden by background background_knowledge.")
3838
return True
3939
return False
4040

@@ -148,7 +148,7 @@ def fas(data, nodes, independence_test_method=fisherz, alpha=0.05, knowledge=Non
148148
node: The search nodes.
149149
independence_test_method: the independence test method, which should be in causallearn.utils.cit
150150
alpha: Significance level of independence tests(p_value)(min = 0.00)
151-
knowledge: background knowledge
151+
knowledge: background background_knowledge
152152
depth: The depth for the fast adjacency search, or -1 if unlimited
153153
verbose: True is verbose output should be printed or logged
154154
@@ -162,7 +162,7 @@ def fas(data, nodes, independence_test_method=fisherz, alpha=0.05, knowledge=Non
162162
if (depth is not None) and type(depth) != int:
163163
raise TypeError("'depth' must be 'int' type!")
164164
if (knowledge is not None) and type(knowledge) != BackgroundKnowledge:
165-
raise TypeError("'knowledge' must be 'BackgroundKnowledge' type!")
165+
raise TypeError("'background_knowledge' must be 'BackgroundKnowledge' type!")
166166

167167
# --------end check parameter -----------
168168

0 commit comments

Comments
 (0)