causing 2.3.0__py3-none-any.whl → 2.4.1__py3-none-any.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.

Potentially problematic release.


This version of causing might be problematic. Click here for more details.

causing/graph.py CHANGED
@@ -69,8 +69,8 @@ def save_graph(path: Path, graph_dot):
69
69
  svg_code = subprocess.check_output(
70
70
  [DOT_COMMAND, "-Tsvg"], input=graph_dot, encoding="utf-8"
71
71
  )
72
- if dot_version()[0] < 3:
73
- svg_code = fix_svg_scale(svg_code)
72
+ # if dot_version()[0] < 3:
73
+ # svg_code = fix_svg_scale(svg_code)
74
74
  with open(path, "w") as f:
75
75
  f.write(svg_code)
76
76
 
@@ -149,6 +149,7 @@ def graph_to_dot(
149
149
  graph_options_str=GRAPH_OPTIONS_STR,
150
150
  in_percent=False,
151
151
  min_sig_figures=3,
152
+ cutoff=0.0001,
152
153
  ):
153
154
  dot_str = "digraph {" + graph_options_str
154
155
  max_val = max(
@@ -157,13 +158,21 @@ def graph_to_dot(
157
158
  )
158
159
 
159
160
  for node, data in g.nodes(data=True):
160
- eff_str = utils.fmt_min_sig(data["effect"], min_sig_figures, percent=in_percent)
161
+ eff_str = utils.fmt_min_sig(
162
+ data["effect"] if abs(data["effect"]) > cutoff else 0,
163
+ min_sig_figures,
164
+ percent=in_percent,
165
+ )
161
166
  label = data.get("label", node).replace("\n", r"\n") + r"\n" + eff_str
162
167
  col_str = color(data["effect"], max_val, palette=node_palette)
163
168
  dot_str += f' "{node}"[label = "{label}" fillcolor="{col_str}"]\n'
164
169
 
165
170
  for from_node, to_node, data in g.edges(data=True):
166
- eff_str = utils.fmt_min_sig(data["effect"], min_sig_figures, percent=in_percent)
171
+ eff_str = utils.fmt_min_sig(
172
+ data["effect"] if abs(data["effect"]) > cutoff else 0,
173
+ min_sig_figures,
174
+ percent=in_percent,
175
+ )
167
176
  col_str = color(data["effect"], max_val, palette=edge_palette)
168
177
  penwidth = color(data["effect"], max_val, palette=pen_width_palette)
169
178
  dot_str += f' "{from_node}" -> "{to_node}" [label="{eff_str}" color="{col_str}" penwidth="{penwidth}"]\n'
causing/model.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+
2
3
  from dataclasses import dataclass, field
3
4
  from typing import Iterable, Callable
4
5
  from functools import cached_property
@@ -8,6 +9,10 @@ import sympy
8
9
  import numpy as np
9
10
 
10
11
 
12
+ class NumericModelError(Exception):
13
+ pass
14
+
15
+
11
16
  @dataclass
12
17
  class Model:
13
18
 
@@ -42,6 +47,7 @@ class Model:
42
47
  self.graph.add_node(var)
43
48
  self.trans_graph = networkx.transitive_closure(self.graph, reflexive=True)
44
49
 
50
+ @np.errstate(all="raise")
45
51
  def compute(
46
52
  self,
47
53
  xdat: np.array,
@@ -77,15 +83,36 @@ class Model:
77
83
  eq_inputs[:, fixed_from_ind] = fixed_vals
78
84
 
79
85
  try:
86
+ # print(f"Comuting variable: {self.yvars[i]}")
87
+ # yhat[i] = np.array(
88
+ # [eq(*eq_in, *parameters.values()) for eq_in in eq_inputs],
89
+ # dtype=np.float64,
90
+ # )
91
+ computed_yvars = []
92
+ for eq_in in eq_inputs:
93
+ try:
94
+ computed_yvars.append(eq(*eq_in, *parameters.values()))
95
+ except FloatingPointError:
96
+ # Floating Point Error for self.yvars[i]
97
+ # Adding 0.0 to overcome this.
98
+ computed_yvars.append(0.0)
99
+
80
100
  yhat[i] = np.array(
81
- [eq(*eq_in, *parameters.values()) for eq_in in eq_inputs],
101
+ computed_yvars,
82
102
  dtype=np.float64,
83
103
  )
84
104
  except Exception as e:
85
- print(
105
+ # for eq_in in eq_inputs:
106
+ # print("--", self.yvars[i])
107
+ # for var, val in zip(
108
+ # self.vars + list(parameters.keys()),
109
+ # list(eq_in) + list(parameters.values()),
110
+ # ):
111
+ # print(var, "=", val)
112
+ # eq(*eq_in, *parameters.values())
113
+ raise NumericModelError(
86
114
  f"Failed to compute model value for yvar {self.yvars[i]}: {e}"
87
- )
88
- raise
115
+ ) from e
89
116
  assert yhat.shape == (self.ndim, tau)
90
117
  return yhat
91
118
 
causing/utils.py CHANGED
@@ -11,7 +11,7 @@ def round_sig(x, sig=2) -> float:
11
11
  """Round x to the given number of significant figures"""
12
12
  if x == 0 or not np.isfinite(x):
13
13
  return x
14
- return round(x, sig - int(floor(log10(abs(x)))) - 1)
14
+ return round(x, sig - int(floor(log10(abs(x)))) + 1)
15
15
 
16
16
 
17
17
  def round_sig_recursive(x, sig=2):
@@ -37,6 +37,11 @@ def round_sig_recursive(x, sig=2):
37
37
 
38
38
  class MatrixEncoder(json.JSONEncoder):
39
39
  def default(self, obj):
40
+ # allow serialization of numpy scalars
41
+ if isinstance(obj, np.integer):
42
+ return int(obj)
43
+ if isinstance(obj, np.floating):
44
+ return float(obj)
40
45
  # avoid importing pytorch for isinstance check
41
46
  if isinstance(obj, np.ndarray) or type(obj).__name__ == "Tensor":
42
47
  return obj.tolist()
@@ -61,11 +66,12 @@ def fmt_min_sig(x, min_sig_figures=3, percent=False, percent_spacer=""):
61
66
  if not math.isfinite(x):
62
67
  return str(x)
63
68
  if x == 0:
64
- return "0"
65
- if percent:
66
- x *= 100
67
- show_dec = max(-math.floor(math.log10(abs(x)) + 1) + min_sig_figures, 0)
68
- num = locale.format_string("%." + str(show_dec) + "f", x, grouping=True)
69
+ num = "0"
70
+ else:
71
+ if percent:
72
+ x *= 100
73
+ show_dec = max(-math.floor(math.log10(abs(x)) + 1) + min_sig_figures, 0)
74
+ num = locale.format_string("%." + str(show_dec) + "f", x, grouping=True)
69
75
  if percent:
70
76
  num += percent_spacer + "%"
71
77
  return num
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: causing
3
- Version: 2.3.0
3
+ Version: 2.4.1
4
4
  Summary: Causing: CAUSal INterpretation using Graphs
5
5
  Home-page: https://github.com/realrate/Causing
6
6
  Author: Dr. Holger Bartel
@@ -11,11 +11,11 @@ Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.9
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
- Requires-Dist: numpy (~=1.23)
15
- Requires-Dist: pandas (~=1.3)
16
- Requires-Dist: scipy (~=1.9)
17
- Requires-Dist: sympy (~=1.5)
18
- Requires-Dist: networkx (~=2.7)
14
+ Requires-Dist: numpy~=1.23
15
+ Requires-Dist: pandas~=1.3
16
+ Requires-Dist: scipy~=1.9
17
+ Requires-Dist: sympy~=1.5
18
+ Requires-Dist: networkx~=2.7
19
19
  Requires-Dist: pre-commit
20
20
 
21
21
  # Causing: CAUSal INterpretation using Graphs
@@ -29,12 +29,12 @@ effects of a given equation system._
29
29
  Get a nice colored graph and immediately understand the causal effects between the variables.
30
30
 
31
31
  **Input:** You simply have to put in a dataset and provide an equation system in form of a
32
- python function. The endogenous variable on the left-hand side are assumed being caused by
32
+ python function. The endogenous variables on the left-hand side are assumed to be caused by
33
33
  the variables on the right-hand side of the equation. Thus, you provide the causal structure
34
34
  in form of a directed acyclic graph (DAG).
35
35
 
36
- **Output:** As an output you will get a colored graph of quantified effects acting between
37
- the model variables. You are able to immediately interpret mediation chains for every
36
+ **Output:** As an output, you will get a colored graph of quantified effects acting between
37
+ the model variables. You can immediately interpret mediation chains for every
38
38
  individual observation - even for highly complex nonlinear systems.
39
39
 
40
40
  Here is a table relating Causing to other approaches:
@@ -42,10 +42,10 @@ Here is a table relating Causing to other approaches:
42
42
  Causing is | Causing is NOT
43
43
  --- | ---
44
44
  ✅ causal model given | ❌ causal search
45
- ✅ DAG directed acyclic graph | ❌ cyclic, undirected or bidirected graph
45
+ ✅ DAG directed acyclic graph | ❌ cyclic, undirected, or bidirected graph
46
46
  ✅ latent variables | ❌ just observed / manifest variables
47
47
  ✅ individual effects | ❌ just average effects
48
- ✅ direct, total and mediation effects | ❌ just total effects
48
+ ✅ direct, total, and mediation effects | ❌ just total effects
49
49
  ✅ structural model | ❌ reduced model
50
50
  ✅ small and big data | ❌ big data requirement
51
51
  ✅ graphical results | ❌ just numerical results
@@ -59,21 +59,21 @@ Causing combines total effects and mediation effects in one single graph that is
59
59
 
60
60
  The total effects of a variable on the final variable are shown in the corresponding nodes of the graph. The total effects are split up over their outgoing edges, yielding the mediation effects shown on the edges. Just education has more than one outgoing edge to be interpreted in this way.
61
61
 
62
- The effects differ from individual to individual. To emphsize this, we talk about individual effects. And the corresponding graph, combining total and mediation effects is called the Imdividual Mediation Effects (IME) graph.
62
+ The effects differ from individual to individual. To emphasize this, we talk about individual effects. And the corresponding graph, combining total and mediation effects is called the Individual Mediation Effects (IME) graph.
63
63
 
64
64
  ## Software
65
65
 
66
- Causing is a free software written in _Python 3_. Graphs are generated using _Graphviz_. See dependencies in [setup.py](setup.py). Causing is available under MIT license. See [LICENSE](LICENSE.md "LICENSE").
66
+ Causing is free software written in _Python 3_. Graphs are generated using _Graphviz_. See dependencies in [setup.py](setup.py). Causing is available under MIT license. See [LICENSE](LICENSE.md "LICENSE").
67
67
 
68
- The software is developed by RealRate, an AI rating agency aiming to re-invent the ratings market by using AI, interpretability and avoiding any conflict of interest. See www.realrate.ai.
68
+ The software is developed by RealRate, an AI rating agency aiming to re-invent the rating market by using AI, interpretability, and avoiding any conflict of interest. See www.realrate.ai.
69
69
 
70
70
  When starting `python -m causing.examples example` after cloning / downloading the Causing repository you will find the results in the _output_ folder. The results are saved in SVG files. The IME files show the individual mediation effects graphs for the respective individual.
71
71
 
72
72
  See `causing/examples` for the code generating some examples.
73
73
 
74
- ## Start your own Model
74
+ ## Start your Model
75
75
 
76
- To start your own model, you have to provide the following information, as done in the example code below:
76
+ To start your model, you have to provide the following information, as done in the example code below:
77
77
 
78
78
  - Define all your model variables as SymPy symbols.
79
79
  - Note that in Sympy some operators are special, e.g. Max() instead of max().
@@ -94,31 +94,31 @@ Y<sub>2</sub> = X<sub>2</sub> + 2 * Y<sub>1</sub><sup>2</sup>
94
94
 
95
95
  Y<sub>3</sub> = Y<sub>1</sub> + Y<sub>2</sub>.
96
96
 
97
- This gives the following graphs. Some notes are in order to understand them:
97
+ This gives the following graphs. Some notes to understand them:
98
98
 
99
- - The data used consist of 200 observations. They are available for the x variables X<sub>1</sub> and X<sub>2</sub> with mean(X<sub>1</sub>) = 3 and mean(X<sub>2</sub>) = 2. Variables Y<sub>1</sub> and Y<sub>2</sub> are assumed to be latent / unobserved. Y<sub>3</sub> is assumed to be manifest / observed. Therefore, 200 observations are available for Y<sub>3</sub>.
99
+ - The data used consists of 200 observations. They are available for the x variables X<sub>1</sub> and X<sub>2</sub> with mean(X<sub>1</sub>) = 3 and mean(X<sub>2</sub>) = 2. Variables Y<sub>1</sub> and Y<sub>2</sub> are assumed to be latent / unobserved. Y<sub>3</sub> is assumed to be manifest / observed. Therefore, 200 observations are available for Y<sub>3</sub>.
100
100
 
101
101
  - To allow for benchmark comparisons, each individual effect is measured with respect to the mean of all observations.
102
102
 
103
103
  - Nodes and edges are colored, showing positive (_green_) and negative (_red_) effects they have on the final variable Y<sub>3</sub>.
104
104
 
105
- - Individual effects are based on the given model. For each individual, however its _own_ exogenous data is put into the given graph function to yield the corresponding endogenous values. The effects are computed at this individual point. Individual effects are shown below just for individual no. 1 out of the 200 observations.
105
+ - Individual effects are based on the given model. For each individual, however, its _own_ exogenous data is put into the given graph function to yield the corresponding endogenous values. The effects are computed at this individual point. Individual effects are shown below just for individual no. 1 out of the 200 observations.
106
106
 
107
- - Total effects are shown below in the nodes and they are split up over the outgoing edges yielding the Mediation effects shown on the edges. Note however, that just outgoining edges sum up to the node value, incoming edges do not. All effects are effects just on the final variable of interest, assumed here to be Y<sub>3</sub>.
107
+ - Total effects are shown below in the nodes and they are split up over the outgoing edges yielding the Mediation effects shown on the edges. Note, however, that just outgoing edges sum up to the node value, incoming edges do not. All effects are effects just on the final variable of interest, assumed here to be Y<sub>3</sub>.
108
108
 
109
109
  ![Individual Mediation Effects (IME)](https://github.com/realrate/Causing/raw/develop/images_readme/IME_1.svg)
110
110
 
111
- As you can see in the right-most graph for the individual mediation effects (IME), there is one green path starting at X<sub>1</sub> passing through Y<sub>1</sub>, Y<sub>2</sub> and finally ending in Y<sub>3</sub>. This means that X<sub>1</sub> is the main cause for Y<sub>3</sub> taking on a value above average with its effect on Y<sub>3</sub> being +29.81. However, this positive effect is slightly reduced by X<sub>2</sub>. In total, accounting for all exogenous and endogenous effects, Y<sub>3</sub> is +27.07 above average. You can understand at one glance why Y<sub>3</sub> is above average for individual no. 1.
111
+ As you can see in the right-most graph for the individual mediation effects (IME), there is one green path starting at X<sub>1</sub> passing through Y<sub>1</sub>, Y<sub>2</sub>, and finally ending in Y<sub>3</sub>. This means that X<sub>1</sub> is the main cause for Y<sub>3</sub> taking on a value above average with its effect on Y<sub>3</sub> being +29.81. However, this positive effect is slightly reduced by X<sub>2</sub>. In total, accounting for all exogenous and endogenous effects, Y<sub>3</sub> is +27.07 above average. You can understand at one glance why Y<sub>3</sub> is above average for individual no. 1.
112
112
 
113
113
  You can find the full source code for this example [here](https://github.com/realrate/Causing/blob/develop/causing/examples/models.py#L16-L45).
114
114
 
115
115
  ## 2. Application to Education and Wages
116
116
 
117
- To dig a bit deeper, here we have a real world example from social sciences. We analyze how the wage earned by young American workers is determined by their educational attainment, family characteristics, and test scores.
117
+ To dig a bit deeper, here we have a real-world example from social sciences. We analyze how the wage earned by young American workers is determined by their educational attainment, family characteristics, and test scores.
118
118
 
119
- This 5 minute introductory video gives a short overview over Causing and includes this real data example: See [Causing Introduction Video](https://youtu.be/GJLsjSZOk2w "Causing_Introduction_Video").
119
+ This 5-minute introductory video gives a short overview of Causing and includes this real data example: See [Causing Introduction Video](https://youtu.be/GJLsjSZOk2w "Causing_Introduction_Video").
120
120
 
121
- See here for a detailed analys of the Education and Wages example: [An Application of Causing: Education and Wages](docs/education.md).
121
+ See here for a detailed analysis of the Education and Wages example: [An Application of Causing: Education and Wages](docs/education.md).
122
122
 
123
123
  ## 3. Application to Insurance Ratings
124
124
 
@@ -128,21 +128,21 @@ The Causing approach and its formulas together with an application are given in:
128
128
  DOI: 10.13140/RG.2.2.31524.83848
129
129
  https://www.researchgate.net/publication/339091133
130
130
 
131
- Note that in this early paper the mediation effects on the final variable of interest are called final effects. Also, while the current Causing version just uses numerically computed effect, that paper uses closed formulas.
131
+ Note that in this early paper the mediation effects on the final variable of interest are called final effects. Also, while the current Causing version just uses numerically computed effects, that paper uses closed formulas.
132
132
 
133
133
  The paper proposes simple linear algebra formulas for the causal analysis of equation systems. The effect of one variable on another is the total derivative. It is extended to endogenous system variables. These total effects are identical to the effects used in graph theory and its do-calculus. Further, mediation effects are defined, decomposing the total effect of one variable on a final variable of interest over all its directly caused variables. This allows for an easy but in-depth causal and mediation analysis.
134
134
 
135
- The equation system provided by the user is represented as a structural neural network (SNN). The network's nodes are represented by the model variables and its edge weights are given by the effects. Unlike classical deep neural networks, we follow a sparse and 'small data' approach. This new methodology is applied to financial strength ratings of insurance companies.
135
+ The equation system provided by the user is represented as a structural neural network (SNN). The network's nodes are represented by the model variables and its edge weights are given by the effects. Unlike classical deep neural networks, we follow a sparse and 'small data' approach. This new methodology is applied to the financial strength ratings of insurance companies.
136
136
 
137
137
  > **Keywords:** total derivative, graphical effect, graph theory, do-Calculus, structural neural network, linear Simultaneous Equations Model (SEM), Structural Causal Model (SCM), insurance rating
138
138
 
139
139
  ## Award
140
140
 
141
- RealRate's AI software _Causing_ is a winner of PyTorch AI Hackathon.
141
+ RealRate's AI software _Causing_ is a winner of the PyTorch AI Hackathon.
142
142
 
143
143
  <img src="https://github.com/realrate/Causing/raw/develop/images_readme/RealRate_AI_Software_Winner.png">
144
144
 
145
- We are exited being a winner of the PyTorch AI Hackathon 2020 in the Responsible AI category. This is quite an honor given that more than 2,500 teams submitted their projects.
145
+ We are excited to be a winner of the PyTorch AI Hackathon 2020 in the Responsible AI category. This is quite an honor given that more than 2,500 teams submitted their projects.
146
146
 
147
147
  [devpost.com/software/realrate-explainable-ai-for-company-ratings](https://devpost.com/software/realrate-explainable-ai-for-company-ratings "devpost.com/software/realrate-explainable-ai-for-company-ratings").
148
148
 
@@ -0,0 +1,14 @@
1
+ causing/__init__.py,sha256=O_9uV9aX3q-c6M3KhY7bQAXncAecwnSfXw7ulGmMvSw,714
2
+ causing/graph.py,sha256=5v3t7dhFtxcIjpeJEOVdKxzSleufmXECSKqlhykMbcE,8637
3
+ causing/model.py,sha256=jgIuuSxoYuel1ZGwl-nj7vVoBsAqXUFAW_nkDld_OkU,8589
4
+ causing/utils.py,sha256=qfiNAb-MxVFeZVan7I4X-q04LVJZ8ST2YdVdvWvnjOE,2461
5
+ tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ tests/test_estimate.py,sha256=xr9qUVzM9XO70agw_J3PE7oy3aiytUs4CMxvsegNZ6w,3120
7
+ tests/utils.py,sha256=OPEuaBQF3_Azu4bW5q-6J5mtzGrVw4KJUWHd8utK4AE,510
8
+ tests/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ tests/examples/models.py,sha256=lr7v4LArOi3MlcKRvjGAJ6pEHVz1IQKbmKctZ02Vcjc,3849
10
+ causing-2.4.1.dist-info/LICENSE.md,sha256=ypzox8OiFHlpmiHOnxpC6PSGuDCNwzn_Q0iPYPJtt2Q,1095
11
+ causing-2.4.1.dist-info/METADATA,sha256=G2gYzFvtJD55pQTfeLdlH13BNY6qrHMLl3LTKw96UJc,10026
12
+ causing-2.4.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
13
+ causing-2.4.1.dist-info/top_level.txt,sha256=AZ4fGg06-ThD38PJjnIg4Yd1x4v_4hgRtPetAcKMmug,14
14
+ causing-2.4.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.37.1)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,14 +0,0 @@
1
- causing/__init__.py,sha256=O_9uV9aX3q-c6M3KhY7bQAXncAecwnSfXw7ulGmMvSw,714
2
- causing/graph.py,sha256=jaGe5m1eFdM4yryAOlKNNYqbRqeUiT-8g9x7PdsK5Ac,8442
3
- causing/model.py,sha256=XiXIIhp6gAdn2h89lPF1YR3QvgTNPtj_0ud5D6UBWQo,7438
4
- causing/utils.py,sha256=be2sjODmuscqAFIajXRqhkT-E8x5PBodBbbog_AeWKM,2250
5
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- tests/test_estimate.py,sha256=xr9qUVzM9XO70agw_J3PE7oy3aiytUs4CMxvsegNZ6w,3120
7
- tests/utils.py,sha256=OPEuaBQF3_Azu4bW5q-6J5mtzGrVw4KJUWHd8utK4AE,510
8
- tests/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- tests/examples/models.py,sha256=lr7v4LArOi3MlcKRvjGAJ6pEHVz1IQKbmKctZ02Vcjc,3849
10
- causing-2.3.0.dist-info/LICENSE.md,sha256=ypzox8OiFHlpmiHOnxpC6PSGuDCNwzn_Q0iPYPJtt2Q,1095
11
- causing-2.3.0.dist-info/METADATA,sha256=7SkUYDSp41ngrC9hXAZX7AT-nOJryvFTTD1gXk4SKbk,10053
12
- causing-2.3.0.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
13
- causing-2.3.0.dist-info/top_level.txt,sha256=AZ4fGg06-ThD38PJjnIg4Yd1x4v_4hgRtPetAcKMmug,14
14
- causing-2.3.0.dist-info/RECORD,,