test_logistic.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import numpy as np
  2. import pytest
  3. from irae_risk.logistic import LogisticPolyRegression
  4. @pytest.fixture
  5. def regression_data():
  6. x = np.linspace(-2.0, 2.0, 20)
  7. y = np.array([0, 1] * 10)
  8. theta = np.array([-0.2, 0.8])
  9. return x, y, theta
  10. def test_goodness_of_fit_uses_unpenalized_likelihood_by_default(regression_data):
  11. x, y, theta = regression_data
  12. model = LogisticPolyRegression(degree=1, lam=(0.0, 0.5))
  13. result = model.goodness_of_fit(x, y, theta, bootstrap_samples=20)
  14. expected_llf = -model.get_nllf(x, y, theta)
  15. k = len(theta)
  16. n = len(x)
  17. assert result["LLF"] == pytest.approx(expected_llf)
  18. assert result["AIC"] == pytest.approx(2 * k - 2 * expected_llf)
  19. assert result["BIC"] == pytest.approx(k * np.log(n) - 2 * expected_llf)
  20. def test_goodness_of_fit_can_include_regularization(regression_data):
  21. x, y, theta = regression_data
  22. model = LogisticPolyRegression(degree=1, lam=(0.0, 0.5))
  23. unregularized = model.goodness_of_fit(
  24. x, y, theta, bootstrap_samples=20
  25. )
  26. regularized = model.goodness_of_fit(
  27. x,
  28. y,
  29. theta,
  30. regularization=True,
  31. bootstrap_samples=20,
  32. )
  33. penalty = model.penalty(theta)
  34. assert regularized["LLF"] == pytest.approx(
  35. -model.get_cost(x, y, theta)
  36. )
  37. assert unregularized["LLF"] - regularized["LLF"] == pytest.approx(penalty)
  38. assert regularized["AIC"] - unregularized["AIC"] == pytest.approx(
  39. 2 * penalty
  40. )
  41. assert regularized["BIC"] - unregularized["BIC"] == pytest.approx(
  42. 2 * penalty
  43. )
  44. def test_regularization_switch_has_no_effect_without_penalty(regression_data):
  45. x, y, theta = regression_data
  46. model = LogisticPolyRegression(degree=1)
  47. default = model.goodness_of_fit(x, y, theta, bootstrap_samples=20)
  48. regularized = model.goodness_of_fit(
  49. x,
  50. y,
  51. theta,
  52. regularization=True,
  53. bootstrap_samples=20,
  54. )
  55. assert regularized == pytest.approx(default)
  56. def test_goodness_of_fit_reports_reproducible_bootstrap_deviance(regression_data):
  57. x, y, theta = regression_data
  58. model = LogisticPolyRegression(degree=1)
  59. first = model.goodness_of_fit(
  60. x,
  61. y,
  62. theta,
  63. bootstrap_samples=25,
  64. bootstrap_seed=123,
  65. )
  66. second = model.goodness_of_fit(
  67. x,
  68. y,
  69. theta,
  70. bootstrap_samples=25,
  71. bootstrap_seed=123,
  72. )
  73. assert "chi2" not in first
  74. assert "p-value(chi2)" not in first
  75. assert first["deviance"] == pytest.approx(2 * model.get_nllf(x, y, theta))
  76. assert first["p-value(deviance_bootstrap)"] == second[
  77. "p-value(deviance_bootstrap)"
  78. ]
  79. assert 0 < first["p-value(deviance_bootstrap)"] <= 1
  80. assert first["deviance_bootstrap_samples"] == 25