Skip to content

Commit

Permalink
Partial #16 - Improves unit testing for R2 and RMSE
Browse files Browse the repository at this point in the history
  • Loading branch information
Florian Bayer authored and Florian Bayer committed Mar 4, 2024
1 parent e8f543b commit 3e4d591
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 0 deletions.
83 changes: 83 additions & 0 deletions tests/unit/test_model_logistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ def test_invalid_input_type(self):
LM(self.x, self.params['pec50'], self.params['slope'], "invalid_input", self.params['back'])
LM(self.x, self.params['pec50'], self.params['slope'], self.params['front'], "invalid_input")

def test_valid_input_x_types(self):
LM = LogisticModel(**self.params)
y = LM(self.x)
assert isinstance(y, np.ndarray)
y = LM(list(self.x))
assert isinstance(y, np.ndarray)
y = LM(-8.0)
assert isinstance(y, float)

def test_output_shape(self):
LM = LogisticModel()
y = LM(self.x, self.params['pec50'], self.params['slope'], self.params['front'], self.params['back'])
Expand Down Expand Up @@ -432,3 +441,77 @@ def test_not_sorted(self):
x1 = self.x[::-1]
LM = LogisticModel(**params)
np.testing.assert_almost_equal(LM.get_auc(self.x), LM.get_auc(x1), decimal=6)


class TestR2:
x = np.array([-np.inf, -12, -11, -10, -9, -8, -7, -6, -5, -4])

def no_curve_back(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 1.0}
LM = LogisticModel(**params)
y = LM(self.x)
r2 = LM.calculate_r2(self.x, y)
r2_expected = 0.0
np.testing.assert_almost_equal(r2, r2_expected)

def no_curve_pec50(self):
params = {'pec50': 0.0, 'slope': 1.0, 'front': 1.0, 'back': 0.0}
LM = LogisticModel(**params)
y = LM(self.x)
r2 = LM.calculate_r2(self.x, y)
r2_expected = 0.0
np.testing.assert_almost_equal(r2, r2_expected)

def curve(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 0.0}
LM = LogisticModel(**params)
y = LM(self.x)
r2 = LM.calculate_r2(self.x, y)
r2_expected = 1.0
np.testing.assert_almost_equal(r2, r2_expected, decimal=6)

def test_nan_robustness(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 0.0}
LM = LogisticModel(**params)
y = LM(self.x)
y[-1] = np.nan
r2_a = LM.calculate_r2(self.x[:-1], y[:-1])
r2_b = LM.calculate_r2(self.x, y)
np.testing.assert_almost_equal(r2_a, r2_b)


class TestRMSE:
x = np.array([-np.inf, -12, -11, -10, -9, -8, -7, -6, -5, -4])

def test_no_curve_no_error(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 1.0}
LM = LogisticModel(**params)
y = LM(self.x)
rmse_expected = 0.0
rmse = LM.calculate_rmse(self.x, y)
np.testing.assert_almost_equal(rmse, rmse_expected)

def test_curve_no_error(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 0.0}
LM = LogisticModel(**params)
y = LM(self.x)
rmse_expected = 0.0
rmse = LM.calculate_rmse(self.x, y)
np.testing.assert_almost_equal(rmse, rmse_expected)

def test_curve_with_error(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 0.0}
LM = LogisticModel(**params)
y = LM(self.x)
error = 0.25
rmse = LM.calculate_rmse(self.x, y+error)
np.testing.assert_almost_equal(rmse, error)

def test_curve_with_error_nan(self):
params = {'pec50': 8.0, 'slope': 1.0, 'front': 1.0, 'back': 0.0}
LM = LogisticModel(**params)
y = LM(self.x)
y[-1] = np.nan
error = 0.25
rmse = LM.calculate_rmse(self.x, y+error)
np.testing.assert_almost_equal(rmse, error)
76 changes: 76 additions & 0 deletions tests/unit/test_model_mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ def test_invalid_input_type(self):
with pytest.raises(TypeError):
M("invalid_input")

def test_valid_input_x_types(self):
M = MeanModel(**self.params)
y = M(self.x)
assert isinstance(y, np.ndarray)
y = M(list(self.x))
assert isinstance(y, np.ndarray)
y = M(-8.0)
assert isinstance(y, type(self.params['intercept']))

def test_output_shape(self):
M = MeanModel()
y = M(self.x, self.params['intercept'])
Expand Down Expand Up @@ -168,3 +177,70 @@ def test_basinhopping(self):
M.basinhopping_ols(self.x, self.y, self.noise)
fitted_params = M.get_fitted_params()
pd.testing.assert_series_equal(pd.Series(fitted_params), pd.Series(self.params), atol=1e-4)


class TestR2:
x = np.log10([0.3, 1, 3, 10, 30, 100, 300, 1000, 3000, 10000]) - 9

def test_output_1(self):
M = MeanModel(intercept=1)
y = M(self.x)
r2 = M.calculate_r2(self.x, y)
r2_expected = 0.0
np.testing.assert_almost_equal(r2, r2_expected)

def test_output_2(self):
M = MeanModel(intercept=0)
y = M(self.x)
r2 = M.calculate_r2(self.x, y)
r2_expected = 0.0
np.testing.assert_almost_equal(r2, r2_expected)

def test_output_3(self):
M = MeanModel(intercept=1)
y = M(self.x)
y[-1] = -np.inf
r2 = M.calculate_r2(self.x, y)
r2_expected = 0.0
np.testing.assert_almost_equal(r2, r2_expected)

def test_output_4(self):
M = MeanModel(intercept=0)
y = np.array([i%2 for i in range(len(self.x))]) - 0.5
r2 = M.calculate_r2(self.x, y)
r2_expected = 0.0
np.testing.assert_almost_equal(r2, r2_expected)

def test_nan_robustness(self):
M = MeanModel(intercept=1)
y = M(self.x)
y[-1] = np.nan
r2_a = M.calculate_r2(self.x[:-1], y[:-1])
r2_b = M.calculate_r2(self.x, y)
np.testing.assert_almost_equal(r2_a, r2_b)


class TestRMSE:
x = np.array([-np.inf, -12, -11, -10, -9, -8, -7, -6, -5, -4])

def test_no_error(self):
M = MeanModel(intercept=1)
y = M(self.x)
rmse_expected = 0.0
rmse = M.calculate_rmse(self.x, y)
np.testing.assert_almost_equal(rmse, rmse_expected)

def test_with_error(self):
M = MeanModel(intercept=1)
y = M(self.x)
error = 0.5
rmse = M.calculate_rmse(self.x, y+error)
np.testing.assert_almost_equal(rmse, error)

def test_with_error_nan(self):
M = MeanModel(intercept=1)
y = M(self.x)
y[-1] = np.nan
error = 0.5
rmse = M.calculate_rmse(self.x, y+error)
np.testing.assert_almost_equal(rmse, error)

0 comments on commit 3e4d591

Please sign in to comment.