From 53af39d42af8ac3063d5a804101e6bffdaf1dc3f Mon Sep 17 00:00:00 2001 From: GUI Date: Wed, 13 Apr 2022 16:20:41 +0200 Subject: [PATCH] integer intercept if rounding=True --- optbinning/scorecard/scorecard.py | 30 ++++++++++++++++++++++++++---- tests/test_scorecard.py | 22 +++++++++++++++++++++- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/optbinning/scorecard/scorecard.py b/optbinning/scorecard/scorecard.py index 2afd49d..6e36091 100644 --- a/optbinning/scorecard/scorecard.py +++ b/optbinning/scorecard/scorecard.py @@ -61,22 +61,26 @@ def _check_parameters(binning_process, estimator, scaling_method, if not isinstance(rounding, bool): raise TypeError("rounding must be a boolean; got {}.".format(rounding)) + if rounding and scaling_method is None: + raise ValueError("rounding is only applied if scaling method is " + "not None.") + if not isinstance(verbose, bool): raise TypeError("verbose must be a boolean; got {}.".format(verbose)) def _check_scorecard_scaling(scaling_method, scaling_method_params, - target_type): + rounding, target_type): if scaling_method is not None: if scaling_method == "pdo_odds": - default_keys = ["pdo", "odds", "scorecard_points"] + default_keys = ("pdo", "odds", "scorecard_points") if target_type != "binary": raise ValueError('scaling_method "pd_odds" is not supported ' 'for a continuous target.') elif scaling_method == "min_max": - default_keys = ["min", "max"] + default_keys = ("min", "max") if set(scaling_method_params.keys()) != set(default_keys): raise ValueError("scaling_method_params must be {} given " @@ -102,6 +106,17 @@ def _check_scorecard_scaling(scaling_method, scaling_method_params, .format(scaling_method_params["min"], scaling_method_params["max"])) + if rounding: + score_min = scaling_method_params['min'] + if int(score_min) != score_min: + raise ValueError("min must be an integer if rounding=True" + "; got {}.".format(score_min)) + + score_max = scaling_method_params['max'] + if int(score_max) != score_max: + raise ValueError("max must be an integer if rounding=True" + "; got {}.".format(score_max)) + def _compute_scorecard_points(points, binning_tables, method, method_data, intercept, reverse_scorecard): @@ -483,6 +498,7 @@ def _fit(self, X, y, sample_weight, metric_special, metric_missing, _check_scorecard_scaling(self.scaling_method, self.scaling_method_params, + self.rounding, self._target_dtype) # Check sample weight @@ -595,8 +611,11 @@ def _fit(self, X, y, sample_weight, metric_special, metric_missing, time_rounding = time.perf_counter() if self.rounding: points = df_scorecard["Points"] - if self.scaling_method == "pdo_odds": + if self.scaling_method in ("pdo_odds", None): round_points = np.rint(points) + + if self.intercept_based: + self.intercept_ = np.rint(self.intercept_) elif self.scaling_method == "min_max": round_mip = RoundingMIP() round_mip.build_model(df_scorecard) @@ -609,6 +628,9 @@ def _fit(self, X, y, sample_weight, metric_special, metric_missing, # Back-up method round_points = np.rint(points) + if self.intercept_based: + self.intercept_ = np.rint(self.intercept_) + df_scorecard.loc[:, "Points"] = round_points self._time_rounding = time.perf_counter() - time_rounding diff --git a/tests/test_scorecard.py b/tests/test_scorecard.py index 2630dc0..a4aed27 100644 --- a/tests/test_scorecard.py +++ b/tests/test_scorecard.py @@ -63,6 +63,26 @@ def test_params(): estimator=estimator, intercept_based=1) scorecard.fit(X, y) + with raises(ValueError): + scorecard = Scorecard(binning_process=binning_process, + estimator=estimator, + scaling_method=None, rounding=True) + scorecard.fit(X, y) + + with raises(ValueError): + scorecard = Scorecard(binning_process=binning_process, + estimator=estimator, scaling_method="min_max", + scaling_method_params={'min': 1.1, 'max': 10}, + rounding=True) + scorecard.fit(X, y) + + with raises(ValueError): + scorecard = Scorecard(binning_process=binning_process, + estimator=estimator, scaling_method="min_max", + scaling_method_params={'min': 1, 'max': 10.1}, + rounding=True) + scorecard.fit(X, y) + with raises(TypeError): scorecard = Scorecard(binning_process=binning_process, estimator=estimator, reverse_scorecard=1) @@ -296,7 +316,7 @@ def test_rounding(): binning_process = BinningProcess(variable_names) estimator = LogisticRegression() - scaling_method_params = {"min": 200.52, "max": 850.66} + scaling_method_params = {"min": 200, "max": 851} scorecard = Scorecard(binning_process=binning_process, estimator=estimator, scaling_method="min_max",