def test_log_likelihood(): """ Computes the log-likelihood "by hand" for a simple example and ensures that the one returned by xlogit is the same """ P = 1 # Without panel data betas = np.array([.1, .1, .1, .1]) X_, y_ = X.reshape(N, P, J, K), y.reshape(N, P, J, 1) # Compute log likelihood using xlogit model = MixedLogit() model._rvidx, model._rvdist = np.array([True, True]), np.array(['n', 'n']) draws = model._get_halton_draws(N, R, K) # (N,Kr,R) panel_info = np.ones((N, P)) obtained_loglik, _ = model._loglik_gradient(betas, X_, y_, panel_info, draws, None, None) # Compute expected log likelihood "by hand" Br = betas[None, [0, 1], None] + draws * betas[None, [2, 3], None] eXB = np.exp(np.einsum('npjk,nkr -> npjr', X_, Br)) p = eXB / np.sum(eXB, axis=2, keepdims=True) expected_loglik = -np.sum( np.log((y_ * p).sum(axis=2).prod(axis=1).mean(axis=1))) assert pytest.approx(expected_loglik, obtained_loglik)
def test_log_likelihood(): """ Computes the log-likelihood "by hand" for a simple example and ensures that the one returned by xlogit is the same """ betas = np.array([.1, .1, .1, .1]) X_, y_ = X.reshape(N, J, K), y.reshape(N, J, 1) # Compute log likelihood using xlogit model = MixedLogit() model._rvidx, model._rvdist = np.array([True, True]), np.array(['n', 'n']) draws = model._generate_halton_draws(N, R, K) # (N,Kr,R) obtained_loglik = model._loglik_gradient(betas, X_, y_, None, draws, None, None, { 'samples': N, 'draws': R }, return_gradient=False) # Compute expected log likelihood "by hand" Br = betas[None, [0, 1], None] + draws * betas[None, [2, 3], None] eXB = np.exp(np.einsum('njk,nkr -> njr', X_, Br)) p = eXB / np.sum(eXB, axis=1, keepdims=True) expected_loglik = -np.sum(np.log((y_ * p).sum(axis=1).mean(axis=1))) assert expected_loglik == pytest.approx(obtained_loglik)
def test__transform_betas(): """ Check that betas are properly transformed to random draws """ betas = np.array([.1, .1, .1, .1]) # Compute log likelihood using xlogit model = MixedLogit() model._rvidx, model._rvdist = np.array([True, True]), np.array(['n', 'n']) draws = model._get_halton_draws(N, R, K) # (N,Kr,R) expected_betas = betas[None, [0, 1], None] + \ draws*betas[None, [2, 3], None] _, obtained_betas = model._transform_betas(betas, draws) assert np.allclose(expected_betas, obtained_betas)
def test_predict(): """ Ensures that returned choice probabilities are consistent. """ # There is no need to initialize a random seed as the halton draws produce # reproducible results P = 1 # Without panel data betas = np.array([.1, .1, .1, .1]) X_ = X.reshape(N, P, J, K) model = MixedLogit() model._rvidx, model._rvdist = np.array([True, True]), np.array(['n', 'n']) model.alternatives = np.array([1, 2]) model.coeff_ = betas model.randvars = randvars model._isvars, model._asvars, model._varnames = [], varnames, varnames model._fit_intercept = False model.coeff_names = np.array(["a", "b", "sd.a", "sd.b"]) #model.fit(X, y, varnames, alts, ids, randvars, verbose=0, halton=True) y_pred, proba, freq = model.predict(X, varnames, alts, ids, n_draws=R, return_proba=True, return_freq=True) # Compute choice probabilities by hand draws = model._get_halton_draws(N, R, K) # (N,Kr,R) Br = betas[None, [0, 1], None] + draws * betas[None, [2, 3], None] V = np.einsum('npjk,nkr -> npjr', X_, Br) V[V > 700] = 700 eV = np.exp(V) e_proba = eV / np.sum(eV, axis=2, keepdims=True) expec_proba = e_proba.prod(axis=1).mean(axis=-1) expec_ypred = model.alternatives[np.argmax(expec_proba, axis=1)] alt_list, counts = np.unique(expec_ypred, return_counts=True) expec_freq = dict( zip(list(alt_list), list(np.round(counts / np.sum(counts), 3)))) assert np.array_equal(expec_ypred, y_pred) assert expec_freq == freq