SearchLibrium 0.0.239__tar.gz → 0.0.240__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.239/src/SearchLibrium.egg-info → searchlibrium-0.0.240}/PKG-INFO +1 -1
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/pyproject.toml +1 -1
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/latent_class.py +42 -16
- searchlibrium-0.0.240/src/SearchLibrium/version.txt +1 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240/src/SearchLibrium.egg-info}/PKG-INFO +1 -1
- searchlibrium-0.0.239/src/SearchLibrium/version.txt +0 -1
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/LICENSE +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/MANIFEST.in +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/README.md +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/setup.cfg +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/BEHier.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/Halton.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/MixedLogit.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/MixedLogitGSE.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/Mode_Activity_Nested.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/RandomP.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/SEARCH_SM_MARIO.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/Two_Level_Nest.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/__init__.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/__main__.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/_choice_model.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/_device.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/abm.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/accessibility.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/banditsa.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/boxcox_functions.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/call_meta.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/constraints_builder.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/data/Swissmetro_final.csv +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/data/TravelMode.csv +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/data/electricity.csv +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/harmony.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/hspbil.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/jax_utils.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/larch_compat.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/larch_models.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/logistic_regression.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/main.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/main_debug.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/mdcev.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/misc.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/mixed_logit.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/mixed_nested.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/mixedrrm.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/multinomial_logit.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/multinomial_nested.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/multinomial_probit.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/numba_engine.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/numba_mxl.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/numba_rrm.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/ordered_logit.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/ordered_logit_mixed.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/predict.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/regularization.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/rrm.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/sample_data.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/sapbil.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/search.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/selection_models.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/setup.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/siman.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/skims.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/sparseea_agds.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/test_lc_de.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/test_mario_searches.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/test_sapbil_vs_banditsa.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/threshold.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/zero_inflated_ordered_probit.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium.egg-info/SOURCES.txt +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium.egg-info/dependency_links.txt +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium.egg-info/entry_points.txt +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium.egg-info/requires.txt +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium.egg-info/top_level.txt +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/tests/test_jax_mask_equivalence.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/tests/test_larch_integration.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/tests/test_lc_smart_init.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/tests/test_per_alternative_random.py +0 -0
- {searchlibrium-0.0.239 → searchlibrium-0.0.240}/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.240
|
|
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.240"
|
|
133
133
|
version_pattern = "MAJOR.MINOR.PATCH"
|
|
134
134
|
commit_message = "[skip ci] Bump version {old_version} -> {new_version}"
|
|
135
135
|
commit = true
|
|
@@ -507,7 +507,7 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
507
507
|
if hasattr(self, cache_key):
|
|
508
508
|
return getattr(self, cache_key)
|
|
509
509
|
|
|
510
|
-
if not self._jax_enabled or len(set(self._Ks)) != 1
|
|
510
|
+
if not self._jax_enabled or len(set(self._Ks)) != 1:
|
|
511
511
|
setattr(self, cache_key, None)
|
|
512
512
|
return None
|
|
513
513
|
|
|
@@ -531,6 +531,13 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
531
531
|
l2 = self.l2_penalty
|
|
532
532
|
l1 = self.l1_penalty
|
|
533
533
|
|
|
534
|
+
# Panel aggregation: the class marginalisation is per decision-maker, so
|
|
535
|
+
# per-task log-choice is segment-summed into M = n_panels person totals.
|
|
536
|
+
panelled = bool(self._panelled)
|
|
537
|
+
M = int(self.n_panels)
|
|
538
|
+
panel_idx_b = self.jnp.asarray(self.panel_idx) if panelled else None
|
|
539
|
+
seg_sum = self.jax.ops.segment_sum
|
|
540
|
+
|
|
534
541
|
def _negloglik_flat(params):
|
|
535
542
|
phi = params[:n_phi]
|
|
536
543
|
beta_flat = params[n_phi:n_phi + C * K]
|
|
@@ -543,11 +550,15 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
543
550
|
denom = jnp.clip(exp_u.sum(axis=2, keepdims=True), 1e-300)
|
|
544
551
|
probs = exp_u / denom
|
|
545
552
|
chosen = jnp.clip((probs * y_b[:, None, :]).sum(axis=2), 1e-300)
|
|
546
|
-
|
|
553
|
+
log_chosen_task = jnp.log(chosen)
|
|
554
|
+
if panelled:
|
|
555
|
+
log_chosen = seg_sum(log_chosen_task, panel_idx_b, num_segments=M)
|
|
556
|
+
else:
|
|
557
|
+
log_chosen = log_chosen_task
|
|
547
558
|
|
|
548
559
|
if has_memb:
|
|
549
560
|
gammas = params[n_phi + C * K:].reshape(C - 1, Km)
|
|
550
|
-
logits = jnp.zeros((
|
|
561
|
+
logits = jnp.zeros((M, C))
|
|
551
562
|
for c in range(C - 1):
|
|
552
563
|
logits = logits.at[:, c].set(X_memb @ gammas[c])
|
|
553
564
|
logits = logits - jnp.max(logits, axis=1, keepdims=True)
|
|
@@ -557,7 +568,7 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
557
568
|
else:
|
|
558
569
|
phi_full = jnp.concatenate([phi, jnp.zeros(1)])
|
|
559
570
|
log_priors_raw = phi_full - self.jax_logsumexp(phi_full)
|
|
560
|
-
log_prior = jnp.broadcast_to(log_priors_raw[None, :], (
|
|
571
|
+
log_prior = jnp.broadcast_to(log_priors_raw[None, :], (M, C))
|
|
561
572
|
|
|
562
573
|
log_joint = log_chosen + log_prior
|
|
563
574
|
log_marg = self.jax_logsumexp(log_joint, axis=1)
|
|
@@ -1595,6 +1606,9 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
1595
1606
|
ll = float(logsumexp(log_joint, axis=1).sum())
|
|
1596
1607
|
ll -= self._regularize_l2_betas(betas)
|
|
1597
1608
|
ll -= self._regularize_l1_betas(betas)
|
|
1609
|
+
if has_gamma:
|
|
1610
|
+
ll -= self._regularize_l2_gammas(gammas)
|
|
1611
|
+
ll -= self._regularize_l1_gammas(gammas)
|
|
1598
1612
|
return ll
|
|
1599
1613
|
|
|
1600
1614
|
def _autograd_hessian(self, params: np.ndarray) -> np.ndarray | None:
|
|
@@ -1612,10 +1626,6 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
1612
1626
|
if len(set(self._Ks)) != 1:
|
|
1613
1627
|
print("[LC] Autograd Hessian requires all classes to share the same variable set.")
|
|
1614
1628
|
return None
|
|
1615
|
-
if self._panelled:
|
|
1616
|
-
# The JIT objective marginalises per task, not per person; use the
|
|
1617
|
-
# panel-aware finite-difference Hessian instead.
|
|
1618
|
-
return None
|
|
1619
1629
|
|
|
1620
1630
|
cache_key = "_cached_autograd_hessian_fn"
|
|
1621
1631
|
if hasattr(self, cache_key):
|
|
@@ -1782,25 +1792,41 @@ class LatentClassMixedLogit(DiscreteChoiceModel):
|
|
|
1782
1792
|
info = -H_num # observed info = -hessian(loglik)
|
|
1783
1793
|
se_method = "numerical-hessian (finite differences)"
|
|
1784
1794
|
|
|
1795
|
+
# When a membership equation is active the class-share logits (phi) do
|
|
1796
|
+
# not enter the likelihood — they are exactly unidentified, which makes
|
|
1797
|
+
# the observed-information matrix exactly singular in those directions
|
|
1798
|
+
# (an artefact, not a genuinely ill-conditioned model). Invert only the
|
|
1799
|
+
# identified block; phi rows/cols are reinstated with zero covariance.
|
|
1800
|
+
P = len(params)
|
|
1801
|
+
if has_gamma and n_phi > 0:
|
|
1802
|
+
keep = np.arange(n_phi, P)
|
|
1803
|
+
else:
|
|
1804
|
+
keep = np.arange(P)
|
|
1805
|
+
info_id = info[np.ix_(keep, keep)]
|
|
1806
|
+
|
|
1785
1807
|
cond_number = np.nan
|
|
1786
|
-
|
|
1808
|
+
cov_id = None
|
|
1787
1809
|
try:
|
|
1788
|
-
eigvals = np.linalg.eigvalsh(
|
|
1810
|
+
eigvals = np.linalg.eigvalsh(info_id)
|
|
1789
1811
|
cond_number = float(eigvals.max() / max(eigvals.min(), 1e-300))
|
|
1790
1812
|
|
|
1791
1813
|
if eigvals.min() < 1e-8 * eigvals.max():
|
|
1792
1814
|
ridge = 1e-6 * eigvals.max()
|
|
1793
|
-
info_reg =
|
|
1794
|
-
|
|
1815
|
+
info_reg = info_id + ridge * np.eye(len(keep))
|
|
1816
|
+
cov_id = np.linalg.inv(info_reg)
|
|
1795
1817
|
se_method = "hessian (ridge-regularised)"
|
|
1796
1818
|
else:
|
|
1797
|
-
|
|
1819
|
+
cov_id = np.linalg.inv(info_id)
|
|
1798
1820
|
except np.linalg.LinAlgError:
|
|
1799
|
-
|
|
1821
|
+
cov_id = np.linalg.pinv(info_id)
|
|
1800
1822
|
se_method = "hessian (pinv fallback)"
|
|
1801
1823
|
|
|
1802
|
-
if
|
|
1803
|
-
|
|
1824
|
+
if cov_id is None:
|
|
1825
|
+
cov_id = np.linalg.pinv(info_id)
|
|
1826
|
+
|
|
1827
|
+
# Re-embed the identified covariance into the full parameter space.
|
|
1828
|
+
cov = np.zeros((P, P))
|
|
1829
|
+
cov[np.ix_(keep, keep)] = cov_id
|
|
1804
1830
|
|
|
1805
1831
|
se = np.sqrt(np.clip(np.diag(cov), 0.0, None))
|
|
1806
1832
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.240
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SearchLibrium
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.240
|
|
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.239
|
|
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
|
|
File without changes
|
|
File without changes
|
{searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/test_sapbil_vs_banditsa.py
RENAMED
|
File without changes
|
|
File without changes
|
{searchlibrium-0.0.239 → searchlibrium-0.0.240}/src/SearchLibrium/zero_inflated_ordered_probit.py
RENAMED
|
File without changes
|
|
File without changes
|
{searchlibrium-0.0.239 → searchlibrium-0.0.240}/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
|