Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## install : Install project package locally and install pre-commit.
.PHONY : install
install :
pip install pip-tools
pip3 install pip-tools
pip-compile requirements.in
pip install -r requirements.txt
pip3 install -r requirements.txt

## help : Documentation for make targets.
.PHONY : help
Expand Down
13 changes: 6 additions & 7 deletions src/pylogit/choice_calcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,9 +524,8 @@ def quadratic_prod_wrt_dp_ds(left,
if weights is None:
weights = np.ones(probs.shape[0])
# Convert matrixlib objects to ndarrays
left = left.A if isinstance(left, np.matrixlib.defmatrix.matrix) else left
right =\
right.A if isinstance(right, np.matrixlib.defmatrix.matrix) else right
left = np.asarray(left) if isinstance(left, np.matrixlib.defmatrix.matrix) else left
right = np.asarray(right) if isinstance(right, np.matrixlib.defmatrix.matrix) else right
# Determine properties of left and right
left_is_ndarray = isinstance(left, np.ndarray)
left_is_sparse, right_is_sparse = issparse(left), issparse(right)
Expand Down Expand Up @@ -957,8 +956,8 @@ def calc_fisher_info_matrix(beta,
##########
if shape_params is not None and intercept_params is not None:
if isinstance(dh_dc, np.matrixlib.defmatrix.matrix):
# Note that the '.A' transforms the matrix into a numpy ndarray
gradient_vec = d_ll_dh.T * np.concatenate((dh_dc.A,
# Note that the 'np.asarray()' transforms the matrix into a numpy ndarray
gradient_vec = d_ll_dh.T * np.concatenate((np.asarray(dh_dc),
dh_d_alpha.toarray(),
dh_db), axis=1)
else:
Expand All @@ -967,8 +966,8 @@ def calc_fisher_info_matrix(beta,
dh_db), axis=1)
elif shape_params is not None and intercept_params is None:
if isinstance(dh_dc, np.matrixlib.defmatrix.matrix):
# Note that the '.A' transforms the matrix into a numpy ndarray
gradient_vec = d_ll_dh.T * np.concatenate((dh_dc.A, dh_db), axis=1)
# Note that the 'np.asarray()' transforms the matrix into a numpy ndarray
gradient_vec = d_ll_dh.T * np.concatenate((np.asarray(dh_dc), dh_db), axis=1)
else:
gradient_vec = d_ll_dh.T * np.concatenate((dh_dc.toarray(),
dh_db), axis=1)
Expand Down
7 changes: 5 additions & 2 deletions src/pylogit/choice_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@

import warnings
from collections import OrderedDict
from collections import Iterable
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
from numbers import Number

import numpy as np
Expand Down Expand Up @@ -971,7 +974,7 @@ def create_long_form_mappings(long_form,
if dense:
for key in mapping_dict:
if mapping_dict[key] is not None:
mapping_dict[key] = mapping_dict[key].A
mapping_dict[key] = mapping_dict[key].toarray()

return mapping_dict

Expand Down
2 changes: 1 addition & 1 deletion src/pylogit/mixed_logit.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ def __filter_past_mappings(self,
orig_map = past_mappings[key]
# Initialize the resultant array that is desired
new_map = orig_map.multiply(np.tile(mask_array,
(1, orig_map.shape[1]))).A
(1, orig_map.shape[1]))).toarray()
# Perform the desired filtering
current_filter = (new_map.sum(axis=1) != 0)
if current_filter.shape[0] > 0:
Expand Down
60 changes: 41 additions & 19 deletions src/pylogit/nested_choice_calcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,14 @@ def calc_nested_probs(nest_coefs,
long_exp_sums_per_nest = np.asarray(long_exp_sums_per_nest)

# Get the relevant log-sum for each row of the long-format data
# Note the .A converts the numpy matrix into a numpy array
# Note the .toarray() converts the numpy matrix into a numpy array
# This is sum _{j \in C_m} exp(V_{ij} / \lambda_m) for the nest
# belonging to each row
long_exp_sums = (rows_to_nests.multiply(long_exp_sums_per_nest)
.sum(axis=1)
.A).ravel()
long_exp_sums_temp = rows_to_nests.multiply(long_exp_sums_per_nest).sum(axis=1)
if isinstance(long_exp_sums_temp, np.matrixlib.defmatrix.matrix):
long_exp_sums = np.asarray(long_exp_sums_temp).ravel()
else:
long_exp_sums = long_exp_sums_temp.toarray().ravel()

# Get the denominators for each individual
ind_denom = (np.power(ind_exp_sums_per_nest,
Expand Down Expand Up @@ -255,7 +257,7 @@ def calc_nested_probs(nest_coefs,
zero_idx = (nest_choice_probs == 0)
nest_choice_probs[zero_idx] = min_comp_value
# Return dictionary.
# Note the ".A" converts the numpy matrix into a numpy array
# Note the ".toarray()" converts the numpy matrix into a numpy array
prob_dict["prob_given_nest"] = prob_given_nest
prob_dict["nest_choice_probs"] = nest_choice_probs
prob_dict["ind_sums_per_nest"] = ind_exp_sums_per_nest
Expand Down Expand Up @@ -407,10 +409,11 @@ def prep_vectors_for_gradient(nest_coefs,
# Create the "long_nest_parameters" which is an array with one element per
# alternative per observation, where each element is the nest parameter for
# the alternative corresponding to the given row
long_nest_params = (rows_to_nests.multiply(nest_coefs[None, :])
.sum(axis=1)
.A
.ravel())
long_nest_params_temp = rows_to_nests.multiply(nest_coefs[None, :]).sum(axis=1)
if isinstance(long_nest_params_temp, np.matrixlib.defmatrix.matrix):
long_nest_params = np.asarray(long_nest_params_temp).ravel()
else:
long_nest_params = long_nest_params_temp.toarray().ravel()

# Calculate y-tilde
scaled_y = choice_vec / long_nest_params
Expand All @@ -420,14 +423,19 @@ def prep_vectors_for_gradient(nest_coefs,

# Determine which nest was chosen by each row's individual.
# Resulting matrix has shape (num_rows, num_nests)
obs_to_chosen_nests = (rows_to_obs.T *
rows_to_nests.multiply(choice_vec[:, None])).A
obs_to_chosen_nests_temp = (rows_to_obs.T *
rows_to_nests.multiply(choice_vec[:, None]))
if isinstance(obs_to_chosen_nests_temp, np.matrixlib.defmatrix.matrix):
obs_to_chosen_nests = np.asarray(obs_to_chosen_nests_temp)
else:
obs_to_chosen_nests = obs_to_chosen_nests_temp.toarray()
row_to_chosen_nest = rows_to_obs * obs_to_chosen_nests
# Determine whether the given row is part of the nest that was chosen
long_chosen_nest = (rows_to_nests.multiply(row_to_chosen_nest)
.sum(axis=1)
.A
.ravel())
long_chosen_nest_temp = rows_to_nests.multiply(row_to_chosen_nest).sum(axis=1)
if isinstance(long_chosen_nest_temp, np.matrixlib.defmatrix.matrix):
long_chosen_nest = np.asarray(long_chosen_nest_temp).ravel()
else:
long_chosen_nest = long_chosen_nest_temp.toarray().ravel()

# Get the various probabilities
prob_dict = calc_nested_probs(nest_coefs,
Expand Down Expand Up @@ -566,7 +574,10 @@ def calc_nested_gradient(orig_nest_coefs,
# Calculate the weights for the sample
if weights is None:
weights = np.ones(design.shape[0])
weights_per_obs = np.max(rows_to_obs.toarray() * weights[:, None], axis=0)
if isinstance(rows_to_obs, np.matrixlib.defmatrix.matrix):
weights_per_obs = np.max(np.asarray(rows_to_obs) * weights[:, None], axis=0)
else:
weights_per_obs = np.max(rows_to_obs.toarray() * weights[:, None], axis=0)

# Transform the nest coefficients into their "always positive" versions
nest_coefs = naturalize_nest_coefs(orig_nest_coefs)
Expand Down Expand Up @@ -743,7 +754,10 @@ def calc_bhhh_hessian_approximation(orig_nest_coefs,
# Calculate the weights for the sample
if weights is None:
weights = np.ones(design.shape[0])
weights_per_obs = np.max(rows_to_obs.toarray() * weights[:, None], axis=0)
if isinstance(rows_to_obs, np.matrixlib.defmatrix.matrix):
weights_per_obs = np.max(np.asarray(rows_to_obs) * weights[:, None], axis=0)
else:
weights_per_obs = np.max(rows_to_obs.toarray() * weights[:, None], axis=0)

# Transform the nest coefficients into their "always positive" versions
nest_coefs = naturalize_nest_coefs(orig_nest_coefs)
Expand Down Expand Up @@ -790,7 +804,11 @@ def calc_bhhh_hessian_approximation(orig_nest_coefs,
spread_half_deriv = rows_to_nests.multiply(half_deriv)
# Aggregate the spread out half-derivatives to the individual level
# This object should have shape (num_obs, num_nests)
nest_gradient_term_2 = rows_to_obs.transpose().dot(spread_half_deriv).A
nest_gradient_term_2_temp = rows_to_obs.transpose().dot(spread_half_deriv)
if isinstance(nest_gradient_term_2_temp, np.matrixlib.defmatrix.matrix):
nest_gradient_term_2 = np.asarray(nest_gradient_term_2_temp)
else:
nest_gradient_term_2 = nest_gradient_term_2_temp.toarray()

# Calculate the third term of the derivative of the log-likelihood
# with respect to the nest parameters
Expand All @@ -810,7 +828,11 @@ def calc_bhhh_hessian_approximation(orig_nest_coefs,

# Get the nest-wide version of this piece of the gradient
spread_out_term_3b = rows_to_nests.multiply(nest_gradient_term_3b[:, None])
nest_gradient_term_3 = rows_to_obs.transpose().dot(spread_out_term_3b).A
nest_gradient_term_3_temp = rows_to_obs.transpose().dot(spread_out_term_3b)
if isinstance(nest_gradient_term_3_temp, np.matrixlib.defmatrix.matrix):
nest_gradient_term_3 = np.asarray(nest_gradient_term_3_temp)
else:
nest_gradient_term_3 = nest_gradient_term_3_temp.toarray()

# Combine the terms. Note the "nest_coefs * (1 - nest_coefs)" is due to the
# fact that we're estimating the logit of the nest coefficients instead of
Expand Down
15 changes: 9 additions & 6 deletions tests/test_asym_logit.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ def test_keyword_argument_constructor_in_fit_mle(self):
# create the init_vals object since the ridge error check is after
# the creation of this argurment.
for kwargs in [kwargs_1, kwargs_2]:
self.assertRaisesRegexp(TypeError,
self.assertRaisesRegex(TypeError,
"ridge",
self.model_obj.fit_mle,
*fit_args,
Expand All @@ -343,7 +343,7 @@ def test_init_vals_length_error_in_fit_mle(self):

# Test to ensure that the ValueError when using an
# init_intercepts kwarg with an incorrect number of parameters
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
"dimension",
self.model_obj.fit_mle,
np.arange(num_coefs),
Expand Down Expand Up @@ -786,7 +786,7 @@ def test_asym_transform_deriv_v(self):
self.assertIsInstance(derivative, type(output))
self.assertEqual(len(derivative.shape), 2)
self.assertEqual(derivative.shape, (num_rows, num_rows))
npt.assert_allclose(np.diag(derivative.A), results)
npt.assert_allclose(np.diag(derivative.toarray()), results)

return None

Expand All @@ -811,7 +811,7 @@ def test_asym_transform_deriv_alpha(self):
if test_output is None:
self.assertIsNone(derivative_results)
else:
npt.assert_allclose(test_output.A, derivative_results.A)
npt.assert_allclose(test_output.toarray(), derivative_results.toarray())

return None

Expand Down Expand Up @@ -957,12 +957,15 @@ def test_asym_transform_deriv_shape(self):
interim_results = self.fake_rows_to_alts.multiply(interim_results)

# Calculate the correct results
results = interim_results.A.dot(dc_d_eta)
results = interim_results.toarray().dot(dc_d_eta)

# Ensure the results are as expected
self.assertIsInstance(derivative, type(output))
self.assertEqual(len(derivative.shape), 2)
self.assertEqual(derivative.shape, (num_rows, num_alts - 1))
npt.assert_allclose(derivative.A, results)
if isinstance(derivative, np.matrixlib.defmatrix.matrix):
npt.assert_allclose(np.asarray(derivative), results)
else:
npt.assert_allclose(derivative.toarray(), results)

return None
18 changes: 9 additions & 9 deletions tests/test_base_multinomial_cm.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def test_numeric_validity_check_for_specification_cols(self):
"""
# Create a variety of "bad" columns for 'x'
bad_exogs = [np.array(['foo', 'bar', 'gerbil', 'sat', 'sun']),
np.array([1, 2, 3, np.NaN, 1]),
np.array([1, 2, 3, np.nan, 1]),
np.array([1, 2, np.inf, 0.5, 0.9]),
np.array([1, 2, -np.inf, 0.5, 0.9]),
np.array([1, 'foo', -np.inf, 0.5, 0.9])]
Expand Down Expand Up @@ -461,13 +461,13 @@ def test_ensure_all_mixing_vars_are_in_the_name_dict(self):
bad_mixing_vars,
name_dict,
independent_variable_names)
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
msg_with_name_dict,
func,
bad_mixing_vars,
name_dict,
independent_variable_names)
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
msg_without_name_dict,
func,
bad_mixing_vars,
Expand Down Expand Up @@ -496,7 +496,7 @@ def test_ensure_all_alternatives_are_chosen(self):

# Perform the requisite tests
self.assertIsNone(func("alt_id", "choice", good_df))
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
"The following alternative ID's were not"
" chosen in any choice situation:",
func,
Expand Down Expand Up @@ -688,7 +688,7 @@ def test_check_for_choice_col_based_on_return_long_probs(self):
for arg_set in good_args:
self.assertIsNone(func(*arg_set))

self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
msg,
func,
*bad_args)
Expand Down Expand Up @@ -937,7 +937,7 @@ def test_check_result_dict_for_needed_keys(self):
# Delete the needed key from the dictionary
del base_dict[key]
# Make sure that we get a value error when testing the function
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
"keys are missing",
func,
base_dict)
Expand Down Expand Up @@ -979,7 +979,7 @@ def test_create_results_summary(self):
for attr in needed_attributes:
delattr(self.model_obj, attr)
# Make sure that we get a value error when testing the function
self.assertRaisesRegexp(NotImplementedError,
self.assertRaisesRegex(NotImplementedError,
msg,
func)
# Set the attribute back
Expand Down Expand Up @@ -1029,7 +1029,7 @@ def test_record_values_for_fit_summary_and_statsmodels(self):
msg = "Call this function only after setting/calculating all other"
msg_2 = " estimation results attributes"
error_msg = msg + msg_2
self.assertRaisesRegexp(NotImplementedError,
self.assertRaisesRegex(NotImplementedError,
error_msg,
func)
# Put the attribute back.
Expand Down Expand Up @@ -1094,7 +1094,7 @@ def test_create_fit_summary(self):
msg = "Call this function only after setting/calculating all other"
msg_2 = " estimation results attributes"
error_msg = msg + msg_2
self.assertRaisesRegexp(NotImplementedError,
self.assertRaisesRegex(NotImplementedError,
error_msg,
func)
# Put the attribute back.
Expand Down
11 changes: 7 additions & 4 deletions tests/test_bootstrap_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
Tests for the bootstrap_abc.py file.
"""
import unittest
from collections import Iterable
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable

import numpy as np
import numpy.testing as npt
Expand Down Expand Up @@ -33,7 +36,7 @@ def nonsense_func(self):

# Perform the desired tests
self.assertIsNone(func(good_obj))
self.assertRaisesRegexp(ValueError, err_msg, func, bad_obj)
self.assertRaisesRegex(ValueError, err_msg, func, bad_obj)
return None

def test_ensure_rows_to_obs_validity(self):
Expand All @@ -49,7 +52,7 @@ def test_ensure_rows_to_obs_validity(self):
for good_obj in good_objects:
self.assertIsNone(func(good_obj))
for bad_obj in bad_objects:
self.assertRaisesRegexp(ValueError, err_msg, func, bad_obj)
self.assertRaisesRegex(ValueError, err_msg, func, bad_obj)
return None

def test_ensure_wide_weights_is_1D_or_2D_ndarray(self):
Expand All @@ -68,7 +71,7 @@ def test_ensure_wide_weights_is_1D_or_2D_ndarray(self):
self.assertIsNone(func(good_obj))
for pos, bad_obj in enumerate(bad_objects):
err_msg = err_msgs[pos]
self.assertRaisesRegexp(ValueError, err_msg, func, bad_obj)
self.assertRaisesRegex(ValueError, err_msg, func, bad_obj)
return None


Expand Down
4 changes: 2 additions & 2 deletions tests/test_bootstrap_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def test_ensure_replicates_kwarg_validity(self):
for good_arg in good_args:
self.assertIsNone(func(good_arg))
for bad_arg in bad_args:
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
expected_error_msg,
func,
bad_arg)
Expand Down Expand Up @@ -715,7 +715,7 @@ def test_interval_type_error_in_calc_conf_intervals(self):
"interval_type MUST be in `\['pi', 'bca', 'abc', 'all'\]`"

# Ensure that the appropriate errors are raised.
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
expected_error_msg,
func,
self.conf_percentage,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_bootstrap_mle.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def __init__(self, fake_model_type):

# Perform a test that should fail. Ensure the correct error is raised.
current_obj = FakeModel(bad_type)
self.assertRaisesRegexp(ValueError,
self.assertRaisesRegex(ValueError,
err_msg,
func,
current_obj)
Expand Down
Loading