pyAgrum-nightly 2.3.1.9.dev202512261765915415__cp310-abi3-macosx_10_15_x86_64.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.
Files changed (107) hide show
  1. pyagrum/__init__.py +165 -0
  2. pyagrum/_pyagrum.so +0 -0
  3. pyagrum/bnmixture/BNMInference.py +268 -0
  4. pyagrum/bnmixture/BNMLearning.py +376 -0
  5. pyagrum/bnmixture/BNMixture.py +464 -0
  6. pyagrum/bnmixture/__init__.py +60 -0
  7. pyagrum/bnmixture/notebook.py +1058 -0
  8. pyagrum/causal/_CausalFormula.py +280 -0
  9. pyagrum/causal/_CausalModel.py +436 -0
  10. pyagrum/causal/__init__.py +81 -0
  11. pyagrum/causal/_causalImpact.py +356 -0
  12. pyagrum/causal/_dSeparation.py +598 -0
  13. pyagrum/causal/_doAST.py +761 -0
  14. pyagrum/causal/_doCalculus.py +361 -0
  15. pyagrum/causal/_doorCriteria.py +374 -0
  16. pyagrum/causal/_exceptions.py +95 -0
  17. pyagrum/causal/_types.py +61 -0
  18. pyagrum/causal/causalEffectEstimation/_CausalEffectEstimation.py +1175 -0
  19. pyagrum/causal/causalEffectEstimation/_IVEstimators.py +718 -0
  20. pyagrum/causal/causalEffectEstimation/_RCTEstimators.py +132 -0
  21. pyagrum/causal/causalEffectEstimation/__init__.py +46 -0
  22. pyagrum/causal/causalEffectEstimation/_backdoorEstimators.py +774 -0
  23. pyagrum/causal/causalEffectEstimation/_causalBNEstimator.py +324 -0
  24. pyagrum/causal/causalEffectEstimation/_frontdoorEstimators.py +396 -0
  25. pyagrum/causal/causalEffectEstimation/_learners.py +118 -0
  26. pyagrum/causal/causalEffectEstimation/_utils.py +466 -0
  27. pyagrum/causal/notebook.py +172 -0
  28. pyagrum/clg/CLG.py +658 -0
  29. pyagrum/clg/GaussianVariable.py +111 -0
  30. pyagrum/clg/SEM.py +312 -0
  31. pyagrum/clg/__init__.py +63 -0
  32. pyagrum/clg/canonicalForm.py +408 -0
  33. pyagrum/clg/constants.py +54 -0
  34. pyagrum/clg/forwardSampling.py +202 -0
  35. pyagrum/clg/learning.py +776 -0
  36. pyagrum/clg/notebook.py +480 -0
  37. pyagrum/clg/variableElimination.py +271 -0
  38. pyagrum/common.py +60 -0
  39. pyagrum/config.py +319 -0
  40. pyagrum/ctbn/CIM.py +513 -0
  41. pyagrum/ctbn/CTBN.py +573 -0
  42. pyagrum/ctbn/CTBNGenerator.py +216 -0
  43. pyagrum/ctbn/CTBNInference.py +459 -0
  44. pyagrum/ctbn/CTBNLearner.py +161 -0
  45. pyagrum/ctbn/SamplesStats.py +671 -0
  46. pyagrum/ctbn/StatsIndepTest.py +355 -0
  47. pyagrum/ctbn/__init__.py +79 -0
  48. pyagrum/ctbn/constants.py +54 -0
  49. pyagrum/ctbn/notebook.py +264 -0
  50. pyagrum/defaults.ini +199 -0
  51. pyagrum/deprecated.py +95 -0
  52. pyagrum/explain/_ComputationCausal.py +75 -0
  53. pyagrum/explain/_ComputationConditional.py +48 -0
  54. pyagrum/explain/_ComputationMarginal.py +48 -0
  55. pyagrum/explain/_CustomShapleyCache.py +110 -0
  56. pyagrum/explain/_Explainer.py +176 -0
  57. pyagrum/explain/_Explanation.py +70 -0
  58. pyagrum/explain/_FIFOCache.py +54 -0
  59. pyagrum/explain/_ShallCausalValues.py +204 -0
  60. pyagrum/explain/_ShallConditionalValues.py +155 -0
  61. pyagrum/explain/_ShallMarginalValues.py +155 -0
  62. pyagrum/explain/_ShallValues.py +296 -0
  63. pyagrum/explain/_ShapCausalValues.py +208 -0
  64. pyagrum/explain/_ShapConditionalValues.py +126 -0
  65. pyagrum/explain/_ShapMarginalValues.py +191 -0
  66. pyagrum/explain/_ShapleyValues.py +298 -0
  67. pyagrum/explain/__init__.py +81 -0
  68. pyagrum/explain/_explGeneralizedMarkovBlanket.py +152 -0
  69. pyagrum/explain/_explIndependenceListForPairs.py +146 -0
  70. pyagrum/explain/_explInformationGraph.py +264 -0
  71. pyagrum/explain/notebook/__init__.py +54 -0
  72. pyagrum/explain/notebook/_bar.py +142 -0
  73. pyagrum/explain/notebook/_beeswarm.py +174 -0
  74. pyagrum/explain/notebook/_showShapValues.py +97 -0
  75. pyagrum/explain/notebook/_waterfall.py +220 -0
  76. pyagrum/explain/shapley.py +225 -0
  77. pyagrum/lib/__init__.py +46 -0
  78. pyagrum/lib/_colors.py +390 -0
  79. pyagrum/lib/bn2graph.py +299 -0
  80. pyagrum/lib/bn2roc.py +1026 -0
  81. pyagrum/lib/bn2scores.py +217 -0
  82. pyagrum/lib/bn_vs_bn.py +605 -0
  83. pyagrum/lib/cn2graph.py +305 -0
  84. pyagrum/lib/discreteTypeProcessor.py +1102 -0
  85. pyagrum/lib/discretizer.py +58 -0
  86. pyagrum/lib/dynamicBN.py +390 -0
  87. pyagrum/lib/explain.py +57 -0
  88. pyagrum/lib/export.py +84 -0
  89. pyagrum/lib/id2graph.py +258 -0
  90. pyagrum/lib/image.py +387 -0
  91. pyagrum/lib/ipython.py +307 -0
  92. pyagrum/lib/mrf2graph.py +471 -0
  93. pyagrum/lib/notebook.py +1821 -0
  94. pyagrum/lib/proba_histogram.py +552 -0
  95. pyagrum/lib/utils.py +138 -0
  96. pyagrum/pyagrum.py +31495 -0
  97. pyagrum/skbn/_MBCalcul.py +242 -0
  98. pyagrum/skbn/__init__.py +49 -0
  99. pyagrum/skbn/_learningMethods.py +282 -0
  100. pyagrum/skbn/_utils.py +297 -0
  101. pyagrum/skbn/bnclassifier.py +1014 -0
  102. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/LICENSE.md +12 -0
  103. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/LICENSES/LGPL-3.0-or-later.txt +304 -0
  104. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/LICENSES/MIT.txt +18 -0
  105. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/METADATA +145 -0
  106. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/RECORD +107 -0
  107. pyagrum_nightly-2.3.1.9.dev202512261765915415.dist-info/WHEEL +4 -0
@@ -0,0 +1,324 @@
1
+ ############################################################################
2
+ # This file is part of the aGrUM/pyAgrum library. #
3
+ # #
4
+ # Copyright (c) 2005-2025 by #
5
+ # - Pierre-Henri WUILLEMIN(_at_LIP6) #
6
+ # - Christophe GONZALES(_at_AMU) #
7
+ # #
8
+ # The aGrUM/pyAgrum library is free software; you can redistribute it #
9
+ # and/or modify it under the terms of either : #
10
+ # #
11
+ # - the GNU Lesser General Public License as published by #
12
+ # the Free Software Foundation, either version 3 of the License, #
13
+ # or (at your option) any later version, #
14
+ # - the MIT license (MIT), #
15
+ # - or both in dual license, as here. #
16
+ # #
17
+ # (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) #
18
+ # #
19
+ # This aGrUM/pyAgrum library is distributed in the hope that it will be #
20
+ # useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
21
+ # INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS #
22
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
23
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
24
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, #
25
+ # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR #
26
+ # OTHER DEALINGS IN THE SOFTWARE. #
27
+ # #
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 #
34
+ # #
35
+ # Contact : info_at_agrum_dot_org #
36
+ # homepage : http://agrum.gitlab.io #
37
+ # gitlab : https://gitlab.com/agrumery/agrum #
38
+ # #
39
+ ############################################################################
40
+
41
+ import numpy as np
42
+ import pandas as pd
43
+
44
+ import pyagrum as gum
45
+ import pyagrum.causal as csl
46
+
47
+
48
+ class CausalBNEstimator:
49
+ """
50
+ A Causal Bayesian Network Estimator.
51
+
52
+ This class utilizes do-calculus identification and lazy propagation
53
+ inference, implemented via the pyAgrum library's causal module,
54
+ to determine the causal effect within Bayesian Networks.
55
+
56
+ Note: In the case of instrumental variables, the causal effect is
57
+ estimated using heuristic methods, as this adjustment is not
58
+ identifiable through do-calculus.
59
+ """
60
+
61
+ def _useCausalStructure(self, cm_clone: csl.CausalModel, causal_model: csl.CausalModel) -> None:
62
+ """
63
+ Use the causal structure given by `cm_clone` on `causal_model`.
64
+
65
+ Parameters
66
+ ----------
67
+ cm_clone: csl.CausalStructure
68
+ The model recieving the causal structure.
69
+ causal_model: csl.CausalStructure
70
+ The model giving the causal structure.
71
+ """
72
+
73
+ for id in causal_model.latentVariablesIds():
74
+ childrens = causal_model.causalBN().children(id)
75
+ childrens = {causal_model.causalBN().variable(c).name() for c in childrens}
76
+ cm_clone.addLatentVariable(causal_model.causalBN().variable(id).name(), tuple(childrens))
77
+ for x, y in causal_model.arcs():
78
+ if not cm_clone.existsArc(x, y):
79
+ cm_clone.addCausalArc(x, y)
80
+
81
+ def __init__(
82
+ self, causal_model: csl.CausalModel, treatment: str, outcome: str, instrument: str | None = None
83
+ ) -> None:
84
+ """
85
+ Initialize an Causal Model estimator.
86
+
87
+ Parameters
88
+ ----------
89
+ causal_model: csl.CausalModel
90
+ The causal graph.
91
+ treatment: str
92
+ The treatment variable.
93
+ outcome: str
94
+ The outcome variable.
95
+ instrument: str, optional
96
+ The instrumental variable
97
+ """
98
+
99
+ if isinstance(causal_model, csl.CausalModel):
100
+ self.causal_model = causal_model.clone()
101
+ self._useCausalStructure(self.causal_model, causal_model)
102
+ else:
103
+ raise ValueError("`causal_model` must be instance of `pyagrum.causal.CausalModel`.")
104
+
105
+ self.treatment = treatment
106
+ self.outcome = outcome
107
+ self.instrument = instrument
108
+
109
+ def fit(self, df: pd.DataFrame, smoothing_prior: float = 1e-9) -> None:
110
+ """
111
+ Fit the inference model.
112
+
113
+ Parameters
114
+ ----------
115
+ df: pd.DataFrame
116
+ The observations.
117
+ smoothing_prior (Optional): float
118
+ The uniform prior distribution. Default is 1e-9.
119
+ """
120
+
121
+ parameter_learner = gum.BNLearner(df, self.causal_model.observationalBN())
122
+ parameter_learner.useNMLCorrection()
123
+ parameter_learner.useSmoothingPrior(smoothing_prior)
124
+
125
+ bn = gum.BayesNet(self.causal_model.observationalBN())
126
+
127
+ parameter_learner.fitParameters(bn)
128
+
129
+ causal_model = csl.CausalModel(bn)
130
+ self._useCausalStructure(causal_model, self.causal_model)
131
+ self.causal_model = causal_model
132
+
133
+ return self.causal_model
134
+
135
+ def _getIntervalIndex(self, x: float, var: str) -> int:
136
+ """
137
+ Gets the domain index of the variable.
138
+
139
+ Parameters
140
+ ---------
141
+ x: float
142
+ The conditional.
143
+ var: str
144
+ The variable label string.
145
+
146
+ Returns
147
+ -------
148
+ int
149
+ The index of the conditional in the variable domain.
150
+ """
151
+
152
+ splits = list()
153
+ accumulator = ""
154
+ for letter in self.causal_model.causalBN().variable(var).domain():
155
+ if letter in ["-", ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]:
156
+ accumulator += letter
157
+ elif len(accumulator) > 0:
158
+ split = float(accumulator)
159
+ if len(splits) > 0 and splits[-1] == split:
160
+ splits.pop()
161
+ splits.append(split)
162
+ accumulator = ""
163
+
164
+ for i in range(len(splits)):
165
+ if x < splits[i]:
166
+ return i
167
+
168
+ return len(splits) - 1
169
+
170
+ def _predictRow(self, X: pd.Series) -> float:
171
+ """
172
+ Predict the Individual Causal Effect (ICE) of a single row.
173
+
174
+ Parameters
175
+ ----------
176
+ X: pd.Series
177
+ The of covariates.
178
+
179
+ Returns
180
+ -------
181
+ float
182
+ The predicted ICE.
183
+ """
184
+
185
+ keys = X.index.to_list()
186
+ values = list()
187
+
188
+ for covar in X.index:
189
+ values.append(self._getIntervalIndex(X[covar], covar))
190
+
191
+ if self.instrument is not None:
192
+ ie = gum.LazyPropagation(self.causal_model.observationalBN())
193
+ ie.setEvidence(dict(zip(keys + [self.instrument], values + [0])))
194
+ cptY0 = ie.posterior(self.outcome)
195
+ cptT0 = ie.posterior(self.treatment)
196
+ ie.setEvidence(dict(zip(keys + [self.instrument], values + [1])))
197
+ cptY1 = ie.posterior(self.outcome)
198
+ cptT1 = ie.posterior(self.treatment)
199
+
200
+ diffY = cptY1 - cptY0
201
+ diffT = cptT1 - cptT0
202
+
203
+ return diffY.expectedValue(
204
+ lambda d: diffY.variable(0).numerical(d[diffY.variable(0).name()])
205
+ ) / diffT.expectedValue(lambda d: diffT.variable(0).numerical(d[diffT.variable(0).name()]))
206
+
207
+ else:
208
+ _, cpt0, _ = csl.causalImpact(
209
+ cm=self.causal_model,
210
+ on=self.outcome,
211
+ doing=self.treatment,
212
+ knowing=set(X.index),
213
+ values=dict(zip(keys + [self.treatment], values + [0])),
214
+ )
215
+
216
+ _, cpt1, _ = csl.causalImpact(
217
+ cm=self.causal_model,
218
+ on=self.outcome,
219
+ doing=self.treatment,
220
+ knowing=set(X.index),
221
+ values=dict(zip(keys + [self.treatment], values + [1])),
222
+ )
223
+
224
+ if cpt0 is None:
225
+ raise csl._exceptions.HedgeException("Causal effect is unidentifiable using do-calculus.")
226
+
227
+ diff = cpt1 - cpt0
228
+ return diff.expectedValue(lambda d: diff.variable(0).numerical(d[diff.variable(0).name()]))
229
+
230
+ def predict(
231
+ self,
232
+ w: np.matrix | np.ndarray | pd.DataFrame = None,
233
+ X: np.matrix | np.ndarray | pd.DataFrame = None,
234
+ M: np.matrix | np.ndarray | pd.DataFrame = None,
235
+ treatment: np.ndarray | pd.Series | None = None,
236
+ y: np.ndarray | pd.Series | None = None,
237
+ ) -> np.ndarray:
238
+ """
239
+ Predict the Individual Causal Effect (ICE),
240
+ also referd to as the Individual Treatment Effect (ITE).
241
+
242
+ Parameters
243
+ ----------
244
+ w: np.matrix or np.ndarray or pd.DataFrame
245
+ The instrument variable.
246
+ X: np.matrix or np.ndarray or pd.DataFrame
247
+ The matrix of covariates.
248
+ treatment: np.ndarray or pd.Series or None, optional
249
+ The vector of treatment assignments.
250
+ y: np.ndarray or pd.Series, optional
251
+ The vector of outcomes.
252
+
253
+ Returns
254
+ -------
255
+ np.ndarray
256
+ An array containing the predicted ICE.
257
+ """
258
+
259
+ if X is not None:
260
+ return X.apply(self._predictRow, axis=1).to_numpy()
261
+ else:
262
+ return M.apply(self._predictRow, axis=1).to_numpy()
263
+
264
+ def estimate_ate(
265
+ self,
266
+ w: np.matrix | np.ndarray | pd.DataFrame = None,
267
+ X: np.matrix | np.ndarray | pd.DataFrame = None,
268
+ M: np.matrix | np.ndarray | pd.DataFrame = None,
269
+ treatment: np.ndarray | pd.Series | None = None,
270
+ y: np.ndarray | pd.Series | None = None,
271
+ pretrain: bool = True,
272
+ ) -> float:
273
+ """
274
+ Predicts the Average Causal Effect (ACE),
275
+ also refered to as the Average Treatment Effect (ATE).
276
+ (The term ATE is used in the method name for compatibility purposes.)
277
+
278
+ Parameters
279
+ ----------
280
+ w: np.matrix or np.ndarray or pd.DataFrame
281
+ The instrument variable.
282
+ X: np.matrix or np.ndarray or pd.DataFrame
283
+ The matrix of covariates.
284
+ treatment: np.ndarray or pd.Series or None, optional
285
+ The vector of treatment assignments.
286
+ y: np.ndarray or pd.Series, optional
287
+ The vector of outcomes.
288
+
289
+ Returns
290
+ -------
291
+ float
292
+ The value of the ACE.
293
+ """
294
+
295
+ if self.instrument is not None:
296
+ ie = gum.LazyPropagation(self.causal_model.observationalBN())
297
+ ie.setEvidence({self.instrument: 0})
298
+ cptY0 = ie.posterior(self.outcome)
299
+ cptT0 = ie.posterior(self.treatment)
300
+ ie.setEvidence({self.instrument: 1})
301
+ cptY1 = ie.posterior(self.outcome)
302
+ cptT1 = ie.posterior(self.treatment)
303
+
304
+ diffY = cptY1 - cptY0
305
+ diffT = cptT1 - cptT0
306
+
307
+ return diffY.expectedValue(
308
+ lambda d: diffY.variable(0).numerical(d[diffY.variable(0).name()])
309
+ ) / diffT.expectedValue(lambda d: diffT.variable(0).numerical(d[diffT.variable(0).name()]))
310
+
311
+ else:
312
+ _, cpt0, _ = csl.causalImpact(
313
+ self.causal_model, on=self.outcome, doing=self.treatment, values={self.treatment: 0}
314
+ )
315
+
316
+ _, cpt1, _ = csl.causalImpact(
317
+ self.causal_model, on=self.outcome, doing=self.treatment, values={self.treatment: 1}
318
+ )
319
+
320
+ if cpt0 is None:
321
+ raise csl._exceptions.HedgeException("Causal effect is unidentifiable using do-calculus.")
322
+
323
+ difference = cpt1 - cpt0
324
+ return difference.expectedValue(lambda d: difference.variable(0).numerical(d[difference.variable(0).name()]))