stmmlib 0.2.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.
Files changed (47) hide show
  1. stmmlib/__init__.py +30 -0
  2. stmmlib/_backend.py +153 -0
  3. stmmlib/_utils.py +175 -0
  4. stmmlib/beta/__init__.py +17 -0
  5. stmmlib/beta/config.py +108 -0
  6. stmmlib/beta/criteria.py +247 -0
  7. stmmlib/beta/design.py +222 -0
  8. stmmlib/beta/diagnose.py +168 -0
  9. stmmlib/beta/diagnostics.py +94 -0
  10. stmmlib/beta/fit.py +598 -0
  11. stmmlib/beta/gpu_solvers.py +169 -0
  12. stmmlib/beta/inference.py +403 -0
  13. stmmlib/beta/lrt_fixed.py +551 -0
  14. stmmlib/beta/moran_panel.py +733 -0
  15. stmmlib/beta/plot_data.py +252 -0
  16. stmmlib/beta/precision.py +98 -0
  17. stmmlib/beta/report.py +373 -0
  18. stmmlib/beta/result.py +696 -0
  19. stmmlib/beta/simulation.py +343 -0
  20. stmmlib/beta/solvers.py +2021 -0
  21. stmmlib/beta/structure.py +56 -0
  22. stmmlib/diagnostics_suite.py +663 -0
  23. stmmlib/gaussian/__init__.py +1 -0
  24. stmmlib/gaussian/blup.py +252 -0
  25. stmmlib/gaussian/covariance.py +599 -0
  26. stmmlib/gaussian/design.py +312 -0
  27. stmmlib/gaussian/diagnostics.py +308 -0
  28. stmmlib/gaussian/gls.py +285 -0
  29. stmmlib/gaussian/hessian.py +197 -0
  30. stmmlib/gaussian/lrt_fixed.py +289 -0
  31. stmmlib/gaussian/models.py +528 -0
  32. stmmlib/gaussian/optimization.py +361 -0
  33. stmmlib/gaussian/simulation.py +186 -0
  34. stmmlib/gaussian/summary.py +277 -0
  35. stmmlib/gaussian/transforms.py +419 -0
  36. stmmlib/gaussian/variance_decomp.py +191 -0
  37. stmmlib/lrt.py +74 -0
  38. stmmlib/output_format.py +148 -0
  39. stmmlib/output_format_beta.py +299 -0
  40. stmmlib/output_format_normal.py +118 -0
  41. stmmlib/registry.py +326 -0
  42. stmmlib/stmm.py +265 -0
  43. stmmlib-0.2.0.dist-info/METADATA +215 -0
  44. stmmlib-0.2.0.dist-info/RECORD +47 -0
  45. stmmlib-0.2.0.dist-info/WHEEL +5 -0
  46. stmmlib-0.2.0.dist-info/licenses/LICENSE +21 -0
  47. stmmlib-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,94 @@
1
+ """Beta model diagnostics: residuals, ACF, permutation tests, visual diagnostics."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+
7
+ import numpy as np
8
+ from scipy.stats import norm
9
+
10
+ if TYPE_CHECKING:
11
+ from stmmlib._backend import Backend
12
+
13
+
14
+ def compute_beta_marginal_resid(result) -> dict:
15
+ """Compute marginal residuals: y_hat - mu_hat from X @ beta."""
16
+ beta = result.beta
17
+ design = result.design
18
+ if not design or "Z" not in design:
19
+ raise ValueError("Result missing design info.")
20
+ from stmmlib.beta.design import stmm_beta_make_design
21
+ # shortcut: design tidak pernah menyimpan X; matrix design ada di _opt
22
+ X = design.get("X") or result._opt.get("X")
23
+ if X is None:
24
+ n = len(result._opt.get("y", []))
25
+ X = np.ones((n, 1), dtype=np.float64)
26
+ eta = X @ beta
27
+ mu = 1.0 / (1.0 + np.exp(-eta))
28
+ mu = np.clip(mu, 1e-15, 1.0 - 1e-15)
29
+ y = result._opt.get("y", None)
30
+ if y is None:
31
+ raise ValueError("Response not found in result.")
32
+ resid = y - mu
33
+ return {"mu": mu, "resid_marginal": resid}
34
+
35
+
36
+ def compute_beta_cond_resid(result) -> dict:
37
+ """Compute conditional residuals using fitted mu."""
38
+ from scipy.special import digamma
39
+ y = result._opt.get("y")
40
+ if y is None:
41
+ raise ValueError("Response not found.")
42
+ mu = result._opt.get("mu_hat", None)
43
+ if mu is None:
44
+ from scipy.special import digamma
45
+ beta = result.beta
46
+ X = result._opt.get("X")
47
+ eta = X @ beta
48
+ mu = 1.0 / (1.0 + np.exp(-eta))
49
+ mu = np.clip(mu, 1e-15, 1.0 - 1e-15)
50
+ phi = result.phi
51
+ a = mu * phi
52
+ b = (1.0 - mu) * phi
53
+ denom = digamma(a) + digamma(b)
54
+ raw_resid = (y - mu) / np.sqrt((a * b) / ((a + b) ** 2 * (a + b + 1)))
55
+ return {"mu": mu, "resid_cond": raw_resid}
56
+
57
+
58
+ def compute_beta_random_resid(result) -> dict:
59
+ """Randomized quantile residuals (Dunn-Smyth 1996).
60
+
61
+ For a CONTINUOUS response (beta) the randomization interval collapses:
62
+ r_i = Phi^-1(F_beta(y_i; mu_i, phi)). No jitter is needed (the earlier
63
+ implementation mistakenly used the beta DENSITY in place of the CDF,
64
+ which produced spuriously extreme tails). Probabilities are clipped to
65
+ [1e-12, 1-1e-12] to keep ndtri finite when y sits at a fitted boundary.
66
+ """
67
+ y = result._opt.get("y")
68
+ if y is None:
69
+ raise ValueError("Response not found.")
70
+ mu = result._opt.get("mu_hat", None)
71
+ if mu is None:
72
+ beta = result.beta
73
+ X = result._opt.get("X")
74
+ eta = X @ beta
75
+ mu = 1.0 / (1.0 + np.exp(-eta))
76
+ mu = np.clip(mu, 1e-15, 1.0 - 1e-15)
77
+ phi = result.phi
78
+ from scipy.stats import beta as _beta_dist
79
+ u = _beta_dist.cdf(y, mu * phi, (1.0 - mu) * phi)
80
+ u = np.clip(u, 1e-12, 1.0 - 1e-12)
81
+ resid = norm.ppf(u)
82
+ return {"mu": mu, "resid_random": resid}
83
+
84
+
85
+ def acf(x, nlags=10):
86
+ """Simple autocorrelation function."""
87
+ n = len(x)
88
+ x = x - np.mean(x)
89
+ var = np.var(x)
90
+ if var == 0:
91
+ return np.zeros(nlags + 1)
92
+ return np.array([np.mean(x[:n - k] * x[k:]) / var for k in range(nlags + 1)])
93
+
94
+