SearchLibrium 0.0.236__tar.gz → 0.0.239__tar.gz
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.
- {searchlibrium-0.0.236/src/SearchLibrium.egg-info → searchlibrium-0.0.239}/PKG-INFO +1 -1
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/pyproject.toml +1 -1
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/MixedLogit.py +105 -1
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/_choice_model.py +53 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/ordered_logit.py +45 -3
- searchlibrium-0.0.239/src/SearchLibrium/version.txt +1 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239/src/SearchLibrium.egg-info}/PKG-INFO +1 -1
- searchlibrium-0.0.236/src/SearchLibrium/version.txt +0 -1
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/LICENSE +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/MANIFEST.in +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/README.md +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/setup.cfg +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/BEHier.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/Halton.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/MixedLogitGSE.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/Mode_Activity_Nested.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/RandomP.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/SEARCH_SM_MARIO.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/Two_Level_Nest.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/__init__.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/__main__.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/_device.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/abm.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/accessibility.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/banditsa.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/boxcox_functions.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/call_meta.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/constraints_builder.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/data/Swissmetro_final.csv +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/data/TravelMode.csv +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/data/electricity.csv +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/harmony.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/hspbil.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/jax_utils.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/larch_compat.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/larch_models.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/latent_class.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/logistic_regression.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/main.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/main_debug.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/mdcev.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/misc.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/mixed_logit.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/mixed_nested.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/mixedrrm.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/multinomial_logit.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/multinomial_nested.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/multinomial_probit.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/numba_engine.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/numba_mxl.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/numba_rrm.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/ordered_logit_mixed.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/predict.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/regularization.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/rrm.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/sample_data.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/sapbil.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/search.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/selection_models.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/setup.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/siman.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/skims.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/sparseea_agds.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/test_lc_de.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/test_mario_searches.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/test_sapbil_vs_banditsa.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/threshold.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/zero_inflated_ordered_probit.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium.egg-info/SOURCES.txt +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium.egg-info/dependency_links.txt +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium.egg-info/entry_points.txt +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium.egg-info/requires.txt +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium.egg-info/top_level.txt +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/tests/test_jax_mask_equivalence.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/tests/test_larch_integration.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/tests/test_lc_smart_init.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/tests/test_per_alternative_random.py +0 -0
- {searchlibrium-0.0.236 → searchlibrium-0.0.239}/tests/test_zero_inflated_ordered_probit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SearchLibrium
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.239
|
|
4
4
|
Summary: Automated specification search for discrete choice models (logit, mixed logit, nested logit, RRM and more) using metaheuristic optimisation
|
|
5
5
|
Author: Mario Fernando Taco Morales, Alexander Paz, Prithvi Beeramole, Robert Burdett
|
|
6
6
|
Author-email: Zeke Ahern <z.ahern@qut.edu.au>
|
|
@@ -129,7 +129,7 @@ Documentation = "https://pypi.org/project/SearchLibrium/"
|
|
|
129
129
|
realpython = "SearchLibrium.__main__:main"
|
|
130
130
|
|
|
131
131
|
[tool.bumpver]
|
|
132
|
-
current_version = "0.0.
|
|
132
|
+
current_version = "0.0.239"
|
|
133
133
|
version_pattern = "MAJOR.MINOR.PATCH"
|
|
134
134
|
commit_message = "[skip ci] Bump version {old_version} -> {new_version}"
|
|
135
135
|
commit = true
|
|
@@ -171,7 +171,7 @@ class MixedLogit(DiscreteChoiceModel):
|
|
|
171
171
|
save_fitted_params=True, mnl_init=True,
|
|
172
172
|
de_init=False, de_popsize=4, de_maxiter=3, de_tol=0.5,
|
|
173
173
|
de_polish=False, l1_penalty=0.0, reg_penalty=0.001, sd_penalty=0.0,
|
|
174
|
-
engine=None):
|
|
174
|
+
engine=None, asc_share_init=True):
|
|
175
175
|
# {
|
|
176
176
|
self.fit_intercept = fit_intercept
|
|
177
177
|
# L2 ridge regularisation strength (default ON). Keeps the Hessian
|
|
@@ -182,6 +182,11 @@ class MixedLogit(DiscreteChoiceModel):
|
|
|
182
182
|
# Extra L2 penalty applied specifically to the random-coefficient standard
|
|
183
183
|
# deviations (Br_w). Shrinks weakly-identified / runaway SDs toward zero.
|
|
184
184
|
self.sd_penalty = float(sd_penalty)
|
|
185
|
+
# Seed alternative-specific constants from observed shares
|
|
186
|
+
# (alpha_j = log(s_j / s_base); detected as exact alternative
|
|
187
|
+
# dummies, no naming convention needed). Disable with
|
|
188
|
+
# asc_share_init=False.
|
|
189
|
+
self.asc_share_init = bool(asc_share_init)
|
|
185
190
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
186
191
|
# RECAST AS NUMPY NDARRAY
|
|
187
192
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
@@ -613,11 +618,98 @@ class MixedLogit(DiscreteChoiceModel):
|
|
|
613
618
|
''' Function. Fit Mixed Logit model '''
|
|
614
619
|
''' ---------------------------------------------------------- '''
|
|
615
620
|
|
|
621
|
+
def _seed_asc_from_shares(self, betas):
|
|
622
|
+
"""Overwrite ASC fixed/random-mean starts with log-share ratios.
|
|
623
|
+
|
|
624
|
+
For alternative dummies the plain-logit MLE is closed form:
|
|
625
|
+
``alpha_j = log(s_j / s_base)`` (the BLP-contraction starting
|
|
626
|
+
point; exact for intercepts-only, excellent with covariates).
|
|
627
|
+
ASC columns are detected from the design (columns exactly
|
|
628
|
+
indicating one alternative), so no naming convention is needed.
|
|
629
|
+
Positions without positive shares on both sides keep their
|
|
630
|
+
incoming value. Returns ``(betas, n_seeded)``; never raises.
|
|
631
|
+
"""
|
|
632
|
+
try:
|
|
633
|
+
import numpy as _np
|
|
634
|
+
betas = _np.asarray(betas, dtype=float).copy()
|
|
635
|
+
Kf, Kr = int(self.Kf), int(self.Kr)
|
|
636
|
+
if Kf + Kr <= 0:
|
|
637
|
+
return betas, 0
|
|
638
|
+
X = _np.asarray(self.X, dtype=float)
|
|
639
|
+
if X.ndim != 4:
|
|
640
|
+
return betas, 0
|
|
641
|
+
N, P, J = X.shape[0], X.shape[1], X.shape[2]
|
|
642
|
+
if J < 2:
|
|
643
|
+
return betas, 0
|
|
644
|
+
# observed shares over valid choice situations
|
|
645
|
+
y = _np.asarray(self.y)
|
|
646
|
+
if y.ndim == 4:
|
|
647
|
+
y = y[..., 0]
|
|
648
|
+
if y.ndim == 3 and y.shape == (N, P, J):
|
|
649
|
+
_flat = y.reshape(N * P, J)
|
|
650
|
+
cnt = _flat.sum(axis=0)
|
|
651
|
+
den = float((_flat.sum(axis=1) > 0).sum())
|
|
652
|
+
elif y.ndim <= 2:
|
|
653
|
+
idx = y.astype(int).ravel()
|
|
654
|
+
idx = idx[(idx >= 0) & (idx < J)]
|
|
655
|
+
if idx.size == 0:
|
|
656
|
+
return betas, 0
|
|
657
|
+
cnt = _np.bincount(idx, minlength=J).astype(float)
|
|
658
|
+
den = float(idx.size)
|
|
659
|
+
else:
|
|
660
|
+
return betas, 0
|
|
661
|
+
if not den > 0:
|
|
662
|
+
return betas, 0
|
|
663
|
+
shares = cnt / den
|
|
664
|
+
try:
|
|
665
|
+
base = int(self.base_alt)
|
|
666
|
+
except Exception:
|
|
667
|
+
base = 0
|
|
668
|
+
if not (0 <= base < J) or not shares[base] > 0:
|
|
669
|
+
return betas, 0
|
|
670
|
+
try:
|
|
671
|
+
fx = _np.where(_np.asarray(self.fxidx, dtype=bool))[0]
|
|
672
|
+
rv = _np.where(_np.asarray(self.rvidx, dtype=bool))[0]
|
|
673
|
+
except Exception:
|
|
674
|
+
return betas, 0
|
|
675
|
+
if len(fx) < Kf or len(rv) < Kr:
|
|
676
|
+
return betas, 0
|
|
677
|
+
alt1 = _np.arange(J)
|
|
678
|
+
n_seed = 0
|
|
679
|
+
for f in range(Kf): # fixed means <-> design column fx[f]
|
|
680
|
+
col = X[:, :, :, int(fx[f])]
|
|
681
|
+
for j in range(J):
|
|
682
|
+
if bool((col == (alt1 == j)).all()):
|
|
683
|
+
if shares[j] > 0:
|
|
684
|
+
betas[f] = float(_np.log(shares[j] / shares[base]))
|
|
685
|
+
n_seed += 1
|
|
686
|
+
break
|
|
687
|
+
for k in range(Kr): # random means <-> design column rv[k]
|
|
688
|
+
col = X[:, :, :, int(rv[k])]
|
|
689
|
+
for j in range(J):
|
|
690
|
+
if bool((col == (alt1 == j)).all()):
|
|
691
|
+
if shares[j] > 0:
|
|
692
|
+
betas[Kf + k] = float(
|
|
693
|
+
_np.log(shares[j] / shares[base]))
|
|
694
|
+
n_seed += 1
|
|
695
|
+
break
|
|
696
|
+
return betas, n_seed
|
|
697
|
+
except Exception:
|
|
698
|
+
try:
|
|
699
|
+
import numpy as _np
|
|
700
|
+
return _np.asarray(betas, dtype=float), 0
|
|
701
|
+
except Exception:
|
|
702
|
+
return betas, 0
|
|
703
|
+
|
|
616
704
|
def fit(self):
|
|
617
705
|
# {
|
|
618
706
|
# Generate draws:
|
|
619
707
|
draws, drawstrans = self.generate_draws(self.N, self.n_draws, self.halton)
|
|
620
708
|
self.draws, self.drawstrans = draws, drawstrans # Record generated values
|
|
709
|
+
# Explicit caller-supplied starts are respected verbatim (no ASC
|
|
710
|
+
# share seeding); the MNL block below may still overwrite
|
|
711
|
+
# self.init_coeff when it runs.
|
|
712
|
+
_explicit_init = self.init_coeff is not None
|
|
621
713
|
|
|
622
714
|
# Optional numba engine (first-class; the T4 minimise_func patch is
|
|
623
715
|
# the equivalent for older installs). Resolved here so the JAX fast
|
|
@@ -692,6 +784,18 @@ class MixedLogit(DiscreteChoiceModel):
|
|
|
692
784
|
self.init_coeff = None
|
|
693
785
|
betas = np.repeat(0.1, n_coeff)
|
|
694
786
|
|
|
787
|
+
# Log-share seeding for alternative-specific constants detected as
|
|
788
|
+
# exact alternative dummies: alpha_j = log(s_j / s_base). Cheap
|
|
789
|
+
# closed form; skipped for explicitly user-supplied starts.
|
|
790
|
+
if getattr(self, 'asc_share_init', True) and not _explicit_init:
|
|
791
|
+
try:
|
|
792
|
+
betas, _n_asc = self._seed_asc_from_shares(betas)
|
|
793
|
+
if _n_asc and not _SL_QUIET:
|
|
794
|
+
print(f"[MXL] ASC share-init seeded {_n_asc} constants "
|
|
795
|
+
f"(log-share ratios).")
|
|
796
|
+
except Exception:
|
|
797
|
+
pass
|
|
798
|
+
|
|
695
799
|
positive_bound = (0, infinity)
|
|
696
800
|
any_bound = (-infinity, infinity)
|
|
697
801
|
lmda_bound = (-5, 1)
|
|
@@ -495,6 +495,59 @@ class DiscreteChoiceModel(ABC):
|
|
|
495
495
|
|
|
496
496
|
# }
|
|
497
497
|
|
|
498
|
+
def cov_params(self, robust=False):
|
|
499
|
+
"""Parameter covariance matrix aligned to ``coeff_names``.
|
|
500
|
+
|
|
501
|
+
Mediation/path analysis (e.g. SEM-style direct + indirect effects)
|
|
502
|
+
needs off-diagonal covariances, not just standard errors. Returns a
|
|
503
|
+
``pandas.DataFrame`` (p x p) with ``coeff_names`` as index/columns.
|
|
504
|
+
|
|
505
|
+
Parameters
|
|
506
|
+
----------
|
|
507
|
+
robust : bool, default False
|
|
508
|
+
If True, prefer the sandwich ``robust_varcov`` when present and
|
|
509
|
+
shape-consistent; otherwise fall back to the inverse Hessian.
|
|
510
|
+
|
|
511
|
+
Notes
|
|
512
|
+
-----
|
|
513
|
+
Uses ``self.robust_varcov`` (if ``robust=True``) else ``self.Hinv``.
|
|
514
|
+
Both are stored by ``fit()``/``post_process()``. Raises ValueError
|
|
515
|
+
when no p x p finite covariance is available (e.g. the model was fit
|
|
516
|
+
with ``return_hess=False``).
|
|
517
|
+
"""
|
|
518
|
+
import numpy as _np
|
|
519
|
+
import pandas as _pd
|
|
520
|
+
est = _np.asarray(getattr(self, 'coeff_est', []), dtype=float).ravel()
|
|
521
|
+
p = int(est.size)
|
|
522
|
+
if p == 0:
|
|
523
|
+
raise ValueError("cov_params: model has no estimated coefficients "
|
|
524
|
+
"(was fit() called?)")
|
|
525
|
+
_V = None
|
|
526
|
+
if robust:
|
|
527
|
+
_V = getattr(self, 'robust_varcov', None)
|
|
528
|
+
if _V is None:
|
|
529
|
+
_V = getattr(self, 'Hinv', None)
|
|
530
|
+
if _V is None:
|
|
531
|
+
raise ValueError("cov_params: no covariance available "
|
|
532
|
+
"(missing Hinv/robust_varcov — refit with "
|
|
533
|
+
"return_hess=True)")
|
|
534
|
+
try:
|
|
535
|
+
_V = _np.asarray(_V, dtype=float)
|
|
536
|
+
except Exception as _e:
|
|
537
|
+
raise ValueError(f"cov_params: stored covariance not array-like "
|
|
538
|
+
f"({_e!r})")
|
|
539
|
+
if _V.shape != (p, p) or not _np.all(_np.isfinite(_V)):
|
|
540
|
+
raise ValueError(f"cov_params: stored covariance has shape "
|
|
541
|
+
f"{tuple(_V.shape)}, expected ({p}, {p}) with "
|
|
542
|
+
f"finite entries")
|
|
543
|
+
_raw_names = getattr(self, 'coeff_names', None)
|
|
544
|
+
_names = (list(_raw_names) if _raw_names is not None else [])
|
|
545
|
+
if len(_names) != p:
|
|
546
|
+
_names = [str(_n) for _n in _names[:p]]
|
|
547
|
+
_names += [f"param_{i}" for i in range(len(_names), p)]
|
|
548
|
+
_V = (_V + _V.T) / 2.0 # enforce symmetry against float noise
|
|
549
|
+
return _pd.DataFrame(_V, index=_names, columns=_names)
|
|
550
|
+
|
|
498
551
|
def num_of_exceeding_pvalues(self, pvalues, threshold):
|
|
499
552
|
"""
|
|
500
553
|
:param pvalues: array of pvalues
|
|
@@ -212,7 +212,7 @@ class OrderedLogit():
|
|
|
212
212
|
self.J = kwargs.get('J') # Number of ordinal categories => categories = {0, 1, ..., J-1}
|
|
213
213
|
|
|
214
214
|
|
|
215
|
-
self.fit_intercept = kwargs.get('fit_intercept')
|
|
215
|
+
self.fit_intercept = kwargs.get('fit_intercept', False)
|
|
216
216
|
self.nparams = self.K + self.J -1 +int(self.fit_intercept) # i.e., intercept + self.K + self.J - 1
|
|
217
217
|
|
|
218
218
|
self.params = kwargs.get('start')
|
|
@@ -244,7 +244,7 @@ class OrderedLogit():
|
|
|
244
244
|
else:
|
|
245
245
|
self.distr = distr
|
|
246
246
|
|
|
247
|
-
self.fit_intercept = kwargs.get('fit_intercept') # Add intercept
|
|
247
|
+
self.fit_intercept = kwargs.get('fit_intercept', False) # Add intercept
|
|
248
248
|
self.define_labels()
|
|
249
249
|
# }
|
|
250
250
|
|
|
@@ -282,7 +282,10 @@ class OrderedLogit():
|
|
|
282
282
|
# {
|
|
283
283
|
#y_latent = X.dot(beta[1:]) # Compute dot product, i.e., X.beta
|
|
284
284
|
if(self.fit_intercept):
|
|
285
|
-
|
|
285
|
+
# params layout is [intercept, K slopes, ...]: broadcast the
|
|
286
|
+
# intercept across cases (a bare beta[0] scalar here silently
|
|
287
|
+
# dropped every slope and broke all downstream shapes).
|
|
288
|
+
y_latent = beta[0] + X.dot(beta[1:1 + self.K])
|
|
286
289
|
else:
|
|
287
290
|
y_latent=X.dot(beta)
|
|
288
291
|
return y_latent
|
|
@@ -559,6 +562,12 @@ class OrderedLogit():
|
|
|
559
562
|
# {
|
|
560
563
|
hessian = self.get_hessian(tol)
|
|
561
564
|
inverse = self.np.linalg.pinv(hessian) # Conventional approach
|
|
565
|
+
# Keep the full covariance for path/mediation analysis (delta-method
|
|
566
|
+
# SEs of indirect effects need off-diagonal terms, not just stderr).
|
|
567
|
+
try:
|
|
568
|
+
self.varcov = np.asarray(inverse, dtype=float)
|
|
569
|
+
except Exception:
|
|
570
|
+
self.varcov = None
|
|
562
571
|
diag = self.np.diagonal(inverse)
|
|
563
572
|
# jax arrays (self.np when _jax=True) don't support boolean-mask
|
|
564
573
|
# in-place assignment; clip() returns a new array either way.
|
|
@@ -573,6 +582,39 @@ class OrderedLogit():
|
|
|
573
582
|
self.stderr = self.np.sqrt(diag_copy)
|
|
574
583
|
# }
|
|
575
584
|
|
|
585
|
+
def cov_params(self, robust=False):
|
|
586
|
+
"""Parameter covariance matrix aligned to ``labels``.
|
|
587
|
+
|
|
588
|
+
Mirrors ``DiscreteChoiceModel.cov_params`` (see _choice_model.py) so
|
|
589
|
+
mediation/path analysis can use off-diagonal terms. Ordered logit
|
|
590
|
+
has no sandwich variant, so ``robust`` is accepted and ignored.
|
|
591
|
+
"""
|
|
592
|
+
import pandas as _pd
|
|
593
|
+
_est = np.asarray(getattr(self, 'params', []), dtype=float).ravel()
|
|
594
|
+
_p = int(_est.size)
|
|
595
|
+
if _p == 0:
|
|
596
|
+
raise ValueError("cov_params: model has no estimated parameters "
|
|
597
|
+
"(was fit() called?)")
|
|
598
|
+
_V = getattr(self, 'varcov', None)
|
|
599
|
+
if _V is None:
|
|
600
|
+
raise ValueError("cov_params: no covariance available "
|
|
601
|
+
"(missing varcov — refit so compute_stderr runs)")
|
|
602
|
+
try:
|
|
603
|
+
_V = np.asarray(_V, dtype=float)
|
|
604
|
+
except Exception as _e:
|
|
605
|
+
raise ValueError(f"cov_params: stored covariance not array-like "
|
|
606
|
+
f"({_e!r})")
|
|
607
|
+
if _V.shape != (_p, _p) or not np.all(np.isfinite(_V)):
|
|
608
|
+
raise ValueError(f"cov_params: stored covariance has shape "
|
|
609
|
+
f"{tuple(_V.shape)}, expected ({_p}, {_p}) with "
|
|
610
|
+
f"finite entries")
|
|
611
|
+
_names = list(getattr(self, 'labels', []) or [])
|
|
612
|
+
if len(_names) != _p:
|
|
613
|
+
_names = [str(_n) for _n in _names[:_p]]
|
|
614
|
+
_names += [f"param_{i}" for i in range(len(_names), _p)]
|
|
615
|
+
_V = (_V + _V.T) / 2.0
|
|
616
|
+
return _pd.DataFrame(_V, index=_names, columns=_names)
|
|
617
|
+
|
|
576
618
|
''' ---------------------------------------------------------- '''
|
|
577
619
|
''' Function. '''
|
|
578
620
|
''' ---------------------------------------------------------- '''
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.239
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SearchLibrium
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.239
|
|
4
4
|
Summary: Automated specification search for discrete choice models (logit, mixed logit, nested logit, RRM and more) using metaheuristic optimisation
|
|
5
5
|
Author: Mario Fernando Taco Morales, Alexander Paz, Prithvi Beeramole, Robert Burdett
|
|
6
6
|
Author-email: Zeke Ahern <z.ahern@qut.edu.au>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.0.236
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/test_sapbil_vs_banditsa.py
RENAMED
|
File without changes
|
|
File without changes
|
{searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium/zero_inflated_ordered_probit.py
RENAMED
|
File without changes
|
|
File without changes
|
{searchlibrium-0.0.236 → searchlibrium-0.0.239}/src/SearchLibrium.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|