tigramite-fast 5.2.10.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.
Files changed (38) hide show
  1. tigramite/__init__.py +0 -0
  2. tigramite/causal_effects.py +1525 -0
  3. tigramite/causal_mediation.py +1592 -0
  4. tigramite/data_processing.py +1574 -0
  5. tigramite/graphs.py +1509 -0
  6. tigramite/independence_tests/LBFGS.py +1114 -0
  7. tigramite/independence_tests/__init__.py +0 -0
  8. tigramite/independence_tests/cmiknn.py +661 -0
  9. tigramite/independence_tests/cmiknn_mixed.py +1397 -0
  10. tigramite/independence_tests/cmisymb.py +286 -0
  11. tigramite/independence_tests/gpdc.py +664 -0
  12. tigramite/independence_tests/gpdc_torch.py +820 -0
  13. tigramite/independence_tests/gsquared.py +190 -0
  14. tigramite/independence_tests/independence_tests_base.py +1310 -0
  15. tigramite/independence_tests/oracle_conditional_independence.py +1582 -0
  16. tigramite/independence_tests/pairwise_CI.py +383 -0
  17. tigramite/independence_tests/parcorr.py +369 -0
  18. tigramite/independence_tests/parcorr_mult.py +485 -0
  19. tigramite/independence_tests/parcorr_wls.py +451 -0
  20. tigramite/independence_tests/regressionCI.py +403 -0
  21. tigramite/independence_tests/robust_parcorr.py +403 -0
  22. tigramite/jpcmciplus.py +966 -0
  23. tigramite/lpcmci.py +3649 -0
  24. tigramite/models.py +2257 -0
  25. tigramite/pcmci.py +3935 -0
  26. tigramite/pcmci_base.py +1218 -0
  27. tigramite/plotting.py +4735 -0
  28. tigramite/rpcmci.py +467 -0
  29. tigramite/toymodels/__init__.py +0 -0
  30. tigramite/toymodels/context_model.py +261 -0
  31. tigramite/toymodels/non_additive.py +1231 -0
  32. tigramite/toymodels/structural_causal_processes.py +1201 -0
  33. tigramite/toymodels/surrogate_generator.py +319 -0
  34. tigramite_fast-5.2.10.1.dist-info/METADATA +182 -0
  35. tigramite_fast-5.2.10.1.dist-info/RECORD +38 -0
  36. tigramite_fast-5.2.10.1.dist-info/WHEEL +5 -0
  37. tigramite_fast-5.2.10.1.dist-info/licenses/license.txt +621 -0
  38. tigramite_fast-5.2.10.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,261 @@
1
+ import numpy as np
2
+
3
+ from tigramite.toymodels import structural_causal_processes as toys
4
+
5
+
6
+ def _nb_latent_before(node, observed_context_indices, node_classification):
7
+ return len(
8
+ [el for el in range(node) if not (el in observed_context_indices or node_classification[el] == "system")])
9
+
10
+ def _do_dummy_projection(links, node_classification, observed_context_indices, time_dummy_index, space_dummy_index):
11
+ """
12
+ Helper function to augment the true_parents by remove context-context links and adding dummy
13
+ (i.e. perform dummy projection)
14
+
15
+ links : dictionary
16
+ Ground truth links
17
+ node_classification : dictionary
18
+ Corresponds to ground truth links
19
+ """
20
+
21
+ # remove latent links, shift remaining, add dummy
22
+ augmented_links = {}
23
+ for node in node_classification.keys():
24
+ if node_classification[node] == "system":
25
+ keep_parents = []
26
+ for parent in links[node]:
27
+ if node_classification[parent[0][0]] == "system":
28
+ keep_parents.append(parent)
29
+ elif node_classification[parent[0][0]] == "time_context":
30
+ if parent[0][0] in observed_context_indices:
31
+ keep_parents.append(((parent[0][0] - _nb_latent_before(parent[0][0], observed_context_indices,
32
+ node_classification),
33
+ parent[0][1]), parent[1], parent[2]))
34
+ else:
35
+ keep_parents.append(((time_dummy_index, 0), 1., "dummy"))
36
+ elif node_classification[parent[0][0]] == "space_context":
37
+ if parent[0][0] in observed_context_indices:
38
+ keep_parents.append(((parent[0][0] - _nb_latent_before(parent[0][0], observed_context_indices,
39
+ node_classification), parent[0][1]),
40
+ parent[1], parent[2]))
41
+ else:
42
+ keep_parents.append(((space_dummy_index, 0), 1., "dummy"))
43
+ augmented_links[node] = list(dict.fromkeys(keep_parents))
44
+
45
+ # remove all parents of context nodes
46
+ elif node_classification[node] == "time_context":
47
+ if node in observed_context_indices:
48
+ augmented_links[node - _nb_latent_before(node, observed_context_indices, node_classification)] = []
49
+ elif node_classification[node] == "space_context":
50
+ if node in observed_context_indices:
51
+ augmented_links[node - _nb_latent_before(node, observed_context_indices, node_classification)] = []
52
+
53
+ augmented_links[time_dummy_index] = []
54
+ augmented_links[space_dummy_index] = []
55
+ return augmented_links
56
+
57
+ def _shift_link_entries(links, const):
58
+ """
59
+ Helper Function to shift keys and values of a link dictionary by an integer constant.
60
+ """
61
+ shifted_links = {}
62
+ for key in links.keys():
63
+ shifted_key = key + const
64
+ values = links[key]
65
+ shifted_values = [((item + const, lag), c, f) for ((item, lag), c, f) in values]
66
+ shifted_links[shifted_key] = shifted_values
67
+ return shifted_links
68
+
69
+ def _group_links(links, node_types, node_type):
70
+ return {i: links[i] for i in links.keys() if node_types[i] == node_type}
71
+
72
+
73
+ class ContextModel:
74
+ """Allows to sample from a joint structural causal model over different spatial
75
+ and temporal contexts. Restricts temporal and spatial context nodes to be constant over datasets or
76
+ time, respectively.
77
+
78
+ Parameters
79
+ ----------
80
+ links : dict
81
+ Dictionary of format: {0:[((i, -tau), coeff, func),...], 1:[...],
82
+ ...} for all variables where i must be in [0..N-1] and tau >= 0 with
83
+ number of variables N. coeff must be a float and func a python
84
+ callable of one argument.
85
+ node_classification : dictionary
86
+ Classification of nodes into system, or context nodes.
87
+ Keys of the dictionary are from {0, ..., N-1} where N is the number of nodes.
88
+ Options for the values are "system", "time_context", "space_context". The temporal context variables are
89
+ assumed exogenous to the system variables. They cannot interact with the spatial context variables due
90
+ to the assumption that they are constant across datasets.
91
+ transient_fraction : float
92
+ Added percentage of T used as a transient. In total a realization of length
93
+ (transient_fraction + 1)*T will be generated, but then transient_fraction*T will be
94
+ cut off.
95
+ noises : list of callables or list of arrays, optional (default: None)
96
+ Random distribution function that is called with noises[j](T) for system and time-context nodes, or
97
+ noises[j](M) for space-context nodes where M is the number of datasets. If list of arrays,
98
+ for noises corresponding to time-context and system variables the array needs to be of
99
+ shape ((transient_fraction + 1)*T, ), for space-context variables it needs to be of shape (M, )
100
+ seed : int, optional (default: None)
101
+ Random seed.
102
+
103
+ Attributes
104
+ -------
105
+ links_tc : dict
106
+ Dictionary of format: {0:[((i, -tau), coeff, func),...], 1:[...],
107
+ ...} for all temporal context variables where i must be in [0..N-1] and tau >= 0 with
108
+ number of variables N. coeff must be a float and func a python
109
+ callable of one argument. The temporal context variables are assumed exogenous
110
+ to the system variables. They cannot interact with the spatial context variables due to the assumption
111
+ that they are constant across datasets.
112
+ links_sc : dict
113
+ Dictionary of format: {0:[((i, -tau), coeff, func),...], 1:[...],
114
+ ...} for all spatial context variables where i must be in [0..N-1] and tau >= 0 with
115
+ number of variables N. coeff must be a float and func a python
116
+ callable of one argument. The spatial context variables are assumed exogenous
117
+ to the system variables. They cannot interact with the temporal context variables due to the assumption
118
+ that they are time-independent, i.e. constant across time.
119
+ links_sys : dict
120
+ Dictionary of format: {0:[((i, -tau), coeff, func),...], 1:[...],
121
+ ...} for all system variables where i must be in [0..N-1] and tau >= 0 with
122
+ number of variables N. coeff must be a float and func a python
123
+ callable of one argument.
124
+ transient_fraction : float
125
+ Added percentage of T used as a transient. In total a realization of length
126
+ (transient_fraction + 1)*T will be generated, but then transient_fraction*T will be
127
+ cut off.
128
+ noises : list of callables or list of arrays, optional (default: None)
129
+ Random distribution function that is called with noises[j](T) for system and time-context nodes, or
130
+ noises[j](M) for space-context nodes where M is the number of datasets. If list of arrays,
131
+ for noises corresponding to time-context and system variables the array needs to be of
132
+ shape ((transient_fraction + 1)*T, ), for space-context variables it needs to be of shape (M, )
133
+ seed : int, optional (default: None)
134
+ Random seed.
135
+
136
+ """
137
+
138
+ def __init__(self, links={}, node_classification={}, transient_fraction=0.2, noises=None, seed=None):
139
+ self.links_tc = _group_links(links, node_classification, "time_context")
140
+ self.links_sc = _group_links(links, node_classification, "space_context")
141
+ self.links_sys = _group_links(links, node_classification, "system")
142
+
143
+ self.N = len(self.links_sys.keys())
144
+ self.noises = noises
145
+ self.seed = seed
146
+ self.transient_fraction = transient_fraction
147
+
148
+
149
+
150
+ def _constant_over_space(self, data_tc, M):
151
+ data_tc_list = [data_tc for _ in range(M)]
152
+ return data_tc_list
153
+
154
+ def _constant_over_time(self, data_sc, T, M, shift):
155
+ data_sc_list = [{i: np.repeat(data_sc[m, i-shift], T) for i in self.links_sc.keys()} for m in
156
+ range(M)]
157
+ return data_sc_list
158
+
159
+ def _generate_temporal_context_data(self, links_tc, T, M, seed):
160
+ """
161
+ Helper Function to generate data for the temporal context nodes. It essentially is a
162
+ wrapper around toys.structural_causal_process to generate data that is random across time
163
+ but constant across datasets.
164
+ """
165
+ if self.noises is not None:
166
+ noises_tc = [self.noises[key] for key in links_tc.keys()]
167
+ if np.all([isinstance(el, np.ndarray) for el in noises_tc]):
168
+ noises_tc = np.stack(noises_tc).transpose()
169
+ else:
170
+ noises_tc = None
171
+ shifted_links_tc = _shift_link_entries(links_tc, -self.N)
172
+ data_tc, nonstat_tc = toys.structural_causal_process(shifted_links_tc, T=T, noises=noises_tc,
173
+ transient_fraction=self.transient_fraction,
174
+ seed=seed)
175
+ data_tc = {i: data_tc[:, i - self.N] for i in links_tc.keys()}
176
+
177
+ data_tc_list = self._constant_over_space(data_tc, M)
178
+ return data_tc_list, np.any(nonstat_tc)
179
+
180
+ def _generate_spatial_context_data(self, links_sc, T, M, shift, seed):
181
+ """
182
+ Helper Function to generate data for the spatial context nodes. It essentially is a
183
+ wrapper around toys.structural_causal_process to generate data that is random across datasets
184
+ but constant across time.
185
+ """
186
+ shifted_links_sc = _shift_link_entries(links_sc, -shift)
187
+ if self.noises is not None:
188
+ noises_sc = [self.noises[key] for key in links_sc.keys()]
189
+ if np.all([isinstance(el, np.ndarray) for el in noises_sc]):
190
+ noises_sc = np.stack(noises_sc).transpose()
191
+ else:
192
+ noises_sc = None
193
+
194
+ data_sc, nonstat_sc = toys.structural_causal_process(shifted_links_sc, T=M, noises=noises_sc,
195
+ transient_fraction=0.,
196
+ seed=seed)
197
+
198
+ data_sc_list = self._constant_over_time(data_sc, T, M, shift)
199
+ return data_sc_list, np.any(nonstat_sc)
200
+
201
+ def generate_data(self, M, T):
202
+ """
203
+ Generates M datasets of time series generated from a joint structural causal model over different spatial
204
+ and temporal contexts.
205
+
206
+ Parameters
207
+ ----------
208
+ M : int
209
+ Number of datasets.
210
+ T : int
211
+ Sample size.
212
+
213
+ Returns
214
+ ----------
215
+ data : dictionary with array-like values
216
+ Datasets generated from this process, each dataset has the shape (T, N).
217
+ nonvalid : bool
218
+ Indicates whether data has NaNs or infinities.
219
+ """
220
+
221
+ links = {**self.links_tc, **self.links_sc, **self.links_sys}
222
+
223
+ K_time = len(self.links_tc.keys())
224
+
225
+ data = {}
226
+ nonstationary = []
227
+
228
+ time_seed = [1, self.seed]
229
+ space_seed = [2, self.seed]
230
+ system_seed = [3, self.seed]
231
+
232
+ # first generate data for temporal context nodes
233
+ data_tc_list, nonstat_tc = self._generate_temporal_context_data(self.links_tc, T, M, time_seed)
234
+
235
+ # generate spatial context data (constant in time)
236
+ data_sc_list, nonstat_sc = self._generate_spatial_context_data(self.links_sc,
237
+ T, M,
238
+ K_time + self.N,
239
+ space_seed)
240
+ for m in range(M):
241
+ data_context = dict(data_tc_list[m])
242
+ data_context.update(data_sc_list[m])
243
+
244
+ if self.noises is not None:
245
+ noises_filled = self.noises
246
+ if np.all([isinstance(el, np.ndarray) for el in self.noises]):
247
+ noises_filled = np.copy(self.noises)
248
+ for key in self.links_sc.keys():
249
+ # fill up any space-context noise to have T entries, then convert to numpy array
250
+ noises_filled[key] = np.random.standard_normal(len(self.noises[list(self.links_sys.keys())[0]]))
251
+ noises_filled = np.stack(noises_filled).transpose()
252
+ else:
253
+ noises_filled = None
254
+
255
+ # generate system data that varies over space and time
256
+ data_m, nonstat = toys.structural_causal_process(links, T=T, intervention=data_context,
257
+ transient_fraction=self.transient_fraction,
258
+ seed=system_seed, noises=noises_filled)
259
+ data[m] = data_m
260
+ nonstationary.append(nonstat or nonstat_tc or nonstat_sc)
261
+ return data, np.any(nonstationary)