SearchLibrium 0.0.112__tar.gz → 0.0.113__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.
Files changed (51) hide show
  1. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/PKG-INFO +1 -1
  2. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/pyproject.toml +1 -1
  3. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/multinomial_logit.py +80 -2
  4. searchlibrium-0.0.113/src/SearchLibrium/version.txt +1 -0
  5. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium.egg-info/PKG-INFO +1 -1
  6. searchlibrium-0.0.112/src/SearchLibrium/version.txt +0 -1
  7. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/README.md +0 -0
  8. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/setup.cfg +0 -0
  9. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/Halton.py +0 -0
  10. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/MixedLogit.py +0 -0
  11. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/Mode_Activity_Nested.py +0 -0
  12. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/RandomP.py +0 -0
  13. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/SEARCH_SM_MARIO.py +0 -0
  14. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/Two_Level_Nest.py +0 -0
  15. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/__init__.py +0 -0
  16. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/__main__.py +0 -0
  17. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/_choice_model.py +0 -0
  18. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/_device.py +0 -0
  19. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/banditsa.py +0 -0
  20. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/bhhh/minimize.py +0 -0
  21. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/boxcox_functions.py +0 -0
  22. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/call_meta.py +0 -0
  23. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/constraints_builder.py +0 -0
  24. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/harmony.py +0 -0
  25. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/latent_class.py +0 -0
  26. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/main.py +0 -0
  27. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/main_debug.py +0 -0
  28. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/mdcev.py +0 -0
  29. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/misc.py +0 -0
  30. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/mixed_logit.py +0 -0
  31. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/mixed_nested.py +0 -0
  32. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/mixedrrm.py +0 -0
  33. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/multinomial_nested.py +0 -0
  34. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/multinomial_probit.py +0 -0
  35. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/ordered_logit.py +0 -0
  36. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/ordered_logit_mixed.py +0 -0
  37. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/rrm.py +0 -0
  38. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/sapbil.py +0 -0
  39. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/search.py +0 -0
  40. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/selection_models.py +0 -0
  41. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/setup.py +0 -0
  42. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/siman.py +0 -0
  43. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/test_lc_de.py +0 -0
  44. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/test_mario_searches.py +0 -0
  45. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/test_sapbil_vs_banditsa.py +0 -0
  46. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium/threshold.py +0 -0
  47. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium.egg-info/SOURCES.txt +0 -0
  48. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium.egg-info/dependency_links.txt +0 -0
  49. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium.egg-info/entry_points.txt +0 -0
  50. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium.egg-info/requires.txt +0 -0
  51. {searchlibrium-0.0.112 → searchlibrium-0.0.113}/src/SearchLibrium.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SearchLibrium
3
- Version: 0.0.112
3
+ Version: 0.0.113
4
4
  Summary: A Python package for econometric models driven by search
5
5
  Author: Alexander Paz Prithvi Beeramole, Robert Burdett
6
6
  Author-email: Zeke Ahern <z.ahern@qut.edu.au>
@@ -60,7 +60,7 @@ Homepage = "https://github.com/zahern/HypothesisX"
60
60
  realpython = "SearchLibrium.__main__:main"
61
61
 
62
62
  [tool.bumpver]
63
- current_version = "0.0.112"
63
+ current_version = "0.0.113"
64
64
  version_pattern = "MAJOR.MINOR.PATCH"
65
65
  commit_message = "[skip ci] Bump version {old_version} -> {new_version}"
66
66
  commit = true
@@ -246,10 +246,12 @@ class MultinomialLogit(DiscreteChoiceModel):
246
246
  transformation="boxcox", ids=None, weights=None, avail=None,
247
247
  base_alt=None, fit_intercept=False, init_coeff=None, maxiter=2000,
248
248
  ftol=1e-6, gtol=1e-6, return_grad=True, return_hess=True,
249
- method="bfgs", scipy_optimisation=True):
249
+ method="bfgs", scipy_optimisation=True, l2_penalty=0.0):
250
250
  # {
251
251
 
252
-
252
+ self.l2_penalty = float(l2_penalty)
253
+ if self.l2_penalty > 0:
254
+ self.reassign_penalty(self.l2_penalty * 0.5)
253
255
  self.fit_intercept = fit_intercept
254
256
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
255
257
  # RECAST AS NUMPY NDARRAY
@@ -342,6 +344,78 @@ class MultinomialLogit(DiscreteChoiceModel):
342
344
 
343
345
  # }
344
346
 
347
+ def wide_setup(self, X_wide, y_chosen, varnames, n_alts,
348
+ ids=None, empirical_init=False, **setup_kw):
349
+ """
350
+ Setup accepting wide-format data (one row per case, features shared
351
+ across alternatives) instead of the standard long format.
352
+
353
+ Parameters
354
+ ----------
355
+ X_wide : ndarray (N, F)
356
+ Feature matrix - one row per case. All features are treated as
357
+ alternative-INVARIANT (isvars).
358
+ y_chosen : ndarray (N,) int
359
+ Chosen alternative index per case in [0, n_alts-1].
360
+ varnames : list[str]
361
+ Feature names matching X_wide columns.
362
+ n_alts : int
363
+ Number of alternatives (K).
364
+ ids : ndarray (N,) int, optional
365
+ Case identifiers. Defaults to np.arange(N).
366
+ empirical_init : bool
367
+ If True, initialise betas from empirical log-shares rather than
368
+ zeros - better warm-start for imbalanced alternatives.
369
+ **setup_kw
370
+ Forwarded to self.setup().
371
+ """
372
+ N = len(y_chosen)
373
+ K = int(n_alts)
374
+ if ids is None:
375
+ ids = np.arange(N, dtype=np.int32)
376
+ else:
377
+ ids = np.asarray(ids, dtype=np.int32)
378
+
379
+ rows = []
380
+ for alt in range(K):
381
+ chunk = np.zeros((N, X_wide.shape[1] + 2))
382
+ chunk[:, :X_wide.shape[1]] = X_wide
383
+ chunk[:, -2] = float(alt)
384
+ chunk[:, -1] = (y_chosen == alt).astype(float)
385
+ rows.append(chunk)
386
+ long = np.vstack(rows)
387
+ ids_long = np.tile(ids, K)
388
+
389
+ sort_idx = np.lexsort((long[:, -2].astype(np.int32), ids_long))
390
+ X_long = long[sort_idx, :-2].astype(float)
391
+ y_long = long[sort_idx, -1].astype(float)
392
+ ids_sorted = ids_long[sort_idx]
393
+ alts = np.arange(K, dtype=np.int32)
394
+ full_varnames = list(varnames)
395
+
396
+ if empirical_init and 'init_coeff' not in setup_kw:
397
+ counts = np.bincount(y_chosen.astype(int), minlength=K).astype(float)
398
+ counts = np.maximum(counts, 1.0)
399
+ log_shares = np.log(counts / counts.sum())
400
+ init_intercepts = log_shares[1:] - log_shares[0]
401
+ init = np.zeros((K - 1) * len(full_varnames))
402
+ for k in range(K - 1):
403
+ init[k * len(full_varnames)] = init_intercepts[k]
404
+ setup_kw['init_coeff'] = init
405
+
406
+ setup_kw.pop('empirical_init', None)
407
+
408
+ self.setup(
409
+ X=X_long, y=y_long,
410
+ varnames=full_varnames,
411
+ alts=alts,
412
+ isvars=full_varnames,
413
+ ids=ids_sorted,
414
+ base_alt=0,
415
+ **setup_kw,
416
+ )
417
+ return self
418
+
345
419
 
346
420
  def predict_setup(self, X_new, varnames, est_coeff, avail_new=None, isvars = None, ids = None, transvars = None, alts =None, y = None, J = None, base_alt=None, fit_intercept=True):
347
421
  """
@@ -552,6 +626,8 @@ class MultinomialLogit(DiscreteChoiceModel):
552
626
  loglik = loglik * weights[:, 0] # doesn't matter which column
553
627
  loglik = np.sum(loglik) # Sum up the elements
554
628
  if not self.return_grad:
629
+ if self.l2_penalty > 0:
630
+ loglik = loglik - 0.5 * self.l2_penalty * np.dot(betas, betas)
555
631
  return (-loglik, )
556
632
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
557
633
  # Individual contribution to the gradient
@@ -597,6 +673,8 @@ class MultinomialLogit(DiscreteChoiceModel):
597
673
 
598
674
  self.Hinv = self.function_hessian(grad) # Conditionally compute Hinv based upon return_hess flag
599
675
  grad = np.sum(grad, axis=0) # Compute grad_[i] = sum(j, grad[i][j])
676
+ if self.l2_penalty > 0 and self.return_grad:
677
+ grad = grad - self.l2_penalty * betas
600
678
  self.gtol_res = np.linalg.norm(grad, ord=np.inf) # Compute the norm of "grad"
601
679
 
602
680
  penalty = self.regularize_loglik(betas)
@@ -0,0 +1 @@
1
+ 0.0.113
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SearchLibrium
3
- Version: 0.0.112
3
+ Version: 0.0.113
4
4
  Summary: A Python package for econometric models driven by search
5
5
  Author: Alexander Paz Prithvi Beeramole, Robert Burdett
6
6
  Author-email: Zeke Ahern <z.ahern@qut.edu.au>
@@ -1 +0,0 @@
1
- 0.0.112