pyAgrum-nightly 2.1.1.9.dev202506061747485979__cp310-abi3-manylinux2014_aarch64.whl → 2.3.1.9.dev202601031765915415__cp310-abi3-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyagrum/__init__.py +6 -2
- pyagrum/_pyagrum.so +0 -0
- pyagrum/bnmixture/BNMInference.py +6 -2
- pyagrum/bnmixture/BNMLearning.py +12 -2
- pyagrum/bnmixture/BNMixture.py +6 -2
- pyagrum/bnmixture/__init__.py +6 -2
- pyagrum/bnmixture/notebook.py +6 -2
- pyagrum/causal/_CausalFormula.py +6 -2
- pyagrum/causal/_CausalModel.py +6 -2
- pyagrum/causal/__init__.py +6 -2
- pyagrum/causal/_causalImpact.py +6 -2
- pyagrum/causal/_dSeparation.py +6 -2
- pyagrum/causal/_doAST.py +6 -2
- pyagrum/causal/_doCalculus.py +6 -2
- pyagrum/causal/_doorCriteria.py +6 -2
- pyagrum/causal/_exceptions.py +6 -2
- pyagrum/causal/_types.py +6 -2
- pyagrum/causal/causalEffectEstimation/_CausalEffectEstimation.py +6 -2
- pyagrum/causal/causalEffectEstimation/_IVEstimators.py +6 -2
- pyagrum/causal/causalEffectEstimation/_RCTEstimators.py +6 -2
- pyagrum/causal/causalEffectEstimation/__init__.py +6 -2
- pyagrum/causal/causalEffectEstimation/_backdoorEstimators.py +6 -2
- pyagrum/causal/causalEffectEstimation/_causalBNEstimator.py +6 -2
- pyagrum/causal/causalEffectEstimation/_frontdoorEstimators.py +6 -2
- pyagrum/causal/causalEffectEstimation/_learners.py +6 -2
- pyagrum/causal/causalEffectEstimation/_utils.py +6 -2
- pyagrum/causal/notebook.py +8 -3
- pyagrum/clg/CLG.py +6 -2
- pyagrum/clg/GaussianVariable.py +6 -2
- pyagrum/clg/SEM.py +6 -2
- pyagrum/clg/__init__.py +6 -2
- pyagrum/clg/canonicalForm.py +6 -2
- pyagrum/clg/constants.py +6 -2
- pyagrum/clg/forwardSampling.py +6 -2
- pyagrum/clg/learning.py +6 -2
- pyagrum/clg/notebook.py +6 -2
- pyagrum/clg/variableElimination.py +6 -2
- pyagrum/common.py +7 -3
- pyagrum/config.py +7 -2
- pyagrum/ctbn/CIM.py +6 -2
- pyagrum/ctbn/CTBN.py +6 -2
- pyagrum/ctbn/CTBNGenerator.py +6 -2
- pyagrum/ctbn/CTBNInference.py +6 -2
- pyagrum/ctbn/CTBNLearner.py +6 -2
- pyagrum/ctbn/SamplesStats.py +6 -2
- pyagrum/ctbn/StatsIndepTest.py +6 -2
- pyagrum/ctbn/__init__.py +6 -2
- pyagrum/ctbn/constants.py +6 -2
- pyagrum/ctbn/notebook.py +6 -2
- pyagrum/deprecated.py +6 -2
- pyagrum/explain/_ComputationCausal.py +75 -0
- pyagrum/explain/_ComputationConditional.py +48 -0
- pyagrum/explain/_ComputationMarginal.py +48 -0
- pyagrum/explain/_CustomShapleyCache.py +110 -0
- pyagrum/explain/_Explainer.py +176 -0
- pyagrum/explain/_Explanation.py +70 -0
- pyagrum/explain/_FIFOCache.py +54 -0
- pyagrum/explain/_ShallCausalValues.py +204 -0
- pyagrum/explain/_ShallConditionalValues.py +155 -0
- pyagrum/explain/_ShallMarginalValues.py +155 -0
- pyagrum/explain/_ShallValues.py +296 -0
- pyagrum/explain/_ShapCausalValues.py +208 -0
- pyagrum/explain/_ShapConditionalValues.py +126 -0
- pyagrum/explain/_ShapMarginalValues.py +191 -0
- pyagrum/explain/_ShapleyValues.py +298 -0
- pyagrum/explain/__init__.py +81 -0
- pyagrum/explain/_explGeneralizedMarkovBlanket.py +152 -0
- pyagrum/explain/_explIndependenceListForPairs.py +146 -0
- pyagrum/explain/_explInformationGraph.py +264 -0
- pyagrum/explain/notebook/__init__.py +54 -0
- pyagrum/explain/notebook/_bar.py +142 -0
- pyagrum/explain/notebook/_beeswarm.py +174 -0
- pyagrum/explain/notebook/_showShapValues.py +97 -0
- pyagrum/explain/notebook/_waterfall.py +220 -0
- pyagrum/explain/shapley.py +225 -0
- pyagrum/lib/__init__.py +6 -2
- pyagrum/lib/_colors.py +6 -2
- pyagrum/lib/bn2graph.py +6 -2
- pyagrum/lib/bn2roc.py +6 -2
- pyagrum/lib/bn2scores.py +6 -2
- pyagrum/lib/bn_vs_bn.py +6 -2
- pyagrum/lib/cn2graph.py +6 -2
- pyagrum/lib/discreteTypeProcessor.py +99 -81
- pyagrum/lib/discretizer.py +6 -2
- pyagrum/lib/dynamicBN.py +6 -2
- pyagrum/lib/explain.py +17 -492
- pyagrum/lib/export.py +6 -2
- pyagrum/lib/id2graph.py +6 -2
- pyagrum/lib/image.py +6 -2
- pyagrum/lib/ipython.py +6 -2
- pyagrum/lib/mrf2graph.py +6 -2
- pyagrum/lib/notebook.py +6 -2
- pyagrum/lib/proba_histogram.py +6 -2
- pyagrum/lib/utils.py +6 -2
- pyagrum/pyagrum.py +976 -126
- pyagrum/skbn/_MBCalcul.py +6 -2
- pyagrum/skbn/__init__.py +6 -2
- pyagrum/skbn/_learningMethods.py +6 -2
- pyagrum/skbn/_utils.py +6 -2
- pyagrum/skbn/bnclassifier.py +6 -2
- pyagrum_nightly-2.1.1.9.dev202506061747485979.dist-info/LICENSE → pyagrum_nightly-2.3.1.9.dev202601031765915415.dist-info/LICENSE.md +3 -1
- pyagrum_nightly-2.3.1.9.dev202601031765915415.dist-info/LICENSES/LGPL-3.0-or-later.txt +304 -0
- pyagrum_nightly-2.3.1.9.dev202601031765915415.dist-info/LICENSES/MIT.txt +18 -0
- {pyagrum_nightly-2.1.1.9.dev202506061747485979.dist-info → pyagrum_nightly-2.3.1.9.dev202601031765915415.dist-info}/METADATA +3 -1
- pyagrum_nightly-2.3.1.9.dev202601031765915415.dist-info/RECORD +107 -0
- {pyagrum_nightly-2.1.1.9.dev202506061747485979.dist-info → pyagrum_nightly-2.3.1.9.dev202601031765915415.dist-info}/WHEEL +1 -1
- pyagrum/lib/shapley.py +0 -657
- pyagrum_nightly-2.1.1.9.dev202506061747485979.dist-info/LICENSE.LGPL +0 -165
- pyagrum_nightly-2.1.1.9.dev202506061747485979.dist-info/LICENSE.MIT +0 -17
- pyagrum_nightly-2.1.1.9.dev202506061747485979.dist-info/RECORD +0 -83
pyagrum/lib/explain.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
|
@@ -38,495 +42,16 @@
|
|
|
38
42
|
tools for BN qualitative analysis and explainability
|
|
39
43
|
"""
|
|
40
44
|
|
|
41
|
-
import itertools
|
|
42
45
|
import warnings
|
|
43
|
-
from typing import Union
|
|
44
|
-
|
|
45
|
-
import pylab
|
|
46
|
-
import pydot as dot
|
|
47
|
-
|
|
48
|
-
import matplotlib as mpl
|
|
49
|
-
import matplotlib.pyplot as plt
|
|
50
|
-
|
|
51
|
-
import pyagrum as gum
|
|
52
|
-
from pyagrum.lib.bn2graph import BN2dot
|
|
53
|
-
import pyagrum.lib._colors as gumcols
|
|
54
|
-
|
|
55
|
-
# importing ShapValues in the name space of explain
|
|
56
|
-
# ruff: noqa: F401
|
|
57
|
-
from pyagrum.lib.shapley import ShapValues
|
|
58
|
-
|
|
59
|
-
_cdict = {
|
|
60
|
-
"red": ((0.0, 0.1, 0.3), (1.0, 0.6, 1.0)),
|
|
61
|
-
"green": ((0.0, 0.0, 0.0), (1.0, 0.6, 0.8)),
|
|
62
|
-
"blue": ((0.0, 0.0, 0.0), (1.0, 1, 0.8)),
|
|
63
|
-
}
|
|
64
|
-
_INFOcmap = mpl.colors.LinearSegmentedColormap("my_colormap", _cdict, 256)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _independenceListForPairs(bn, target=None):
|
|
68
|
-
"""
|
|
69
|
-
returns a list of triples `(i,j,k)` for each non arc `(i,j)` such that `i` is independent of `j` given `k`.
|
|
70
|
-
|
|
71
|
-
Parameters
|
|
72
|
-
----------
|
|
73
|
-
bn: gum.BayesNet
|
|
74
|
-
the Bayesian Network
|
|
75
|
-
|
|
76
|
-
target: (optional) str or int
|
|
77
|
-
the name or id of the target variable. If a target is given, only the independence given a subset of the markov blanket of the target are tested.
|
|
78
|
-
|
|
79
|
-
Returns
|
|
80
|
-
-------
|
|
81
|
-
List[(str,str,List[str])]
|
|
82
|
-
A list of independence found in the structure of BN.
|
|
83
|
-
"""
|
|
84
|
-
|
|
85
|
-
def powerset(iterable):
|
|
86
|
-
xs = list(iterable)
|
|
87
|
-
# note we return an iterator rather than a list
|
|
88
|
-
return itertools.chain.from_iterable(itertools.combinations(xs, n) for n in range(len(xs) + 1))
|
|
89
|
-
|
|
90
|
-
# testing every d-separation
|
|
91
|
-
l = []
|
|
92
|
-
nams = sorted(bn.names())
|
|
93
|
-
if target is None:
|
|
94
|
-
firstnams = nams.copy()
|
|
95
|
-
indepnodes = bn.names()
|
|
96
|
-
else:
|
|
97
|
-
indepnodes = {bn.variable(i).name() for i in gum.MarkovBlanket(bn, target).nodes()}
|
|
98
|
-
if isinstance(target, str):
|
|
99
|
-
firstnams = [target]
|
|
100
|
-
else:
|
|
101
|
-
firstnams = [bn.variable(target).name()]
|
|
102
|
-
|
|
103
|
-
for i in firstnams:
|
|
104
|
-
nams.remove(i)
|
|
105
|
-
for j in nams:
|
|
106
|
-
if not (bn.existsArc(i, j) or bn.existsArc(j, i)):
|
|
107
|
-
for k in powerset(sorted(indepnodes - {i, j})):
|
|
108
|
-
if bn.isIndependent(i, j, k):
|
|
109
|
-
l.append((i, j, tuple(k)))
|
|
110
|
-
break
|
|
111
|
-
return l
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def independenceListForPairs(bn, filename, target=None, plot=True, alphabetic=False):
|
|
115
|
-
"""
|
|
116
|
-
get the p-values of the chi2 test of a (as simple as possible) independence proposition for every non arc.
|
|
117
|
-
|
|
118
|
-
Parameters
|
|
119
|
-
----------
|
|
120
|
-
bn : gum.BayesNet
|
|
121
|
-
the Bayesian network
|
|
122
|
-
|
|
123
|
-
filename : str
|
|
124
|
-
the name of the csv database
|
|
125
|
-
|
|
126
|
-
alphabetic : bool
|
|
127
|
-
if True, the list is alphabetically sorted else it is sorted by the p-value
|
|
128
|
-
|
|
129
|
-
target: (optional) str or int
|
|
130
|
-
the name or id of the target variable
|
|
131
|
-
|
|
132
|
-
plot : bool
|
|
133
|
-
if True, plot the result
|
|
134
|
-
|
|
135
|
-
Returns
|
|
136
|
-
-------
|
|
137
|
-
the list
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
learner = gum.BNLearner(filename, bn)
|
|
141
|
-
vals = {}
|
|
142
|
-
for indep in _independenceListForPairs(bn, target):
|
|
143
|
-
vals[indep] = learner.chi2(*indep)[1]
|
|
144
|
-
|
|
145
|
-
if plot:
|
|
146
|
-
plotvals = dict()
|
|
147
|
-
for indep in vals:
|
|
148
|
-
key = "$" + indep[0] + " \\perp " + indep[1]
|
|
149
|
-
if len(indep[2]) > 0:
|
|
150
|
-
key += " \\mid " + ",".join(indep[2])
|
|
151
|
-
key += "$"
|
|
152
|
-
plotvals[key] = vals[indep]
|
|
153
|
-
|
|
154
|
-
if not alphabetic:
|
|
155
|
-
sortedkeys = sorted(plotvals, key=plotvals.__getitem__, reverse=False)
|
|
156
|
-
else:
|
|
157
|
-
sortedkeys = list(plotvals.keys())
|
|
158
|
-
|
|
159
|
-
fig = pylab.figure(figsize=(10, 1 + 0.25 * len(plotvals)))
|
|
160
|
-
ax = fig.add_subplot(1, 1, 1)
|
|
161
|
-
ax.plot([plotvals[k] for k in sortedkeys], sortedkeys, "o")
|
|
162
|
-
ax.grid(True)
|
|
163
|
-
ax.vlines(x=0.05, ymin=-0.5, ymax=len(vals) - 0.5, colors="purple")
|
|
164
|
-
ax.add_patch(mpl.patches.Rectangle((0, -0.5), 0.05, len(vals), color="yellow"))
|
|
165
|
-
|
|
166
|
-
return vals
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def _normalizeVals(vals, hilightExtrema=False):
|
|
170
|
-
"""
|
|
171
|
-
normalisation if vals is not a proba (max>1)
|
|
172
|
-
"""
|
|
173
|
-
ma = float(max(vals.values()))
|
|
174
|
-
mi = float(min(vals.values()))
|
|
175
|
-
if ma == mi:
|
|
176
|
-
return None
|
|
177
|
-
|
|
178
|
-
if not hilightExtrema:
|
|
179
|
-
vmi = 0.01
|
|
180
|
-
vma = 0.99
|
|
181
|
-
else:
|
|
182
|
-
vmi = 0
|
|
183
|
-
vma = 1
|
|
184
|
-
|
|
185
|
-
res = {name: vmi + (val - mi) * (vma - vmi) / (ma - mi) for name, val in vals.items()}
|
|
186
|
-
return res
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def getInformationGraph(bn, evs=None, size=None, cmap=_INFOcmap, withMinMax=False):
|
|
190
|
-
"""
|
|
191
|
-
Create a dot representation of the information graph for this BN
|
|
192
|
-
|
|
193
|
-
Parameters
|
|
194
|
-
----------
|
|
195
|
-
bn: gum.BayesNet
|
|
196
|
-
the BN
|
|
197
|
-
evs : Dict[str,str|int|List[float]]
|
|
198
|
-
map of evidence
|
|
199
|
-
size: str|int
|
|
200
|
-
size of the graph
|
|
201
|
-
cmap: matplotlib.colors.Colormap
|
|
202
|
-
color map
|
|
203
|
-
withMinMax: bool
|
|
204
|
-
min and max in the return values ?
|
|
205
|
-
|
|
206
|
-
Returns
|
|
207
|
-
-------
|
|
208
|
-
dot.Dot | Tuple[dot.Dot,float,float,float,float]
|
|
209
|
-
graph as a dot representation and if asked, min_information_value, max_information_value, min_mutual_information_value, max_mutual_information_value
|
|
210
|
-
"""
|
|
211
|
-
if size is None:
|
|
212
|
-
size = gum.config["notebook", "default_graph_size"]
|
|
213
|
-
|
|
214
|
-
if evs is None:
|
|
215
|
-
evs = {}
|
|
216
|
-
|
|
217
|
-
ie = gum.LazyPropagation(bn)
|
|
218
|
-
ie.setEvidence(evs)
|
|
219
|
-
ie.makeInference()
|
|
220
|
-
|
|
221
|
-
idEvs = ie.hardEvidenceNodes() | ie.softEvidenceNodes()
|
|
222
|
-
|
|
223
|
-
nodevals = dict()
|
|
224
|
-
for n in bn.nodes():
|
|
225
|
-
if n not in idEvs:
|
|
226
|
-
v = ie.H(n)
|
|
227
|
-
if v != v: # is NaN
|
|
228
|
-
warnings.warn(f"For {bn.variable(n).name()}, entropy is NaN.")
|
|
229
|
-
v = 0
|
|
230
|
-
nodevals[bn.variable(n).name()] = v
|
|
231
|
-
|
|
232
|
-
arcvals = dict()
|
|
233
|
-
for x, y in bn.arcs():
|
|
234
|
-
v = ie.jointMutualInformation({x, y})
|
|
235
|
-
if v != v: # is NaN
|
|
236
|
-
warnings.warn(f"For {bn.variable(x).name()}->{bn.variable(y).name()}, mutual information is Nan.")
|
|
237
|
-
v = 0
|
|
238
|
-
arcvals[(x, y)] = v
|
|
239
|
-
|
|
240
|
-
gr = BN2dot(
|
|
241
|
-
bn,
|
|
242
|
-
size,
|
|
243
|
-
nodeColor=_normalizeVals(nodevals, hilightExtrema=False),
|
|
244
|
-
arcWidth=arcvals,
|
|
245
|
-
cmapNode=cmap,
|
|
246
|
-
cmapArc=cmap,
|
|
247
|
-
showMsg=nodevals,
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
if withMinMax:
|
|
251
|
-
mi_node = min(nodevals.values())
|
|
252
|
-
ma_node = max(nodevals.values())
|
|
253
|
-
mi_arc = min(arcvals.values())
|
|
254
|
-
ma_arc = max(arcvals.values())
|
|
255
|
-
return gr, mi_node, ma_node, mi_arc, ma_arc
|
|
256
|
-
else:
|
|
257
|
-
return gr
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
def _reprInformation(bn, evs=None, size=None, cmap=_INFOcmap, asString=False):
|
|
261
|
-
"""
|
|
262
|
-
repr a bn annotated with results from inference : Information and mutual information
|
|
263
|
-
|
|
264
|
-
Parameters
|
|
265
|
-
----------
|
|
266
|
-
bn: pyagrum.BayesNet
|
|
267
|
-
the model
|
|
268
|
-
evs: Dict[str|int,str|int|List[float]]
|
|
269
|
-
the observations
|
|
270
|
-
size: int|str
|
|
271
|
-
size of the rendered graph
|
|
272
|
-
cmap: matplotlib.colours.Colormap
|
|
273
|
-
the cmap
|
|
274
|
-
asString: bool
|
|
275
|
-
returns the string or display the HTML
|
|
276
|
-
|
|
277
|
-
Returns
|
|
278
|
-
-------
|
|
279
|
-
str|None
|
|
280
|
-
return the HTML string or directly display it.
|
|
281
|
-
"""
|
|
282
|
-
import IPython.display
|
|
283
|
-
import IPython.core.pylabtools
|
|
284
|
-
from base64 import encodebytes
|
|
285
|
-
from matplotlib.backends.backend_agg import FigureCanvasAgg as fc
|
|
286
|
-
|
|
287
|
-
if size is None:
|
|
288
|
-
size = gum.config["notebook", "default_graph_size"]
|
|
289
|
-
|
|
290
|
-
if evs is None:
|
|
291
|
-
evs = {}
|
|
292
|
-
|
|
293
|
-
gr, mi, ma, _, _ = getInformationGraph(bn, evs, size, cmap, withMinMax=True)
|
|
294
|
-
gumcols.prepareDot(gr, size=size)
|
|
295
|
-
|
|
296
|
-
# dynamic member makes pylink unhappy
|
|
297
|
-
# pylint: disable=no-member
|
|
298
|
-
gsvg = IPython.display.SVG(gr.create_svg(encoding="utf-8"))
|
|
299
|
-
width = (
|
|
300
|
-
int(gsvg.data.split("width=")[1].split('"')[1].split("pt")[0]) / mpl.pyplot.rcParams["figure.dpi"]
|
|
301
|
-
) # pixel in inches
|
|
302
|
-
if width < 5:
|
|
303
|
-
width = 5
|
|
304
|
-
|
|
305
|
-
fig = mpl.figure.Figure(figsize=(width, 1))
|
|
306
|
-
fig.patch.set_alpha(0)
|
|
307
|
-
canvas = fc(fig)
|
|
308
|
-
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
|
|
309
|
-
norm = mpl.colors.Normalize(vmin=mi, vmax=ma)
|
|
310
|
-
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap=cmap, norm=norm, orientation="horizontal")
|
|
311
|
-
cb1.set_label("Entropy")
|
|
312
|
-
cb1.ax.text(mi, -2, f"{mi:.4f}", ha="left", va="top", color=gumcols.proba2bgcolor(0.01, cmap))
|
|
313
|
-
cb1.ax.text(ma, -2, f"{ma:.4f}", ha="right", va="top", color=gumcols.proba2bgcolor(0.99, cmap))
|
|
314
|
-
png = IPython.core.pylabtools.print_figure(canvas.figure, "png") # from IPython.core.pylabtools
|
|
315
|
-
png_legend = f"<img style='vertical-align:middle' src='data:image/png;base64,{encodebytes(png).decode('ascii')}'>"
|
|
316
|
-
|
|
317
|
-
sss = f"<div align='center'>{gsvg.data}<br/>{png_legend}</div>"
|
|
318
|
-
|
|
319
|
-
if asString:
|
|
320
|
-
return sss
|
|
321
|
-
|
|
322
|
-
return IPython.display.display(IPython.display.HTML(sss))
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
def getInformation(bn, evs=None, size=None, cmap=_INFOcmap) -> str:
|
|
326
|
-
"""
|
|
327
|
-
get a HTML string for a bn annotated with results from inference : entropy and mutual information
|
|
328
|
-
|
|
329
|
-
Parameters
|
|
330
|
-
----------
|
|
331
|
-
bn: pyagrum.BayesNet
|
|
332
|
-
the model
|
|
333
|
-
evs: Dict[str|int,str|int|List[float]]
|
|
334
|
-
the observations
|
|
335
|
-
size: int|str
|
|
336
|
-
size of the rendered graph
|
|
337
|
-
cmap: matplotlib.colours.Colormap
|
|
338
|
-
the cmap
|
|
339
|
-
|
|
340
|
-
Returns
|
|
341
|
-
-------
|
|
342
|
-
str
|
|
343
|
-
return the HTML string
|
|
344
|
-
"""
|
|
345
|
-
if size is None:
|
|
346
|
-
size = gum.config["notebook", "default_graph_size"]
|
|
347
|
-
|
|
348
|
-
if evs is None:
|
|
349
|
-
evs = {}
|
|
350
|
-
|
|
351
|
-
return _reprInformation(bn, evs, size, cmap, asString=True)
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
def showInformation(bn, evs=None, size=None, cmap=_INFOcmap):
|
|
355
|
-
"""
|
|
356
|
-
diplay a bn annotated with results from inference : entropy and mutual information
|
|
357
|
-
|
|
358
|
-
Parameters
|
|
359
|
-
----------
|
|
360
|
-
bn: pyagrum.BayesNet
|
|
361
|
-
the model
|
|
362
|
-
evs: Dict[str|int,str|int|List[float]]
|
|
363
|
-
the observations
|
|
364
|
-
size: int|str
|
|
365
|
-
size of the rendered graph
|
|
366
|
-
cmap: matplotlib.colours.Colormap
|
|
367
|
-
the cmap
|
|
368
|
-
"""
|
|
369
|
-
if evs is None:
|
|
370
|
-
evs = {}
|
|
371
|
-
|
|
372
|
-
if size is None:
|
|
373
|
-
size = gum.config["notebook", "default_graph_size"]
|
|
374
|
-
return _reprInformation(bn, evs, size, cmap, asString=False)
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
########################## MB(k) #####################################
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
def _buildMB(model, x: int, k: int = 1):
|
|
381
|
-
"""
|
|
382
|
-
Build the nodes and arcs of Markov Blanket (of order k) of node x
|
|
383
|
-
|
|
384
|
-
Parameters
|
|
385
|
-
----------
|
|
386
|
-
model: pyagrum.DirectedGraphicalModel
|
|
387
|
-
i.e. a class with methods parents, children, variable(i), idFromName(name)
|
|
388
|
-
x : int
|
|
389
|
-
the nodeId of the node for the Markov blanket
|
|
390
|
-
k: int
|
|
391
|
-
the order of the Markov blanket. If k=2, build the MarkovBlanket(MarkovBlanket())
|
|
392
|
-
|
|
393
|
-
Returns
|
|
394
|
-
-------
|
|
395
|
-
(nodes,arcs,depth) : the set of nodes, the set of arcs of the Markov Blanket and a dict[Str,int] that gives the MB-depth of each node in nodes.
|
|
396
|
-
"""
|
|
397
|
-
nodes = {x}
|
|
398
|
-
arcs = set()
|
|
399
|
-
depth = dict()
|
|
400
|
-
|
|
401
|
-
def _internal_build_markov_blanket(bn, x: int, k: int):
|
|
402
|
-
nodes.add(x)
|
|
403
|
-
depth[x] = k
|
|
404
|
-
if k == 0:
|
|
405
|
-
return
|
|
406
|
-
for y in bn.parents(x):
|
|
407
|
-
visit(y, k - 1)
|
|
408
|
-
arcs.add((y, x))
|
|
409
|
-
for y in bn.children(x):
|
|
410
|
-
visit(y, k - 1)
|
|
411
|
-
arcs.add((x, y))
|
|
412
|
-
for z in bn.parents(y):
|
|
413
|
-
visit(z, k - 1)
|
|
414
|
-
arcs.add((z, y))
|
|
415
|
-
|
|
416
|
-
def visit(x, k):
|
|
417
|
-
if x in nodes and depth[x] >= k:
|
|
418
|
-
return
|
|
419
|
-
_internal_build_markov_blanket(model, x, k)
|
|
420
|
-
|
|
421
|
-
_internal_build_markov_blanket(model, x, k)
|
|
422
|
-
return nodes, arcs, depth
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
def generalizedMarkovBlanket(bn, var: Union[int, str], k: int = 1, cmapNode=None):
|
|
426
|
-
"""
|
|
427
|
-
Build a pydot.Dot representation of the nested Markov Blankets (of order k) of node x
|
|
428
|
-
|
|
429
|
-
Warnings
|
|
430
|
-
--------
|
|
431
|
-
It is assumed that k<=8. If not, every thing is fine except that the colorscale will change in order to accept more colors.
|
|
432
|
-
|
|
433
|
-
Parameters
|
|
434
|
-
----------
|
|
435
|
-
bn: pyagrum.DirectedGraphicalModel
|
|
436
|
-
i.e. a class with methods parents, children, variable(i), idFromName(name)
|
|
437
|
-
var : str|int
|
|
438
|
-
the name or nodeId of the node for the Markov blanket
|
|
439
|
-
k: int
|
|
440
|
-
the order of the Markov blanket. If k=1, build the MarkovBlanket(MarkovBlanket())
|
|
441
|
-
cmap: maplotlib.ColorMap
|
|
442
|
-
the colormap used (if not, inferno is used)
|
|
443
|
-
|
|
444
|
-
Returns
|
|
445
|
-
-------
|
|
446
|
-
pydotplus.Dot object
|
|
447
|
-
"""
|
|
448
|
-
if cmapNode is None:
|
|
449
|
-
cmapNode = plt.get_cmap("inferno") # gum.config["notebook", "default_arc_cmap"])
|
|
450
|
-
|
|
451
|
-
maxcols = max(
|
|
452
|
-
8, k
|
|
453
|
-
) # It is assumed that k<=8. If not, every thing is fine except that the colorscale will change in order to accept more colors.
|
|
454
|
-
|
|
455
|
-
mb = dot.Dot(f"MB({var},{k}", graph_type="digraph", bgcolor="transparent")
|
|
456
|
-
|
|
457
|
-
if isinstance(var, str):
|
|
458
|
-
nx = bn.idFromName(var)
|
|
459
|
-
else:
|
|
460
|
-
nx = var
|
|
461
|
-
nodes, arcs, visited = _buildMB(bn, nx, k)
|
|
462
|
-
names = dict()
|
|
463
|
-
|
|
464
|
-
for n in nodes:
|
|
465
|
-
protected_name = f'"{bn.variable(n).name()}"'
|
|
466
|
-
pnode = dot.Node(protected_name, style="filled")
|
|
467
|
-
if n == var:
|
|
468
|
-
bgcol = "#99FF99"
|
|
469
|
-
fgcol = "black"
|
|
470
|
-
else:
|
|
471
|
-
bgcol = gumcols.proba2bgcolor(1 - (k - visited[n]) / maxcols, cmapNode)
|
|
472
|
-
fgcol = gumcols.proba2fgcolor(1 - (k - visited[n]) / maxcols, cmapNode)
|
|
473
|
-
pnode.set_fillcolor(bgcol)
|
|
474
|
-
pnode.set_fontcolor(fgcol)
|
|
475
|
-
mb.add_node(pnode)
|
|
476
|
-
names[n] = protected_name
|
|
477
|
-
for n in nodes:
|
|
478
|
-
for u in bn.parents(n).intersection(nodes):
|
|
479
|
-
edge = dot.Edge(names[u], names[n])
|
|
480
|
-
if (u, n) in arcs:
|
|
481
|
-
edge.set_color("black")
|
|
482
|
-
else:
|
|
483
|
-
edge.set_color("#DDDDDD")
|
|
484
|
-
mb.add_edge(edge)
|
|
485
|
-
|
|
486
|
-
return mb
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
def generalizedMarkovBlanketNames(bn, var: Union[int, str], depth: int = 1):
|
|
490
|
-
"""
|
|
491
|
-
List the name of all nodes in the nested Markov Blankets (of order k) in association with their depth
|
|
492
|
-
|
|
493
|
-
Parameters
|
|
494
|
-
----------
|
|
495
|
-
bn: pyagrum.DirectedGraphicalModel
|
|
496
|
-
i.e. a class with methods parents, children, variable(i), idFromName(name)
|
|
497
|
-
var : str|int
|
|
498
|
-
the name or nodeId of the node for the Markov blanket
|
|
499
|
-
depth: int
|
|
500
|
-
the order of the Markov blanket. If k=1, build the MarkovBlanket(MarkovBlanket()
|
|
501
|
-
|
|
502
|
-
Returns
|
|
503
|
-
-------
|
|
504
|
-
Dict[str,int]
|
|
505
|
-
the list of names and their depth.
|
|
506
|
-
"""
|
|
507
|
-
if isinstance(var, str):
|
|
508
|
-
nx = bn.idFromName(var)
|
|
509
|
-
else:
|
|
510
|
-
nx = var
|
|
511
|
-
nodes, _, visited = _buildMB(bn, nx, depth)
|
|
512
|
-
return {bn.variable(node).name(): depth - visited[node] for node in nodes}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
def showShapValues(bn, shaps, cmap="plasma") -> None:
|
|
516
|
-
"""
|
|
517
|
-
Show the Shap values in the DAG of the BN
|
|
518
|
-
|
|
519
|
-
Parameters
|
|
520
|
-
----------
|
|
521
|
-
bn : pyagrum.BayesNet
|
|
522
|
-
The Bayesian network
|
|
523
|
-
shaps: dict[str,float]
|
|
524
|
-
The (Shap) values to each variable
|
|
525
|
-
cmap: Matplotlib.ColorMap
|
|
526
|
-
The colormap used for coloring the nodes
|
|
527
|
-
"""
|
|
528
|
-
import pyagrum.lib.shapley as shapley
|
|
529
|
-
import pyagrum.lib.notebook as gnb
|
|
530
46
|
|
|
531
|
-
|
|
532
|
-
|
|
47
|
+
warnings.warn(
|
|
48
|
+
"The module 'pyagrum.lib.explain' has been deprecated since version 2.2.2. "
|
|
49
|
+
"Please use the 'pyagrum.explain' module instead.",
|
|
50
|
+
DeprecationWarning,
|
|
51
|
+
stacklevel=2,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
from pyagrum.explain.shapley import ShapValues # noqa: E402
|
|
55
|
+
from pyagrum.explain.notebook import showShapValues # noqa: E402
|
|
56
|
+
from pyagrum.explain import independenceListForPairs # noqa: E402
|
|
57
|
+
from pyagrum.explain import showInformation, getInformation, getInformationGraph # noqa: E402
|
pyagrum/lib/export.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/id2graph.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/image.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/ipython.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/mrf2graph.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/notebook.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/proba_histogram.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|
pyagrum/lib/utils.py
CHANGED
|
@@ -25,8 +25,12 @@
|
|
|
25
25
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
|
|
26
26
|
# OTHER DEALINGS IN THE SOFTWARE. #
|
|
27
27
|
# #
|
|
28
|
-
# See
|
|
29
|
-
#
|
|
28
|
+
# See LICENCES for more details. #
|
|
29
|
+
# #
|
|
30
|
+
# SPDX-FileCopyrightText: Copyright 2005-2025 #
|
|
31
|
+
# - Pierre-Henri WUILLEMIN(_at_LIP6) #
|
|
32
|
+
# - Christophe GONZALES(_at_AMU) #
|
|
33
|
+
# SPDX-License-Identifier: LGPL-3.0-or-later OR MIT #
|
|
30
34
|
# #
|
|
31
35
|
# Contact : info_at_agrum_dot_org #
|
|
32
36
|
# homepage : http://agrum.gitlab.io #
|