diff --git a/_unittests/ut_mlmodel/test_quantile_regression.py b/_unittests/ut_mlmodel/test_quantile_regression.py index e1eb927a..2c1593ae 100644 --- a/_unittests/ut_mlmodel/test_quantile_regression.py +++ b/_unittests/ut_mlmodel/test_quantile_regression.py @@ -32,6 +32,22 @@ def test_quantile_regression_no_intercept(self): self.assertEqual(clq.intercept_, 0) self.assertEqualArray(clr.intercept_, clq.intercept_) + def test_quantile_regression_no_intercept_positive(self): + X = numpy.array([[0.1, 0.2], [0.2, 0.3]]) + Y = numpy.array([1., 1.1]) + clr = LinearRegression(fit_intercept=False, positive=True) + clr.fit(X, Y) + clq = QuantileLinearRegression(fit_intercept=False, positive=True) + clq.fit(X, Y) + self.assertEqual(clr.intercept_, 0) + self.assertEqual(clq.intercept_, 0) + self.assertGreater(clr.coef_.min(), 0) + self.assertGreater(clq.coef_.min(), 0) + self.assertEqualArray(clr.intercept_, clq.intercept_) + self.assertEqualArray(clr.coef_[0], clq.coef_[0]) + self.assertGreater(clr.coef_[1:].min(), 3) + self.assertGreater(clq.coef_[1:].min(), 3) + def test_quantile_regression_intercept(self): X = numpy.array([[0.1, 0.2], [0.2, 0.3], [0.3, 0.3]]) Y = numpy.array([1., 1.1, 1.2]) @@ -44,6 +60,21 @@ def test_quantile_regression_intercept(self): self.assertEqualArray(clr.intercept_, clq.intercept_) self.assertEqualArray(clr.coef_, clq.coef_) + def test_quantile_regression_intercept_positive(self): + X = numpy.array([[0.1, 0.2], [0.2, 0.3], [0.3, 0.3]]) + Y = numpy.array([1., 1.1, 1.2]) + clr = LinearRegression(fit_intercept=True, positive=True) + clr.fit(X, Y) + clq = QuantileLinearRegression( + verbose=False, fit_intercept=True, positive=True) + clq.fit(X, Y) + self.assertNotEqual(clr.intercept_, 0) + self.assertNotEqual(clq.intercept_, 0) + self.assertEqualArray(clr.intercept_, clq.intercept_) + self.assertEqualArray(clr.coef_, clq.coef_) + self.assertGreater(clr.coef_.min(), 0) + self.assertGreater(clq.coef_.min(), 0) + def test_quantile_regression_intercept_weights(self): X = numpy.array([[0.1, 0.2], [0.2, 0.3], [0.3, 0.3]]) Y = numpy.array([1., 1.1, 1.2]) diff --git a/mlinsights/mlmodel/quantile_regression.py b/mlinsights/mlmodel/quantile_regression.py index 5f600b29..2943b9ff 100644 --- a/mlinsights/mlmodel/quantile_regression.py +++ b/mlinsights/mlmodel/quantile_regression.py @@ -31,7 +31,7 @@ class QuantileLinearRegression(LinearRegression): def __init__(self, fit_intercept=True, normalize=False, copy_X=True, n_jobs=1, delta=0.0001, max_iter=10, quantile=0.5, - verbose=False): + positive=False, verbose=False): """ :param fit_intercept: boolean, optional, default True whether to calculate the intercept for this model. If set @@ -59,11 +59,12 @@ def __init__(self, fit_intercept=True, normalize=False, copy_X=True, :param quantile: float, by default 0.5, determines which quantile to use to estimate the regression. + :param positive: when set to True, forces the coefficients to be positive. :param verbose: bool, optional, default False Prints error at each iteration of the optimisation. """ LinearRegression.__init__(self, fit_intercept=fit_intercept, normalize=normalize, - copy_X=copy_X, n_jobs=n_jobs) + copy_X=copy_X, n_jobs=n_jobs, positive=positive) self.max_iter = max_iter self.verbose = verbose self.delta = delta @@ -131,7 +132,8 @@ def compute_z(Xm, beta, Y, W, delta=0.0001): Xm = X clr = LinearRegression(fit_intercept=False, copy_X=self.copy_X, - n_jobs=self.n_jobs, normalize=self.normalize) + n_jobs=self.n_jobs, normalize=self.normalize, + positive=self.positive) W = numpy.ones(X.shape[0]) if sample_weight is None else sample_weight self.n_iter_ = 0 @@ -197,5 +199,4 @@ def score(self, X, y, sample_weight=None): if mult is not None: epsilon *= mult * 2 return epsilon.sum() / X.shape[0] - else: - return mean_absolute_error(y, pred, sample_weight=sample_weight) + return mean_absolute_error(y, pred, sample_weight=sample_weight)