SearchLibrium 0.0.83__tar.gz → 0.0.84__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.83 → searchlibrium-0.0.84}/PKG-INFO +1 -1
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/pyproject.toml +1 -1
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/__init__.py +15 -7
- searchlibrium-0.0.84/src/SearchLibrium/selection_models.py +268 -0
- searchlibrium-0.0.84/src/SearchLibrium/version.txt +1 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/PKG-INFO +1 -1
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/SOURCES.txt +1 -0
- searchlibrium-0.0.83/src/SearchLibrium/version.txt +0 -1
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/README.md +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/setup.cfg +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/Halton.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/MixedLogit.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/Mode_Activity_Nested.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/RandomP.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/SEARCH_SM_MARIO.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/Two_Level_Nest.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/__main__.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/_choice_model.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/_device.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/bhhh/minimize.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/boxcox_functions.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/call_meta.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/constraints_builder.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/harmony.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/latent_class.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/main.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/main_debug.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/misc.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/mixed_logit.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/mixed_nested.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/mixedrrm.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/multinomial_logit.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/multinomial_nested.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/multinomial_probit.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/ordered_logit.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/ordered_logit_mixed.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/rrm.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/search.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/setup.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/siman.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium/threshold.py +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/dependency_links.txt +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/entry_points.txt +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/requires.txt +0 -0
- {searchlibrium-0.0.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/top_level.txt +0 -0
|
@@ -59,7 +59,7 @@ Homepage = "https://github.com/zahern/HypothesisX"
|
|
|
59
59
|
realpython = "SearchLibrium.__main__:main"
|
|
60
60
|
|
|
61
61
|
[tool.bumpver]
|
|
62
|
-
current_version = "0.0.
|
|
62
|
+
current_version = "0.0.84"
|
|
63
63
|
version_pattern = "MAJOR.MINOR.PATCH"
|
|
64
64
|
commit_message = "[skip ci] Bump version {old_version} -> {new_version}"
|
|
65
65
|
commit = true
|
|
@@ -86,7 +86,9 @@ try:
|
|
|
86
86
|
from .rrm import RandomRegret
|
|
87
87
|
from .mixedrrm import MixedRandomRegret
|
|
88
88
|
from .ordered_logit import OrderedLogit, OrderedLogitLong
|
|
89
|
+
from .selection_models import BinaryProbit, HeckmanTwoStep
|
|
89
90
|
from .latent_class import LatentClassMixedLogit
|
|
91
|
+
from .multinomial_probit import MultinomialProbit
|
|
90
92
|
from .RandomP import RandomParameters
|
|
91
93
|
from .constraints_builder import ConstraintBuilder, create_constraints
|
|
92
94
|
from .search import Parameters
|
|
@@ -102,21 +104,27 @@ except ImportError as e:
|
|
|
102
104
|
from rrm import RandomRegret
|
|
103
105
|
from mixedrrm import MixedRandomRegret
|
|
104
106
|
from ordered_logit import OrderedLogit, OrderedLogitLong
|
|
107
|
+
from selection_models import BinaryProbit, HeckmanTwoStep
|
|
105
108
|
from latent_class import LatentClassMixedLogit
|
|
109
|
+
from multinomial_probit import MultinomialProbit
|
|
106
110
|
from RandomP import RandomParameters
|
|
107
111
|
from constraints_builder import ConstraintBuilder, create_constraints
|
|
108
112
|
from search import Parameters
|
|
109
113
|
from call_meta import call_siman, call_harmony, call_search, estimate_ctrl
|
|
110
114
|
try:
|
|
111
115
|
from .main import print_ascii_art_logo
|
|
112
|
-
except:
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
except Exception:
|
|
117
|
+
try:
|
|
118
|
+
from main import print_ascii_art_logo
|
|
119
|
+
except Exception:
|
|
120
|
+
print_ascii_art_logo = None
|
|
115
121
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
|
|
123
|
+
if print_ascii_art_logo is not None:
|
|
124
|
+
try:
|
|
125
|
+
print_ascii_art_logo()
|
|
126
|
+
except Exception:
|
|
127
|
+
print("SearchLibrium logo skipped; optional display dependencies are missing.")
|
|
120
128
|
|
|
121
129
|
#print('loaded all')
|
|
122
130
|
print('Welcome to SearchLibrium')
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from scipy.optimize import minimize
|
|
7
|
+
from scipy.stats import norm, t as student_t
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import jax
|
|
11
|
+
import jax.numpy as jnp
|
|
12
|
+
from jax.scipy.special import ndtr as jax_ndtr
|
|
13
|
+
except ImportError: # pragma: no cover
|
|
14
|
+
jax = None
|
|
15
|
+
jnp = None
|
|
16
|
+
jax_ndtr = None
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from ._choice_model import DiscreteChoiceModel
|
|
20
|
+
except ImportError:
|
|
21
|
+
from _choice_model import DiscreteChoiceModel
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BinaryProbit(DiscreteChoiceModel):
|
|
25
|
+
"""Binary probit estimated with JAX autodiff and scipy L-BFGS-B."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, _jax=False):
|
|
28
|
+
super(BinaryProbit, self).__init__(_jax)
|
|
29
|
+
self.descr = "Binary Probit"
|
|
30
|
+
self.result = None
|
|
31
|
+
self._X_design = None
|
|
32
|
+
|
|
33
|
+
def setup(self, X, y, varnames=None, fit_intercept=True):
|
|
34
|
+
X = np.asarray(X)
|
|
35
|
+
y = np.asarray(y).reshape(-1)
|
|
36
|
+
if varnames is None:
|
|
37
|
+
varnames = [f"x{i}" for i in range(X.shape[1])]
|
|
38
|
+
self.X = X
|
|
39
|
+
self.y = y
|
|
40
|
+
self.varnames = np.asarray(varnames, dtype="<U64")
|
|
41
|
+
self.fit_intercept = bool(fit_intercept)
|
|
42
|
+
self.sample_size = int(X.shape[0])
|
|
43
|
+
if self.fit_intercept:
|
|
44
|
+
self._X_design = np.column_stack([np.ones((X.shape[0], 1)), X])
|
|
45
|
+
self._design_names = np.asarray(["intercept", *self.varnames], dtype="<U64")
|
|
46
|
+
else:
|
|
47
|
+
self._X_design = X.copy()
|
|
48
|
+
self._design_names = self.varnames.copy()
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def _negloglik_jax(self, params, X, y):
|
|
52
|
+
xb = X @ params
|
|
53
|
+
p = jnp.clip(jax_ndtr(xb), 1e-10, 1.0 - 1e-10)
|
|
54
|
+
ll = y * jnp.log(p) + (1.0 - y) * jnp.log(1.0 - p)
|
|
55
|
+
return -jnp.sum(ll)
|
|
56
|
+
|
|
57
|
+
def fit(self, disp=False, **fit_kwargs):
|
|
58
|
+
if jax is None or jnp is None or jax_ndtr is None:
|
|
59
|
+
raise ImportError("JAX is required for BinaryProbit")
|
|
60
|
+
|
|
61
|
+
X = jnp.asarray(self._X_design)
|
|
62
|
+
y = jnp.asarray(self.y)
|
|
63
|
+
init = np.zeros(X.shape[1], dtype=float)
|
|
64
|
+
|
|
65
|
+
val_grad = jax.jit(jax.value_and_grad(self._negloglik_jax))
|
|
66
|
+
|
|
67
|
+
def _obj(params_np):
|
|
68
|
+
val, grad = val_grad(jnp.asarray(params_np), X, y)
|
|
69
|
+
return float(val), np.asarray(grad, dtype=float)
|
|
70
|
+
|
|
71
|
+
res = minimize(
|
|
72
|
+
fun=lambda p: _obj(p)[0],
|
|
73
|
+
x0=init,
|
|
74
|
+
jac=lambda p: _obj(p)[1],
|
|
75
|
+
method="L-BFGS-B",
|
|
76
|
+
options={"disp": bool(disp), "maxiter": int(fit_kwargs.pop("maxiter", 1000))},
|
|
77
|
+
)
|
|
78
|
+
self.result = res
|
|
79
|
+
self.coeff_names = self._design_names.copy()
|
|
80
|
+
self.coeff_est = np.asarray(res.x, dtype=float)
|
|
81
|
+
self.loglik = float(-res.fun)
|
|
82
|
+
self.converged = bool(res.success)
|
|
83
|
+
self.total_fun_eval = int(getattr(res, "nfev", 0))
|
|
84
|
+
|
|
85
|
+
hess_inv = getattr(res, "hess_inv", None)
|
|
86
|
+
if hess_inv is not None:
|
|
87
|
+
if hasattr(hess_inv, "todense"):
|
|
88
|
+
cov = np.asarray(hess_inv.todense(), dtype=float)
|
|
89
|
+
else:
|
|
90
|
+
cov = np.asarray(hess_inv, dtype=float)
|
|
91
|
+
stderr = np.sqrt(np.clip(np.diag(cov), 1e-12, None))
|
|
92
|
+
else:
|
|
93
|
+
stderr = np.full_like(self.coeff_est, np.nan, dtype=float)
|
|
94
|
+
|
|
95
|
+
self.stderr = stderr
|
|
96
|
+
self.zvalues = self.coeff_est / np.where(stderr > 0, stderr, np.nan)
|
|
97
|
+
self.pvalues = 2.0 * (1.0 - norm.cdf(np.abs(self.zvalues)))
|
|
98
|
+
k = len(self.coeff_est)
|
|
99
|
+
n = max(int(self.sample_size), 1)
|
|
100
|
+
self.aic = float(2 * k - 2 * self.loglik)
|
|
101
|
+
self.bic = float(k * np.log(n) - 2 * self.loglik)
|
|
102
|
+
return res
|
|
103
|
+
|
|
104
|
+
def predict_proba(self, X=None):
|
|
105
|
+
if self.coeff_est is None:
|
|
106
|
+
raise RuntimeError("BinaryProbit must be fit before prediction")
|
|
107
|
+
X_arr = self.X if X is None else np.asarray(X)
|
|
108
|
+
if self.fit_intercept:
|
|
109
|
+
X_arr = np.column_stack([np.ones((X_arr.shape[0], 1)), X_arr])
|
|
110
|
+
xb = X_arr @ self.coeff_est
|
|
111
|
+
return norm.cdf(xb)
|
|
112
|
+
|
|
113
|
+
def summary_frame(self):
|
|
114
|
+
if self.coeff_est is None:
|
|
115
|
+
return pd.DataFrame()
|
|
116
|
+
return pd.DataFrame({
|
|
117
|
+
"coef": self.coeff_est,
|
|
118
|
+
"stderr": self.stderr,
|
|
119
|
+
"z": self.zvalues,
|
|
120
|
+
"pvalue": self.pvalues,
|
|
121
|
+
}, index=self.coeff_names)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class _OLSResult:
|
|
126
|
+
params: pd.Series
|
|
127
|
+
bse: pd.Series
|
|
128
|
+
tvalues: pd.Series
|
|
129
|
+
pvalues: pd.Series
|
|
130
|
+
llf: float
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class HeckmanTwoStep(DiscreteChoiceModel):
|
|
134
|
+
"""Heckman selection model using JAX probit + closed-form OLS second stage."""
|
|
135
|
+
|
|
136
|
+
def __init__(self, _jax=False):
|
|
137
|
+
super(HeckmanTwoStep, self).__init__(_jax)
|
|
138
|
+
self.descr = "Heckman Two-Step"
|
|
139
|
+
self.selection_result = None
|
|
140
|
+
self.outcome_result = None
|
|
141
|
+
self.params_table = pd.DataFrame()
|
|
142
|
+
|
|
143
|
+
def setup(
|
|
144
|
+
self,
|
|
145
|
+
selection_X,
|
|
146
|
+
selection_y,
|
|
147
|
+
outcome_X,
|
|
148
|
+
outcome_y,
|
|
149
|
+
selection_varnames=None,
|
|
150
|
+
outcome_varnames=None,
|
|
151
|
+
fit_intercept=True,
|
|
152
|
+
):
|
|
153
|
+
selection_X = np.asarray(selection_X)
|
|
154
|
+
selection_y = np.asarray(selection_y).reshape(-1)
|
|
155
|
+
outcome_X = np.asarray(outcome_X)
|
|
156
|
+
outcome_y = np.asarray(outcome_y).reshape(-1)
|
|
157
|
+
if selection_varnames is None:
|
|
158
|
+
selection_varnames = [f"s{i}" for i in range(selection_X.shape[1])]
|
|
159
|
+
if outcome_varnames is None:
|
|
160
|
+
outcome_varnames = [f"o{i}" for i in range(outcome_X.shape[1])]
|
|
161
|
+
self.selection_X = selection_X
|
|
162
|
+
self.selection_y = selection_y
|
|
163
|
+
self.outcome_X = outcome_X
|
|
164
|
+
self.outcome_y = outcome_y
|
|
165
|
+
self.selection_varnames = np.asarray(selection_varnames, dtype="<U64")
|
|
166
|
+
self.outcome_varnames = np.asarray(outcome_varnames, dtype="<U64")
|
|
167
|
+
self.fit_intercept = bool(fit_intercept)
|
|
168
|
+
self.sample_size = int(selection_X.shape[0])
|
|
169
|
+
return self
|
|
170
|
+
|
|
171
|
+
def fit(self, disp=False, **fit_kwargs):
|
|
172
|
+
sel_X = np.asarray(self.selection_X, dtype=float)
|
|
173
|
+
out_X = np.asarray(self.outcome_X, dtype=float)
|
|
174
|
+
if self.fit_intercept:
|
|
175
|
+
sel_X = np.column_stack([np.ones((sel_X.shape[0], 1)), sel_X])
|
|
176
|
+
out_X = np.column_stack([np.ones((out_X.shape[0], 1)), out_X])
|
|
177
|
+
|
|
178
|
+
probit_model = BinaryProbit(_jax=True)
|
|
179
|
+
sel_names = (["intercept"] if self.fit_intercept else []) + list(self.selection_varnames)
|
|
180
|
+
probit_model.setup(sel_X[:, 1:] if self.fit_intercept else sel_X,
|
|
181
|
+
self.selection_y,
|
|
182
|
+
varnames=sel_names[1:] if self.fit_intercept else sel_names,
|
|
183
|
+
fit_intercept=self.fit_intercept)
|
|
184
|
+
probit_model.fit(disp=disp, **fit_kwargs)
|
|
185
|
+
|
|
186
|
+
xb = sel_X @ probit_model.coeff_est
|
|
187
|
+
mills = norm.pdf(xb) / np.clip(norm.cdf(xb), 1e-10, None)
|
|
188
|
+
|
|
189
|
+
mask = self.selection_y == 1
|
|
190
|
+
out_design = np.column_stack([out_X[mask], mills[mask]])
|
|
191
|
+
out_y = self.outcome_y[mask]
|
|
192
|
+
|
|
193
|
+
xtx = out_design.T @ out_design
|
|
194
|
+
xtx_inv = np.linalg.pinv(xtx)
|
|
195
|
+
beta = xtx_inv @ (out_design.T @ out_y)
|
|
196
|
+
resid = out_y - out_design @ beta
|
|
197
|
+
dof = max(out_design.shape[0] - out_design.shape[1], 1)
|
|
198
|
+
sigma2 = float((resid @ resid) / dof)
|
|
199
|
+
cov = sigma2 * xtx_inv
|
|
200
|
+
se = np.sqrt(np.clip(np.diag(cov), 1e-12, None))
|
|
201
|
+
tvals = beta / np.where(se > 0, se, np.nan)
|
|
202
|
+
pvals = 2.0 * (1.0 - student_t.cdf(np.abs(tvals), df=dof))
|
|
203
|
+
ll_ols = -0.5 * out_design.shape[0] * (math.log(2.0 * math.pi * sigma2) + 1.0)
|
|
204
|
+
|
|
205
|
+
out_names = (["intercept"] if self.fit_intercept else []) + list(self.outcome_varnames) + ["IMR"]
|
|
206
|
+
ols = _OLSResult(
|
|
207
|
+
params=pd.Series(beta, index=out_names),
|
|
208
|
+
bse=pd.Series(se, index=out_names),
|
|
209
|
+
tvalues=pd.Series(tvals, index=out_names),
|
|
210
|
+
pvalues=pd.Series(pvals, index=out_names),
|
|
211
|
+
llf=float(ll_ols),
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
self.selection_result = probit_model
|
|
215
|
+
self.outcome_result = ols
|
|
216
|
+
self.loglik = float(probit_model.loglik + ll_ols)
|
|
217
|
+
total_k = len(probit_model.coeff_est) + len(beta)
|
|
218
|
+
self.aic = float(2 * total_k - 2 * self.loglik)
|
|
219
|
+
self.bic = float(total_k * np.log(max(self.sample_size, 1)) - 2 * self.loglik)
|
|
220
|
+
self.converged = bool(probit_model.converged)
|
|
221
|
+
|
|
222
|
+
selection_tbl = pd.DataFrame({
|
|
223
|
+
"coef": probit_model.coeff_est,
|
|
224
|
+
"stderr": probit_model.stderr,
|
|
225
|
+
"z": probit_model.zvalues,
|
|
226
|
+
"pvalue": probit_model.pvalues,
|
|
227
|
+
}, index=probit_model.coeff_names)
|
|
228
|
+
outcome_tbl = pd.DataFrame({
|
|
229
|
+
"coef": ols.params,
|
|
230
|
+
"stderr": ols.bse,
|
|
231
|
+
"z": ols.tvalues,
|
|
232
|
+
"pvalue": ols.pvalues,
|
|
233
|
+
})
|
|
234
|
+
self.params_table = pd.concat(
|
|
235
|
+
{"selection": selection_tbl, "outcome": outcome_tbl},
|
|
236
|
+
names=["equation", "term"],
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
coeff_names = [f"selection::{name}" for name in selection_tbl.index]
|
|
240
|
+
coeff_names += [f"outcome::{name}" for name in outcome_tbl.index]
|
|
241
|
+
self.coeff_names = np.asarray(coeff_names, dtype="<U128")
|
|
242
|
+
self.coeff_est = np.concatenate([selection_tbl["coef"].values, outcome_tbl["coef"].values])
|
|
243
|
+
self.stderr = np.concatenate([selection_tbl["stderr"].values, outcome_tbl["stderr"].values])
|
|
244
|
+
self.zvalues = np.concatenate([selection_tbl["z"].values, outcome_tbl["z"].values])
|
|
245
|
+
self.pvalues = np.concatenate([selection_tbl["pvalue"].values, outcome_tbl["pvalue"].values])
|
|
246
|
+
return {"probit": probit_model, "ols": ols}
|
|
247
|
+
|
|
248
|
+
def predict_selection_proba(self, X=None):
|
|
249
|
+
if self.selection_result is None:
|
|
250
|
+
raise RuntimeError("HeckmanTwoStep must be fit before prediction")
|
|
251
|
+
X_arr = self.selection_X if X is None else np.asarray(X)
|
|
252
|
+
return self.selection_result.predict_proba(X_arr)
|
|
253
|
+
|
|
254
|
+
def predict_outcome(self, X=None, selection_probability=None):
|
|
255
|
+
if self.outcome_result is None:
|
|
256
|
+
raise RuntimeError("HeckmanTwoStep must be fit before prediction")
|
|
257
|
+
X_arr = self.outcome_X if X is None else np.asarray(X)
|
|
258
|
+
if self.fit_intercept:
|
|
259
|
+
X_arr = np.column_stack([np.ones((X_arr.shape[0], 1)), X_arr])
|
|
260
|
+
if selection_probability is None:
|
|
261
|
+
selection_probability = np.clip(self.predict_selection_proba(), 1e-10, 1 - 1e-10)
|
|
262
|
+
xb = norm.ppf(np.clip(selection_probability, 1e-10, 1 - 1e-10))
|
|
263
|
+
imr = norm.pdf(xb) / np.clip(norm.cdf(xb), 1e-10, None)
|
|
264
|
+
X_aug = np.column_stack([X_arr, imr])
|
|
265
|
+
return X_aug @ self.outcome_result.params.values
|
|
266
|
+
|
|
267
|
+
def summary_frame(self):
|
|
268
|
+
return self.params_table.copy()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.84
|
|
@@ -28,6 +28,7 @@ src/SearchLibrium/ordered_logit.py
|
|
|
28
28
|
src/SearchLibrium/ordered_logit_mixed.py
|
|
29
29
|
src/SearchLibrium/rrm.py
|
|
30
30
|
src/SearchLibrium/search.py
|
|
31
|
+
src/SearchLibrium/selection_models.py
|
|
31
32
|
src/SearchLibrium/setup.py
|
|
32
33
|
src/SearchLibrium/siman.py
|
|
33
34
|
src/SearchLibrium/threshold.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.0.83
|
|
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.83 → searchlibrium-0.0.84}/src/SearchLibrium.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|