canbiplotme 0.3.0__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.
- canbiplotme/__init__.py +34 -0
- canbiplotme/data.py +304 -0
- canbiplotme/datasets/__init__.py +56 -0
- canbiplotme/datasets/gcb_trade.npz +0 -0
- canbiplotme/datasets/gcb_trade_a21.npz +0 -0
- canbiplotme/datasets/sim_me.npz +0 -0
- canbiplotme/datasets/sim_trade.csv +2521 -0
- canbiplotme/dynamic.py +105 -0
- canbiplotme/inference.py +281 -0
- canbiplotme/meta.py +118 -0
- canbiplotme/plot.py +48 -0
- canbiplotme/regions.py +94 -0
- canbiplotme/reml.py +124 -0
- canbiplotme/rng.py +100 -0
- canbiplotme/simulation.py +77 -0
- canbiplotme/stage1.py +189 -0
- canbiplotme/stage2.py +336 -0
- canbiplotme-0.3.0.dist-info/METADATA +107 -0
- canbiplotme-0.3.0.dist-info/RECORD +22 -0
- canbiplotme-0.3.0.dist-info/WHEEL +5 -0
- canbiplotme-0.3.0.dist-info/licenses/LICENSE +674 -0
- canbiplotme-0.3.0.dist-info/top_level.txt +1 -0
canbiplotme/__init__.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""canbiplotme: canonical biplot for grouped estimates measured with error.
|
|
2
|
+
|
|
3
|
+
Python port of the R package ``gcbiplot`` (Gravity Canonical Biplot;
|
|
4
|
+
formerly ``canbiplotME``), Freire-Cadme (2026). The ``gcb*`` names are aliases
|
|
5
|
+
of the ``cbme*`` ones and match the R functions.
|
|
6
|
+
"""
|
|
7
|
+
from .data import (MEData, me_data, deviation_matrix, replicate_array, select_components, subset_individuals,
|
|
8
|
+
error_correlation)
|
|
9
|
+
from .stage2 import CBMEFit, cbme
|
|
10
|
+
from .inference import simulate_coefs, cbme_test, boot_pvalue, cbme_influence, procrustes_align, holm, cbme_permutation_test
|
|
11
|
+
from .regions import cbme_regions, choose_region
|
|
12
|
+
from .simulation import cbme_simulate_tests, cbme_coverage
|
|
13
|
+
from .stage1 import (gravity_by_individual, pairs_bootstrap, support_counts, identify_d6, as_me_data,
|
|
14
|
+
refit_on_pairs)
|
|
15
|
+
from .dynamic import gravity_dynamic, dynamic_test, cbme_trajectory
|
|
16
|
+
from .reml import cbme_reml
|
|
17
|
+
from .meta import mvmeta
|
|
18
|
+
from .datasets import load_sim_me, load_sim_trade, load_gcb_trade, load_gcb_trade_a21
|
|
19
|
+
from .rng import RRNG
|
|
20
|
+
|
|
21
|
+
# names of the R package gcbiplot
|
|
22
|
+
gcb_data = me_data
|
|
23
|
+
gcb = cbme
|
|
24
|
+
gcb_test = cbme_test
|
|
25
|
+
gcb_influence = cbme_influence
|
|
26
|
+
gcb_regions = cbme_regions
|
|
27
|
+
|
|
28
|
+
__version__ = "0.3.0"
|
|
29
|
+
__all__ = ["MEData", "me_data", "deviation_matrix", "CBMEFit", "cbme", "simulate_coefs", "cbme_test",
|
|
30
|
+
"cbme_influence", "procrustes_align", "holm", "cbme_permutation_test", "cbme_regions", "choose_region",
|
|
31
|
+
"cbme_simulate_tests", "cbme_coverage", "gravity_by_individual", "pairs_bootstrap",
|
|
32
|
+
"support_counts", "identify_d6", "as_me_data", "refit_on_pairs", "gravity_dynamic",
|
|
33
|
+
"dynamic_test", "cbme_trajectory", "cbme_reml", "mvmeta", "load_sim_me", "load_sim_trade", "load_gcb_trade", "load_gcb_trade_a21", "RRNG", "boot_pvalue", "replicate_array",
|
|
34
|
+
"select_components", "subset_individuals", "error_correlation", "gcb_data", "gcb", "gcb_test", "gcb_influence", "gcb_regions"]
|
canbiplotme/data.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"""Input data: grouped estimates measured with error (port of ``me_data``)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MEData:
|
|
9
|
+
"""Grouped estimates measured with error.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
beta : array-like (N, K)
|
|
14
|
+
Estimated coefficients; ``NaN`` marks a component that is not
|
|
15
|
+
identified for that individual (decision D3).
|
|
16
|
+
V : array-like (N, K, K) or list of (K, K), optional
|
|
17
|
+
Measurement-error covariance of each individual. Derived from the
|
|
18
|
+
replicates when omitted.
|
|
19
|
+
group : array-like (N,)
|
|
20
|
+
Group of each individual.
|
|
21
|
+
replicates : dict, optional
|
|
22
|
+
``{group: array (R, n_g, K)}`` bootstrap replicates of the individuals of
|
|
23
|
+
each group (in the order in which they appear in ``beta``). They give
|
|
24
|
+
the joint error covariance of the group.
|
|
25
|
+
Omega : dict, optional
|
|
26
|
+
``{group: array (n_g K, n_g K)}`` joint error covariance, ordered
|
|
27
|
+
individual-major. Ignored when ``replicates`` or ``D`` is given.
|
|
28
|
+
D : dict, optional
|
|
29
|
+
``{group: array (R, n_g K)}`` matrices of replicate deviations (already
|
|
30
|
+
built); alternative to ``replicates``.
|
|
31
|
+
id : sequence of str, optional
|
|
32
|
+
Labels of the individuals.
|
|
33
|
+
components : sequence of str, optional
|
|
34
|
+
Names of the components.
|
|
35
|
+
levels : sequence, optional
|
|
36
|
+
Order of the groups (default: categorical order or sorted unique values).
|
|
37
|
+
error_blocks : array-like (N,), optional
|
|
38
|
+
Blocks of individuals whose errors are correlated, when they are not
|
|
39
|
+
the groups (e.g. one block when the first stage uses fixed effects
|
|
40
|
+
common to all individuals). ``replicates``, ``D`` and ``Omega`` are then
|
|
41
|
+
keyed by block, and pairwise comparisons include the covariance between
|
|
42
|
+
the means of groups of the same block.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, beta, V=None, group=None, replicates=None, Omega=None, D=None,
|
|
46
|
+
id=None, components=None, levels=None, error_blocks=None):
|
|
47
|
+
if isinstance(beta, pd.DataFrame):
|
|
48
|
+
if components is None:
|
|
49
|
+
components = list(beta.columns)
|
|
50
|
+
if id is None:
|
|
51
|
+
id = [str(i) for i in beta.index]
|
|
52
|
+
beta = beta.to_numpy()
|
|
53
|
+
beta = np.array(beta, dtype=float)
|
|
54
|
+
if beta.ndim == 1:
|
|
55
|
+
beta = beta[:, None]
|
|
56
|
+
N, K = beta.shape
|
|
57
|
+
self.components = list(components) if components is not None else [f"z{k + 1}" for k in range(K)]
|
|
58
|
+
self.id = list(id) if id is not None else [f"i{i + 1}" for i in range(N)]
|
|
59
|
+
if group is None:
|
|
60
|
+
raise ValueError("`group` is required.")
|
|
61
|
+
if levels is not None:
|
|
62
|
+
levs = [str(v) for v in levels]
|
|
63
|
+
elif isinstance(group, (pd.Categorical, pd.Series)) and isinstance(getattr(group, "dtype", None), pd.CategoricalDtype):
|
|
64
|
+
cat = pd.Categorical(group).remove_unused_categories()
|
|
65
|
+
levs = [str(v) for v in cat.categories]
|
|
66
|
+
else:
|
|
67
|
+
levs = sorted({str(v) for v in np.asarray(group, dtype=object)})
|
|
68
|
+
self.levels = levs
|
|
69
|
+
self.group = np.array([str(v) for v in np.asarray(group, dtype=object)], dtype=object)
|
|
70
|
+
if not set(self.group) <= set(levs):
|
|
71
|
+
raise ValueError("Some groups are not in `levels`.")
|
|
72
|
+
if len(self.group) != N:
|
|
73
|
+
raise ValueError("`group` must have one element per row of `beta`.")
|
|
74
|
+
self.N, self.K, self.G = N, K, len(self.levels)
|
|
75
|
+
self.block = None
|
|
76
|
+
if error_blocks is not None:
|
|
77
|
+
self.block = np.array([str(v) for v in np.asarray(error_blocks, dtype=object)], dtype=object)
|
|
78
|
+
if len(self.block) != N:
|
|
79
|
+
raise ValueError("`error_blocks` must have one element per row of `beta`.")
|
|
80
|
+
for lev in self.levels:
|
|
81
|
+
if len(set(self.block[self.group == lev])) > 1:
|
|
82
|
+
raise ValueError("Each group must lie in a single error block.")
|
|
83
|
+
self.D = None
|
|
84
|
+
self.Omega = None
|
|
85
|
+
if replicates is not None:
|
|
86
|
+
self.D = {}
|
|
87
|
+
for lev in self.block_levels:
|
|
88
|
+
r = np.asarray(replicates[lev], dtype=float)
|
|
89
|
+
idx = np.where(self.block_of == lev)[0]
|
|
90
|
+
if r.ndim != 3 or r.shape[1] != len(idx) or r.shape[2] != K:
|
|
91
|
+
raise ValueError(f"replicates[{lev!r}] must be an array (R, n_g, K).")
|
|
92
|
+
self.D[lev] = deviation_matrix(r, beta[idx])
|
|
93
|
+
elif D is not None:
|
|
94
|
+
self.D = {lev: np.asarray(D[lev], dtype=float) for lev in self.block_levels}
|
|
95
|
+
elif Omega is not None:
|
|
96
|
+
self.Omega = {lev: np.asarray(Omega[lev], dtype=float) for lev in self.block_levels}
|
|
97
|
+
if V is None:
|
|
98
|
+
if self.D is not None:
|
|
99
|
+
V = _V_from_blocks(lambda lev: self.D[lev].T @ self.D[lev] / (self.D[lev].shape[0] - 1), self)
|
|
100
|
+
elif self.Omega is not None:
|
|
101
|
+
V = _V_from_blocks(lambda lev: self.Omega[lev], self)
|
|
102
|
+
else:
|
|
103
|
+
raise ValueError("Provide `V`, `replicates`, `D` or `Omega`.")
|
|
104
|
+
V = np.array(V, dtype=float)
|
|
105
|
+
if V.shape != (N, K, K):
|
|
106
|
+
raise ValueError("`V` must have shape (N, K, K).")
|
|
107
|
+
self.V = V
|
|
108
|
+
vd = np.einsum("ikk->ik", V)
|
|
109
|
+
ok = np.isfinite(beta) & np.isfinite(vd) & (vd > 0)
|
|
110
|
+
beta = beta.copy()
|
|
111
|
+
beta[~ok] = np.nan
|
|
112
|
+
self.beta = beta
|
|
113
|
+
if np.any(pd.Series(self.group).value_counts() < 2):
|
|
114
|
+
import warnings
|
|
115
|
+
warnings.warn("Some groups have fewer than two individuals.")
|
|
116
|
+
|
|
117
|
+
# ------------------------------------------------------------------
|
|
118
|
+
@property
|
|
119
|
+
def has_joint(self) -> bool:
|
|
120
|
+
return self.D is not None or self.Omega is not None
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def block_of(self) -> np.ndarray:
|
|
124
|
+
"""Error block of each individual (the group unless ``error_blocks`` was given)."""
|
|
125
|
+
return self.group if self.block is None else self.block
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def block_levels(self) -> list:
|
|
129
|
+
if self.block is None:
|
|
130
|
+
return list(self.levels)
|
|
131
|
+
return sorted(set(self.block.tolist())) # as R's factor(): sorted levels
|
|
132
|
+
|
|
133
|
+
def block_omega(self, b):
|
|
134
|
+
"""Joint error covariance of an error block."""
|
|
135
|
+
if self.D is not None:
|
|
136
|
+
D = self.D[b]
|
|
137
|
+
return D.T @ D / (D.shape[0] - 1)
|
|
138
|
+
return self.Omega[b]
|
|
139
|
+
|
|
140
|
+
def group_omega(self, lev):
|
|
141
|
+
"""Joint error covariance of a group (n_g K x n_g K)."""
|
|
142
|
+
if self.block is not None and self.has_joint:
|
|
143
|
+
b = self.block[self.group == lev][0]
|
|
144
|
+
inb = np.where(self.block == b)[0]
|
|
145
|
+
pos = np.searchsorted(inb, np.where(self.group == lev)[0])
|
|
146
|
+
cols = (pos[:, None] * self.K + np.arange(self.K)[None, :]).ravel()
|
|
147
|
+
return self.block_omega(b)[np.ix_(cols, cols)]
|
|
148
|
+
if self.D is not None:
|
|
149
|
+
D = self.D[lev]
|
|
150
|
+
return D.T @ D / (D.shape[0] - 1)
|
|
151
|
+
if self.Omega is not None:
|
|
152
|
+
return self.Omega[lev]
|
|
153
|
+
idx = np.where(self.group == lev)[0]
|
|
154
|
+
K = self.K
|
|
155
|
+
O = np.zeros((len(idx) * K, len(idx) * K))
|
|
156
|
+
for j, i in enumerate(idx):
|
|
157
|
+
v = np.nan_to_num(self.V[i], nan=0.0, posinf=0.0, neginf=0.0)
|
|
158
|
+
O[j * K:(j + 1) * K, j * K:(j + 1) * K] = v
|
|
159
|
+
return O
|
|
160
|
+
|
|
161
|
+
def identified_table(self) -> pd.DataFrame:
|
|
162
|
+
rows = []
|
|
163
|
+
for lev in self.levels:
|
|
164
|
+
b = self.beta[self.group == lev]
|
|
165
|
+
rows.append([b.shape[0]] + list(np.isfinite(b).sum(axis=0)))
|
|
166
|
+
return pd.DataFrame(rows, index=self.levels, columns=["n"] + self.components)
|
|
167
|
+
|
|
168
|
+
def __repr__(self) -> str:
|
|
169
|
+
err = ("joint (bootstrap replicates)" if self.D is not None else
|
|
170
|
+
"joint (Omega)" if self.Omega is not None else "independent")
|
|
171
|
+
return (f"<MEData> {self.N} individuals, {self.K} components, {self.G} groups\n"
|
|
172
|
+
f"Identified components per group:\n{self.identified_table()}\n"
|
|
173
|
+
f"Error correlation within groups: {err}")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def me_data(*args, **kwargs) -> MEData:
|
|
177
|
+
"""Functional alias of :class:`MEData` (same name as in R)."""
|
|
178
|
+
return MEData(*args, **kwargs)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def deviation_matrix(r: np.ndarray, beta_g: np.ndarray) -> np.ndarray:
|
|
182
|
+
"""Deviation matrix D_g (R x n_g K), individual-major columns.
|
|
183
|
+
|
|
184
|
+
Failed replicates (every coefficient missing) are dropped and R is the
|
|
185
|
+
number of valid replicates, as in the thesis (``omega_regimen``). Missing
|
|
186
|
+
coefficients of a replicate are set to zero after centring and the column
|
|
187
|
+
is rescaled by sqrt(R / R_valid), which keeps its variance and makes
|
|
188
|
+
D'D/(R-1) positive semidefinite.
|
|
189
|
+
"""
|
|
190
|
+
r = np.asarray(r, float)
|
|
191
|
+
r = r[np.isfinite(r).reshape(r.shape[0], -1).any(axis=1)]
|
|
192
|
+
R, n, K = r.shape
|
|
193
|
+
D = np.zeros((R, n * K))
|
|
194
|
+
for i in range(n):
|
|
195
|
+
for k in range(K):
|
|
196
|
+
x = r[:, i, k]
|
|
197
|
+
ok = np.isfinite(x)
|
|
198
|
+
if not np.isfinite(beta_g[i, k]) or not ok.any():
|
|
199
|
+
continue
|
|
200
|
+
d = x - x[ok].mean()
|
|
201
|
+
d[~ok] = 0.0
|
|
202
|
+
D[:, i * K + k] = d * np.sqrt(R / ok.sum())
|
|
203
|
+
return D
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def replicate_array(reps, id, components, name=lambda i, k: f"{i}_{k}") -> np.ndarray:
|
|
207
|
+
"""Arrange replicate coefficient vectors (dicts or pandas Series keyed by
|
|
208
|
+
coefficient name; ``None`` = failed replicate) into an array (R, n_g, K)."""
|
|
209
|
+
reps = [r for r in reps if r is not None]
|
|
210
|
+
out = np.full((len(reps), len(id), len(components)), np.nan)
|
|
211
|
+
for j, r in enumerate(reps):
|
|
212
|
+
for a, i in enumerate(id):
|
|
213
|
+
for b, k in enumerate(components):
|
|
214
|
+
v = r.get(name(i, k), np.nan) if hasattr(r, "get") else np.nan
|
|
215
|
+
out[j, a, b] = np.nan if v is None else float(v)
|
|
216
|
+
return out
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def select_components(x: "MEData", components) -> "MEData":
|
|
220
|
+
"""Keep some components (with their covariance blocks and replicate
|
|
221
|
+
deviations) and drop individuals left without identified components."""
|
|
222
|
+
import copy
|
|
223
|
+
j = [x.components.index(c) if isinstance(c, str) else int(c) for c in components]
|
|
224
|
+
K = x.K
|
|
225
|
+
out = copy.copy(x)
|
|
226
|
+
out.__dict__ = dict(x.__dict__)
|
|
227
|
+
out.beta = x.beta[:, j]
|
|
228
|
+
out.V = x.V[:, j][:, :, j]
|
|
229
|
+
out.components = [x.components[k] for k in j]
|
|
230
|
+
out.K = len(j)
|
|
231
|
+
|
|
232
|
+
def cols(n):
|
|
233
|
+
return np.array([i * K + k for i in range(n) for k in j], dtype=int)
|
|
234
|
+
if x.D is not None:
|
|
235
|
+
out.D = {lev: D[:, cols(D.shape[1] // K)] for lev, D in x.D.items()}
|
|
236
|
+
if x.Omega is not None:
|
|
237
|
+
out.Omega = {lev: O[np.ix_(cols(O.shape[1] // K), cols(O.shape[1] // K))] for lev, O in x.Omega.items()}
|
|
238
|
+
keep = np.where(np.isfinite(out.beta).any(axis=1))[0]
|
|
239
|
+
if len(keep) < x.N:
|
|
240
|
+
out = subset_individuals(out, keep)
|
|
241
|
+
return out
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def subset_individuals(x: "MEData", keep) -> "MEData":
|
|
245
|
+
"""Keep some individuals (indices), with the matching replicate columns."""
|
|
246
|
+
import copy
|
|
247
|
+
keep = np.sort(np.asarray(keep, int))
|
|
248
|
+
out = copy.copy(x)
|
|
249
|
+
out.__dict__ = dict(x.__dict__)
|
|
250
|
+
K = x.K
|
|
251
|
+
blk = x.block_of
|
|
252
|
+
def cols(lev):
|
|
253
|
+
idx = np.where(blk == lev)[0]
|
|
254
|
+
pos = [p for p, i in enumerate(idx) if i in set(keep)]
|
|
255
|
+
return np.array([p * K + k for p in pos for k in range(K)], dtype=int)
|
|
256
|
+
if x.D is not None:
|
|
257
|
+
out.D = {lev: x.D[lev][:, cols(lev)] for lev in x.block_levels}
|
|
258
|
+
if x.Omega is not None:
|
|
259
|
+
out.Omega = {lev: x.Omega[lev][np.ix_(cols(lev), cols(lev))] for lev in x.block_levels}
|
|
260
|
+
if x.block is not None:
|
|
261
|
+
out.block = x.block[keep]
|
|
262
|
+
out.beta = x.beta[keep]; out.V = x.V[keep]; out.group = x.group[keep]
|
|
263
|
+
out.id = [x.id[i] for i in keep]; out.N = len(keep)
|
|
264
|
+
out.levels = [l for l in x.levels if np.any(out.group == l)]; out.G = len(out.levels)
|
|
265
|
+
if out.D is not None:
|
|
266
|
+
out.D = {l: out.D[l] for l in out.block_levels}
|
|
267
|
+
if out.Omega is not None:
|
|
268
|
+
out.Omega = {l: out.Omega[l] for l in out.block_levels}
|
|
269
|
+
return out
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _V_from_blocks(omega_of, x: MEData) -> np.ndarray:
|
|
273
|
+
V = np.full((x.N, x.K, x.K), np.nan)
|
|
274
|
+
for lev in x.block_levels:
|
|
275
|
+
Om = omega_of(lev)
|
|
276
|
+
idx = np.where(x.block_of == lev)[0]
|
|
277
|
+
for j, i in enumerate(idx):
|
|
278
|
+
V[i] = Om[j * x.K:(j + 1) * x.K, j * x.K:(j + 1) * x.K]
|
|
279
|
+
return V
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def error_correlation(x: MEData) -> pd.DataFrame:
|
|
283
|
+
"""Mean correlation of the errors and design effect of the simple mean, by
|
|
284
|
+
group and component (cells with at least two identified individuals)."""
|
|
285
|
+
if not x.has_joint:
|
|
286
|
+
raise ValueError("`x` has no joint error covariance.")
|
|
287
|
+
K = x.K
|
|
288
|
+
rows = []
|
|
289
|
+
for lev in x.levels:
|
|
290
|
+
O = x.group_omega(lev)
|
|
291
|
+
idx = np.where(x.group == lev)[0]
|
|
292
|
+
for k in range(K):
|
|
293
|
+
j = np.where(np.isfinite(x.beta[idx, k]))[0]
|
|
294
|
+
m = len(j)
|
|
295
|
+
if m < 2:
|
|
296
|
+
continue
|
|
297
|
+
r = j * K + k
|
|
298
|
+
Ok = O[np.ix_(r, r)]
|
|
299
|
+
sd = np.sqrt(np.diag(Ok))
|
|
300
|
+
C = Ok / np.outer(sd, sd)
|
|
301
|
+
rows.append({"group": lev, "component": x.components[k], "m": m,
|
|
302
|
+
"rho": float(C[np.triu_indices(m, 1)].mean()),
|
|
303
|
+
"deff": float((Ok.sum() / m ** 2) / (np.mean(np.diag(Ok)) / m))})
|
|
304
|
+
return pd.DataFrame(rows)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Example datasets (simulated)."""
|
|
2
|
+
from importlib import resources
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def load_sim_me():
|
|
9
|
+
"""Simulated second-stage data: 46 individuals, 4 components, 4 groups,
|
|
10
|
+
structurally missing components and 99 bootstrap-like replicates per group
|
|
11
|
+
(same data as ``data(sim_me)`` in the R package)."""
|
|
12
|
+
from ..data import MEData
|
|
13
|
+
with resources.files(__package__).joinpath("sim_me.npz").open("rb") as f:
|
|
14
|
+
z = np.load(f, allow_pickle=False)
|
|
15
|
+
levels = sorted(set(z["group"].tolist()))
|
|
16
|
+
D = {g: z[f"D_{g}"] for g in levels}
|
|
17
|
+
return MEData(z["beta"], z["V"], z["group"].tolist(), D=D, id=z["id"].tolist(),
|
|
18
|
+
components=z["components"].tolist())
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def load_sim_trade() -> pd.DataFrame:
|
|
22
|
+
"""Small simulated gravity panel (18 origins in 3 regimes, 36 destinations, 4 years)."""
|
|
23
|
+
with resources.files(__package__).joinpath("sim_trade.csv").open("r") as f:
|
|
24
|
+
return pd.read_csv(f)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def load_gcb_trade():
|
|
28
|
+
"""Second-stage data of the thesis (same as ``data(gcb_trade)`` in R).
|
|
29
|
+
|
|
30
|
+
Gravity coefficients of 115 exporters in six trade regimes (CEPII Gravity
|
|
31
|
+
V202211 and BACI flows, 2010-2020): log distance, common official language,
|
|
32
|
+
colonial link, common religion and WTO trade agreement; bootstrap error
|
|
33
|
+
covariances, rule D6 already applied (non-identified components are
|
|
34
|
+
``NaN``), and the deviation matrices of the 199 pairs-bootstrap replicates
|
|
35
|
+
of each regime, which give the joint error covariance within regimes.
|
|
36
|
+
"""
|
|
37
|
+
from ..data import MEData
|
|
38
|
+
with resources.files(__package__).joinpath("gcb_trade.npz").open("rb") as f:
|
|
39
|
+
z = np.load(f, allow_pickle=False)
|
|
40
|
+
levels = z["levels"].tolist()
|
|
41
|
+
D = {g: z[f"D_{g}"] for g in levels}
|
|
42
|
+
return MEData(z["beta"], z["V"], z["group"].tolist(), D=D, id=z["id"].tolist(),
|
|
43
|
+
components=z["components"].tolist(), levels=levels)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def load_gcb_trade_a21():
|
|
47
|
+
"""Analysis 21 of the thesis (same as ``data(gcb_trade_a21)`` in R): first
|
|
48
|
+
stage with importer-year fixed effects common to the 115 exporters, so the
|
|
49
|
+
errors are correlated across regimes (one error block with the deviation
|
|
50
|
+
matrix of the 199 pairs-bootstrap replicates of the whole sample)."""
|
|
51
|
+
from ..data import MEData
|
|
52
|
+
with resources.files(__package__).joinpath("gcb_trade_a21.npz").open("rb") as f:
|
|
53
|
+
z = np.load(f, allow_pickle=False)
|
|
54
|
+
return MEData(z["beta"], z["V"], z["group"].tolist(), D={"all": z["D_all"]}, id=z["id"].tolist(),
|
|
55
|
+
components=z["components"].tolist(), levels=z["levels"].tolist(),
|
|
56
|
+
error_blocks=z["block"].tolist())
|
|
Binary file
|
|
Binary file
|
|
Binary file
|