From 0858305c77b7fda169e3c51d8c518afdd3672aec Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Tue, 13 Jul 2021 14:23:22 +0530 Subject: [PATCH 01/13] Made FitnessFunction::Evaluate a non-static member function. --- .../all_categorical_split_impl.hpp | 4 +- .../best_binary_numeric_split_impl.hpp | 6 +- .../decision_tree_regressor_impl.hpp | 8 ++- src/mlpack/methods/decision_tree/mad_gain.hpp | 12 ++-- src/mlpack/methods/decision_tree/mse_gain.hpp | 12 ++-- .../random_binary_numeric_split_impl.hpp | 6 +- .../tests/decision_tree_regressor_test.cpp | 61 ++++++++++++------- 7 files changed, 69 insertions(+), 40 deletions(-) diff --git a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp index cda19da51f..1256436f79 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp @@ -127,6 +127,8 @@ double AllCategoricalSplit::SplitIfBetter( double& splitInfo, AuxiliarySplitInfo& /* aux */) { + FitnessFunction fitnessFunction; + // Count the number of elements in each potential child. const double epsilon = 1e-7; // Tolerance for floating-point errors. arma::Col counts(numCategories, arma::fill::zeros); @@ -190,7 +192,7 @@ double AllCategoricalSplit::SplitIfBetter( const double childPct = UseWeights ? double(childWeightSums[i]) / sumWeight : double(counts[i]) / double(data.n_elem); - const double childGain = FitnessFunction::template Evaluate( + const double childGain = fitnessFunction.template Evaluate( childResponses[i], childWeights[i]); overallGain += childPct * childGain; diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp index 0f20f97145..7ece8f3f9a 100644 --- a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp @@ -205,6 +205,8 @@ BestBinaryNumericSplit::SplitIfBetter( typedef typename ResponsesType::elem_type RType; typedef typename WeightVecType::elem_type WType; + FitnessFunction fitnessFunction; + // First sanity check: if we don't have enough points, we can't split. if (data.n_elem < (minimumLeafSize * 2)) return DBL_MAX; @@ -270,9 +272,9 @@ BestBinaryNumericSplit::SplitIfBetter( continue; // Calculate the gain for the left and right child. - const double leftGain = FitnessFunction::template + const double leftGain = fitnessFunction.template Evaluate(sortedResponses, sortedWeights, 0, index); - const double rightGain = FitnessFunction::template + const double rightGain = fitnessFunction.template Evaluate(sortedResponses, sortedWeights, index, responses.n_elem); diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp index 31a63fedd0..5e0b7339ca 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -607,6 +607,8 @@ double DecisionTreeRegressor( + double bestGain = fitnessFunction.template Evaluate( responses.subvec(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); size_t bestDim = datasetInfo.Dimensionality(); // This means "no split". @@ -786,6 +788,8 @@ double DecisionTreeRegressor( + double bestGain = fitnessFunction.template Evaluate( responses.subvec(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); size_t bestDim = data.n_rows; // This means "no split". diff --git a/src/mlpack/methods/decision_tree/mad_gain.hpp b/src/mlpack/methods/decision_tree/mad_gain.hpp index 5e2e519dc4..56c5087306 100644 --- a/src/mlpack/methods/decision_tree/mad_gain.hpp +++ b/src/mlpack/methods/decision_tree/mad_gain.hpp @@ -43,10 +43,10 @@ class MADGain * @param end End index. */ template - static double Evaluate(const VecType& values, - const WeightVecType& weights, - const size_t begin, - const size_t end) + double Evaluate(const VecType& values, + const WeightVecType& weights, + const size_t begin, + const size_t end) { double mad = 0.0; @@ -89,8 +89,8 @@ class MADGain * @param weights Weights associated to each value. */ template - static double Evaluate(const VecType& values, - const WeightVecType& weights) + double Evaluate(const VecType& values, + const WeightVecType& weights) { // Corner case: if there are no elements, the impurity is zero. if (values.n_elem == 0) diff --git a/src/mlpack/methods/decision_tree/mse_gain.hpp b/src/mlpack/methods/decision_tree/mse_gain.hpp index 2516351d80..e4e9c0ff3b 100644 --- a/src/mlpack/methods/decision_tree/mse_gain.hpp +++ b/src/mlpack/methods/decision_tree/mse_gain.hpp @@ -41,10 +41,10 @@ class MSEGain * @param end End index. */ template - static double Evaluate(const VecType& values, - const WeightVecType& weights, - const size_t begin, - const size_t end) + double Evaluate(const VecType& values, + const WeightVecType& weights, + const size_t begin, + const size_t end) { double mse = 0.0; @@ -85,8 +85,8 @@ class MSEGain * @param weights Weights associated to each value. */ template - static double Evaluate(const VecType& values, - const WeightVecType& weights) + double Evaluate(const VecType& values, + const WeightVecType& weights) { // Corner case: if there are no elements, the impurity is zero. if (values.n_elem == 0) diff --git a/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp b/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp index 4d459798b1..a9f03396dc 100644 --- a/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp @@ -151,6 +151,8 @@ double RandomBinaryNumericSplit::SplitIfBetter( AuxiliarySplitInfo& /* aux */, const bool splitIfBetterGain) { + FitnessFunction fitnessFunction; + double bestFoundGain = std::min(bestGain + minimumGainSplit, 0.0); // Forcing a minimum leaf size of 1 (empty children don't make sense). const size_t minimum = std::max(minimumLeafSize, (size_t) 1); @@ -230,9 +232,9 @@ double RandomBinaryNumericSplit::SplitIfBetter( } // Calculate the gain for the left and right child. - const double leftGain = FitnessFunction::template + const double leftGain = fitnessFunction.template Evaluate(leftResponses, leftWeights, 0, leftLeafSize); - const double rightGain = FitnessFunction::template + const double rightGain = fitnessFunction.template Evaluate(rightResponses, rightWeights, 0, rightLeafSize); // Calculate the gain at this split point. diff --git a/src/mlpack/tests/decision_tree_regressor_test.cpp b/src/mlpack/tests/decision_tree_regressor_test.cpp index cafde0cc4d..c7909aaeab 100644 --- a/src/mlpack/tests/decision_tree_regressor_test.cpp +++ b/src/mlpack/tests/decision_tree_regressor_test.cpp @@ -77,7 +77,8 @@ TEST_CASE("MSEGainPerfectTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; responses.ones(10); - REQUIRE(MSEGain::Evaluate(responses, weights) == + MSEGain Gain; + REQUIRE(Gain.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } @@ -88,10 +89,12 @@ TEST_CASE("MSEGainEmptyTest", "[DecisionTreeRegressorTest]") { arma::rowvec weights = arma::ones(10); arma::rowvec responses; - REQUIRE(MSEGain::Evaluate(responses, weights) == + + MSEGain Gain; + REQUIRE(Gain.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); - REQUIRE(MSEGain::Evaluate(responses, weights) == + REQUIRE(Gain.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } @@ -107,9 +110,11 @@ TEST_CASE("MSEGainHandCalculation", "[DecisionTreeRegressorTest]") // Hand calculated gain values. const double gain = -27.08999; const double weightedGain = -27.53960; - REQUIRE(MSEGain::Evaluate(responses, weights) == + + MSEGain Gain; + REQUIRE(Gain.Evaluate(responses, weights) == Approx(gain).margin(1e-5)); - REQUIRE(MSEGain::Evaluate(responses, weights) == + REQUIRE(Gain.Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); } @@ -122,7 +127,8 @@ TEST_CASE("MADGainPerfectTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; responses.ones(10); - REQUIRE(MADGain::Evaluate(responses, weights) == + MADGain Gain; + REQUIRE(Gain.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } @@ -142,8 +148,8 @@ TEST_CASE("MADGainNormalTest", "[DecisionTreeRegressorTest") theoreticalGain /= (double) responses.n_elem; // Calculated gain. - const double calculatedGain = - MADGain::Evaluate(responses, weights); + MADGain Gain; + const double calculatedGain = Gain.Evaluate(responses, weights); REQUIRE(calculatedGain == Approx(theoreticalGain).margin(1e-5)); } @@ -155,10 +161,12 @@ TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]") { arma::rowvec weights = arma::ones(10); arma::rowvec responses; - REQUIRE(MADGain::Evaluate(responses, weights) == + + MADGain Gain; + REQUIRE(Gain.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); - REQUIRE(MADGain::Evaluate(responses, weights) == + REQUIRE(Gain.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } @@ -174,9 +182,11 @@ TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]") // Hand calculated gain values. const double gain = -4.1; const double weightedGain = -3.8592; - REQUIRE(MADGain::Evaluate(responses, weights) == + + MADGain Gain; + REQUIRE(Gain.Evaluate(responses, weights) == Approx(gain).margin(1e-5)); - REQUIRE(MADGain::Evaluate(responses, weights) == + REQUIRE(Gain.Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); } @@ -203,7 +213,8 @@ TEST_CASE("AllCategoricalSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( bestGain, predictor, 2, responses, weights, 3, 1e-7, splitInfo, aux); const double weightedGain = @@ -234,7 +245,8 @@ TEST_CASE("AllCategoricalSplitMinSamplesTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( bestGain, predictors, 4, responses, weights, 4, 1e-7, splitInfo, aux); @@ -265,7 +277,8 @@ TEST_CASE("AllCategoricalSplitNoGainTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( bestGain, predictors, 10, responses, weights, 10, 1e-7, splitInfo, aux); @@ -296,7 +309,8 @@ TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_", BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MADGain::Evaluate(responses, weights); + MADGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux); const double weightedGain = @@ -332,7 +346,8 @@ TEST_CASE("BestBinaryNumericSplitMinSamplesTest_", BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( bestGain, predictors, responses, weights, 8, 1e-7, splitInfo, aux); // This should make no difference because it won't split at all. @@ -366,7 +381,8 @@ TEST_CASE("BestBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux); @@ -390,7 +406,8 @@ TEST_CASE("RandomBinaryNumericSplitAlwaysSplit_", RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux); const double weightedGain = @@ -417,7 +434,8 @@ TEST_CASE("RandomBinaryNumericSplitMinSamplesTest_", RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( bestGain, values, responses, weights, 8, 1e-7, splitInfo, aux); // This should make no difference because it won't split at all. @@ -451,7 +469,8 @@ TEST_CASE("RandomBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::Evaluate(responses, weights); + MSEGain Gain; + const double bestGain = Gain.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, true); From 78845cadf5fa0161d929b62a33661eb72cbadb04 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 14 Jul 2021 18:47:46 +0530 Subject: [PATCH 02/13] Add FitnessFunction as parameter to private Train functions --- .../methods/decision_tree/decision_tree_regressor.hpp | 6 ++++-- .../decision_tree/decision_tree_regressor_impl.hpp | 10 ++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp index 6ad75adc05..0bb619ea1c 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp @@ -488,7 +488,8 @@ class DecisionTreeRegressor : const size_t minimumLeafSize, const double minimumGainSplit, const size_t maximumDepth, - DimensionSelectionType& dimensionSelector); + DimensionSelectionType& dimensionSelector, + FitnessFunction fitnessFunction = FitnessFunction()); /** * Corresponding to the public Train() method, this method is designed for @@ -514,7 +515,8 @@ class DecisionTreeRegressor : const size_t minimumLeafSize, const double minimumGainSplit, const size_t maximumDepth, - DimensionSelectionType& dimensionSelector); + DimensionSelectionType& dimensionSelector, + FitnessFunction fitnessFunction = FitnessFunction()); }; diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp index 5e0b7339ca..278789c316 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -605,10 +605,9 @@ double DecisionTreeRegressor Date: Wed, 14 Jul 2021 19:00:07 +0530 Subject: [PATCH 03/13] Add FitnessFunction as parameter to SplitIfBetter --- .../decision_tree/all_categorical_split.hpp | 3 +- .../all_categorical_split_impl.hpp | 5 ++- .../best_binary_numeric_split.hpp | 6 ++-- .../best_binary_numeric_split_impl.hpp | 10 +++--- .../decision_tree_regressor_impl.hpp | 9 +++-- .../random_binary_numeric_split.hpp | 1 + .../random_binary_numeric_split_impl.hpp | 3 +- .../tests/decision_tree_regressor_test.cpp | 34 +++++++++++-------- 8 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/mlpack/methods/decision_tree/all_categorical_split.hpp b/src/mlpack/methods/decision_tree/all_categorical_split.hpp index 13911887a9..b604729a00 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split.hpp @@ -103,7 +103,8 @@ class AllCategoricalSplit const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& aux); + AuxiliarySplitInfo& aux, + FitnessFunction fitnessFunction); /** * Return the number of children in the split. diff --git a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp index 1256436f79..25ca80a858 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp @@ -125,10 +125,9 @@ double AllCategoricalSplit::SplitIfBetter( const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& /* aux */) + AuxiliarySplitInfo& /* aux */, + FitnessFunction fitnessFunction) { - FitnessFunction fitnessFunction; - // Count the number of elements in each potential child. const double epsilon = 1e-7; // Tolerance for floating-point errors. arma::Col counts(numCategories, arma::fill::zeros); diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp index a39ac91d8f..4b51055705 100644 --- a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp +++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp @@ -118,7 +118,8 @@ class BestBinaryNumericSplit const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& aux); + AuxiliarySplitInfo& aux, + FitnessFunction fitnessFunction); /** * Check if we can split a node. If we can split a node in a way that @@ -154,7 +155,8 @@ class BestBinaryNumericSplit const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& /* aux */); + AuxiliarySplitInfo& /* aux */, + FitnessFunction fitnessFunction); /** * Returns 2, since the binary split always has two children. diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp index 7ece8f3f9a..de06768c65 100644 --- a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp @@ -200,13 +200,12 @@ BestBinaryNumericSplit::SplitIfBetter( const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& /* aux */) + AuxiliarySplitInfo& /* aux */, + FitnessFunction fitnessFunction) { typedef typename ResponsesType::elem_type RType; typedef typename WeightVecType::elem_type WType; - FitnessFunction fitnessFunction; - // First sanity check: if we don't have enough points, we can't split. if (data.n_elem < (minimumLeafSize * 2)) return DBL_MAX; @@ -340,13 +339,12 @@ BestBinaryNumericSplit::SplitIfBetter( const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& /* aux */) + AuxiliarySplitInfo& /* aux */, + FitnessFunction fitnessFunction) { typedef typename ResponsesType::elem_type RType; typedef typename WeightVecType::elem_type WType; - FitnessFunction fitnessFunction; - // First sanity check: if we don't have enough points, we can't split. if (data.n_elem < (minimumLeafSize * 2)) return DBL_MAX; diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp index 278789c316..b10f089c7c 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -640,7 +640,8 @@ double DecisionTreeRegressor::SplitIfBetter( const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, + FitnessFunction fitnessFunction, const bool splitIfBetterGain) { - FitnessFunction fitnessFunction; - double bestFoundGain = std::min(bestGain + minimumGainSplit, 0.0); // Forcing a minimum leaf size of 1 (empty children don't make sense). const size_t minimum = std::max(minimumLeafSize, (size_t) 1); diff --git a/src/mlpack/tests/decision_tree_regressor_test.cpp b/src/mlpack/tests/decision_tree_regressor_test.cpp index c7909aaeab..da158bc462 100644 --- a/src/mlpack/tests/decision_tree_regressor_test.cpp +++ b/src/mlpack/tests/decision_tree_regressor_test.cpp @@ -216,10 +216,11 @@ TEST_CASE("AllCategoricalSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]") MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( - bestGain, predictor, 2, responses, weights, 3, 1e-7, splitInfo, aux); + bestGain, predictor, 2, responses, weights, 3, 1e-7, splitInfo, aux, + Gain); const double weightedGain = AllCategoricalSplit::SplitIfBetter(bestGain, predictor, 2, - responses, weights, 3, 1e-7, splitInfo, aux); + responses, weights, 3, 1e-7, splitInfo, aux, Gain); // Make sure that a split was made. REQUIRE(gain > bestGain); @@ -248,7 +249,8 @@ TEST_CASE("AllCategoricalSplitMinSamplesTest_", "[DecisionTreeRegressorTest]") MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( - bestGain, predictors, 4, responses, weights, 4, 1e-7, splitInfo, aux); + bestGain, predictors, 4, responses, weights, 4, 1e-7, splitInfo, aux, + Gain); // Make sure it's not split. REQUIRE(gain == DBL_MAX); @@ -281,10 +283,10 @@ TEST_CASE("AllCategoricalSplitNoGainTest_", "[DecisionTreeRegressorTest]") const double bestGain = Gain.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( bestGain, predictors, 10, responses, weights, 10, 1e-7, - splitInfo, aux); + splitInfo, aux, Gain); const double weightedGain = AllCategoricalSplit::SplitIfBetter(bestGain, predictors, - 10, responses, weights, 10, 1e-7, splitInfo, aux); + 10, responses, weights, 10, 1e-7, splitInfo, aux, Gain); // Make sure that there was no split. REQUIRE(gain == DBL_MAX); @@ -312,10 +314,10 @@ TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_", MADGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( - bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux); + bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux, Gain); const double weightedGain = BestBinaryNumericSplit::SplitIfBetter(bestGain, predictors, - responses, weights, 3, 1e-7, splitInfo, aux); + responses, weights, 3, 1e-7, splitInfo, aux, Gain); // Make sure that a split was made. REQUIRE(gain > bestGain); @@ -349,11 +351,11 @@ TEST_CASE("BestBinaryNumericSplitMinSamplesTest_", MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( - bestGain, predictors, responses, weights, 8, 1e-7, splitInfo, aux); + bestGain, predictors, responses, weights, 8, 1e-7, splitInfo, aux, Gain); // This should make no difference because it won't split at all. const double weightedGain = BestBinaryNumericSplit::SplitIfBetter(bestGain, - predictors, responses, weights, 8, 1e-7, splitInfo, aux); + predictors, responses, weights, 8, 1e-7, splitInfo, aux, Gain); // Make sure that no split was made. REQUIRE(gain == DBL_MAX); @@ -384,7 +386,8 @@ TEST_CASE("BestBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( - bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux); + bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux, + Gain); // Make sure there was no split. REQUIRE(gain == DBL_MAX); @@ -409,10 +412,10 @@ TEST_CASE("RandomBinaryNumericSplitAlwaysSplit_", MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( - bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux); + bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux, Gain); const double weightedGain = RandomBinaryNumericSplit::SplitIfBetter(bestGain, values, - responses, weights, 1, 1e-7, splitInfo, aux); + responses, weights, 1, 1e-7, splitInfo, aux, Gain); // Make sure that split was made. REQUIRE(gain != DBL_MAX); @@ -437,11 +440,11 @@ TEST_CASE("RandomBinaryNumericSplitMinSamplesTest_", MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( - bestGain, values, responses, weights, 8, 1e-7, splitInfo, aux); + bestGain, values, responses, weights, 8, 1e-7, splitInfo, aux, Gain); // This should make no difference because it won't split at all. const double weightedGain = RandomBinaryNumericSplit::SplitIfBetter(bestGain, values, - responses, weights, 8, 1e-7, splitInfo, aux); + responses, weights, 8, 1e-7, splitInfo, aux, Gain); // Make sure that no split was made. REQUIRE(gain == DBL_MAX); @@ -472,7 +475,8 @@ TEST_CASE("RandomBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") MSEGain Gain; const double bestGain = Gain.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( - bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, true); + bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, Gain, + true); // Make sure there was no split. REQUIRE(gain == DBL_MAX); From 52f4886efc9c883937fb03eb6ce2c2e24672dae9 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 14 Jul 2021 19:12:04 +0530 Subject: [PATCH 04/13] Add FitnessFunction as parameter to public Train functions --- .../decision_tree/decision_tree_regressor.hpp | 8 ++++++-- .../decision_tree_regressor_impl.hpp | 16 ++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp index 0bb619ea1c..f244fbf9f8 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp @@ -286,7 +286,8 @@ class DecisionTreeRegressor : const double minimumGainSplit = 1e-7, const size_t maximumDepth = 0, DimensionSelectionType dimensionSelector = - DimensionSelectionType()); + DimensionSelectionType(), + FitnessFunction fitnessFunction = FitnessFunction()); /** * Train the decision tree on the given data, assuming that all dimensions are @@ -311,7 +312,8 @@ class DecisionTreeRegressor : const double minimumGainSplit = 1e-7, const size_t maximumDepth = 0, DimensionSelectionType dimensionSelector = - DimensionSelectionType()); + DimensionSelectionType(), + FitnessFunction fitnessFunction = FitnessFunction()); /** * Train the decision tree on the given weighted data. This will overwrite @@ -343,6 +345,7 @@ class DecisionTreeRegressor : const size_t maximumDepth = 0, DimensionSelectionType dimensionSelector = DimensionSelectionType(), + FitnessFunction fitnessFunction = FitnessFunction(), const std::enable_if_t::type>::value>* = 0); @@ -373,6 +376,7 @@ class DecisionTreeRegressor : const size_t maximumDepth = 0, DimensionSelectionType dimensionSelector = DimensionSelectionType(), + FitnessFunction fitnessFunction = FitnessFunction(), const std::enable_if_t::type>::value>* = 0); diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp index b10f089c7c..e798f1c107 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -432,7 +432,8 @@ double DecisionTreeRegressor(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses, weights, minimumLeafSize, minimumGainSplit, maximumDepth, - dimensionSelector); + dimensionSelector, fitnessFunction); } //! Train on the given data, assuming all dimensions are numeric. @@ -471,7 +472,8 @@ double DecisionTreeRegressor(tmpData, 0, tmpData.n_cols, tmpResponses, weights, minimumLeafSize, minimumGainSplit, maximumDepth, - dimensionSelector); + dimensionSelector, fitnessFunction); } //! Train on the given weighted data. @@ -513,6 +515,7 @@ double DecisionTreeRegressor(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses, tmpWeights, minimumLeafSize, minimumGainSplit, maximumDepth, - dimensionSelector); + dimensionSelector, fitnessFunction); } //! Train on the given weighted all numeric data. @@ -558,6 +561,7 @@ double DecisionTreeRegressor(tmpData, 0, tmpData.n_cols, tmpResponses, tmpWeights, minimumLeafSize, minimumGainSplit, maximumDepth, - dimensionSelector); + dimensionSelector, fitnessFunction); } //! Train on the given data. From f43a51b58d0af2c596c3e1e12f74f6b0237f72e1 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 14 Jul 2021 20:06:22 +0530 Subject: [PATCH 05/13] DecisionTreeRegressor::CalculatePrediction() => FitnessFunction::OutputLeafValue() --- .../decision_tree/decision_tree_regressor.hpp | 7 --- .../decision_tree_regressor_impl.hpp | 47 ++++--------------- src/mlpack/methods/decision_tree/mad_gain.hpp | 22 +++++++++ src/mlpack/methods/decision_tree/mse_gain.hpp | 22 +++++++++ 4 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp index f244fbf9f8..6dfd53ecf4 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp @@ -459,13 +459,6 @@ class DecisionTreeRegressor : typedef typename CategoricalSplit::AuxiliarySplitInfo CategoricalAuxiliarySplitInfo; - /** - * Calculate the prediction value for the leaf nodes. - */ - template - void CalculatePrediction(const ResponsesType& responses, - const WeightsType& weights); - /** * Corresponding to the public Train() method, this method is designed for * avoiding unnecessary copies during training. This function is called to diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp index e798f1c107..ba87d0a74d 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -762,10 +762,11 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), - UseWeights ? weights.subvec(begin, begin + count - 1) : weights); + // Calculate prediction value because we are a leaf. + splitPointOrPrediction = + fitnessFunction.template OutputLeafValue( + responses.subvec(begin, begin + count - 1), + UseWeights ? weights.subvec(begin, begin + count - 1) : weights); } return -bestGain; @@ -916,10 +917,11 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), - UseWeights ? weights.subvec(begin, begin + count - 1) : weights); + // Calculate prediction value because we are a leaf. + splitPointOrPrediction = + fitnessFunction.template OutputLeafValue( + responses.subvec(begin, begin + count - 1), + UseWeights ? weights.subvec(begin, begin + count - 1) : weights); } return -bestGain; @@ -974,35 +976,6 @@ void DecisionTreeRegressor class NumericSplitType, - template class CategoricalSplitType, - typename DimensionSelectionType, - bool NoRecursion> -template -void DecisionTreeRegressor::CalculatePrediction(const ResponsesType& responses, - const WeightsType& weights) -{ - if (UseWeights) - { - double accWeights, weightedSum; - WeightedSum(responses, weights, 0, responses.n_elem, accWeights, - weightedSum); - splitPointOrPrediction = weightedSum / accWeights; - } - else - { - double sum; - Sum(responses, 0, responses.n_elem, sum); - splitPointOrPrediction = sum / responses.n_elem; - } -} - template class NumericSplitType, template class CategoricalSplitType, diff --git a/src/mlpack/methods/decision_tree/mad_gain.hpp b/src/mlpack/methods/decision_tree/mad_gain.hpp index 56c5087306..d73ecba4cc 100644 --- a/src/mlpack/methods/decision_tree/mad_gain.hpp +++ b/src/mlpack/methods/decision_tree/mad_gain.hpp @@ -98,6 +98,28 @@ class MADGain return Evaluate(values, weights, 0, values.n_elem); } + + /** + * Calculates the output value for each leaf node for prediction. + */ + template + double OutputLeafValue(const ResponsesType& responses, + const WeightsType& weights) + { + if (UseWeights) + { + double accWeights, weightedSum; + WeightedSum(responses, weights, 0, responses.n_elem, accWeights, + weightedSum); + return weightedSum / accWeights; + } + else + { + double sum; + Sum(responses, 0, responses.n_elem, sum); + return sum / responses.n_elem; + } + } }; } // namespace tree diff --git a/src/mlpack/methods/decision_tree/mse_gain.hpp b/src/mlpack/methods/decision_tree/mse_gain.hpp index e4e9c0ff3b..af1368881b 100644 --- a/src/mlpack/methods/decision_tree/mse_gain.hpp +++ b/src/mlpack/methods/decision_tree/mse_gain.hpp @@ -95,6 +95,28 @@ class MSEGain return Evaluate(values, weights, 0, values.n_elem); } + /** + * Calculates the output value for each leaf node for prediction. + */ + template + double OutputLeafValue(const ResponsesType& responses, + const WeightsType& weights) + { + if (UseWeights) + { + double accWeights, weightedSum; + WeightedSum(responses, weights, 0, responses.n_elem, accWeights, + weightedSum); + return weightedSum / accWeights; + } + else + { + double sum; + Sum(responses, 0, responses.n_elem, sum); + return sum / responses.n_elem; + } + } + /** * Calculates the mean squared error gain for the left and right children * for the current index. From 708eb5cfadf14e06bf7b1d2c3c168121b81225a7 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Thu, 15 Jul 2021 23:55:18 +0530 Subject: [PATCH 06/13] Change responses.subvec() to responses.cols(). --- .../decision_tree/decision_tree_regressor_impl.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp index ba87d0a74d..029a5ff57c 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -623,7 +623,7 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); size_t bestDim = datasetInfo.Dimensionality(); // This means "no split". const size_t end = dimensionSelector.End(); @@ -639,7 +639,7 @@ double DecisionTreeRegressor(bestGain, data.cols(begin, begin + count - 1).row(i), datasetInfo.NumMappings(i), - responses.subvec(begin, begin + count - 1), + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights, minimumLeafSize, minimumGainSplit, @@ -651,7 +651,7 @@ double DecisionTreeRegressor(bestGain, data.cols(begin, begin + count - 1).row(i), - responses.subvec(begin, begin + count - 1), + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights, minimumLeafSize, minimumGainSplit, @@ -765,7 +765,7 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); } @@ -808,7 +808,7 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); size_t bestDim = data.n_rows; // This means "no split". @@ -920,7 +920,7 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); } From 7cfe63adf217d77ae0a3037b0ce5da8601b649cd Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Mon, 19 Jul 2021 21:12:47 +0530 Subject: [PATCH 07/13] Pass reference to FitnessFunctions Co-authored-by: Ryan Curtin --- src/mlpack/methods/decision_tree/all_categorical_split.hpp | 2 +- .../methods/decision_tree/all_categorical_split_impl.hpp | 2 +- .../methods/decision_tree/best_binary_numeric_split.hpp | 4 ++-- .../methods/decision_tree/best_binary_numeric_split_impl.hpp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mlpack/methods/decision_tree/all_categorical_split.hpp b/src/mlpack/methods/decision_tree/all_categorical_split.hpp index b604729a00..3dc9e096c6 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split.hpp @@ -104,7 +104,7 @@ class AllCategoricalSplit const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& aux, - FitnessFunction fitnessFunction); + FitnessFunction& fitnessFunction); /** * Return the number of children in the split. diff --git a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp index 25ca80a858..b09727a16b 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp @@ -126,7 +126,7 @@ double AllCategoricalSplit::SplitIfBetter( const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, - FitnessFunction fitnessFunction) + FitnessFunction& fitnessFunction) { // Count the number of elements in each potential child. const double epsilon = 1e-7; // Tolerance for floating-point errors. diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp index 4b51055705..c84f8e04bd 100644 --- a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp +++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp @@ -119,7 +119,7 @@ class BestBinaryNumericSplit const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& aux, - FitnessFunction fitnessFunction); + FitnessFunction& fitnessFunction); /** * Check if we can split a node. If we can split a node in a way that @@ -156,7 +156,7 @@ class BestBinaryNumericSplit const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, - FitnessFunction fitnessFunction); + FitnessFunction& fitnessFunction); /** * Returns 2, since the binary split always has two children. diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp index de06768c65..ba9a5147af 100644 --- a/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split_impl.hpp @@ -201,7 +201,7 @@ BestBinaryNumericSplit::SplitIfBetter( const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, - FitnessFunction fitnessFunction) + FitnessFunction& fitnessFunction) { typedef typename ResponsesType::elem_type RType; typedef typename WeightVecType::elem_type WType; @@ -340,7 +340,7 @@ BestBinaryNumericSplit::SplitIfBetter( const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, - FitnessFunction fitnessFunction) + FitnessFunction& fitnessFunction) { typedef typename ResponsesType::elem_type RType; typedef typename WeightVecType::elem_type WType; From bd0d6c8c58917fc47ace2b3ff8eb65731cfae2e7 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Mon, 19 Jul 2021 21:16:05 +0530 Subject: [PATCH 08/13] Apply suggestions from code review Co-authored-by: Ryan Curtin --- .../methods/decision_tree/random_binary_numeric_split.hpp | 2 +- .../methods/decision_tree/random_binary_numeric_split_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp b/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp index 6329c2bcd2..9078c8b858 100644 --- a/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp +++ b/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp @@ -121,7 +121,7 @@ class RandomBinaryNumericSplit const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& aux, - FitnessFunction fitnessFunction, + FitnessFunction& fitnessFunction, const bool splitIfBetterGain = false); /** diff --git a/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp b/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp index aab94ff6f8..677d9816f7 100644 --- a/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/random_binary_numeric_split_impl.hpp @@ -149,7 +149,7 @@ double RandomBinaryNumericSplit::SplitIfBetter( const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, - FitnessFunction fitnessFunction, + FitnessFunction& fitnessFunction, const bool splitIfBetterGain) { double bestFoundGain = std::min(bestGain + minimumGainSplit, 0.0); From 89c3d85f6e35ccf0f9f0fde699486cd67dc1f658 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Mon, 19 Jul 2021 21:26:53 +0530 Subject: [PATCH 09/13] Change name of fitness function instance in tests --- .../tests/decision_tree_regressor_test.cpp | 116 ++++++++---------- 1 file changed, 51 insertions(+), 65 deletions(-) diff --git a/src/mlpack/tests/decision_tree_regressor_test.cpp b/src/mlpack/tests/decision_tree_regressor_test.cpp index da158bc462..25df7a3e0e 100644 --- a/src/mlpack/tests/decision_tree_regressor_test.cpp +++ b/src/mlpack/tests/decision_tree_regressor_test.cpp @@ -77,9 +77,8 @@ TEST_CASE("MSEGainPerfectTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; responses.ones(10); - MSEGain Gain; - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + MSEGain f; + REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } /** @@ -90,12 +89,9 @@ TEST_CASE("MSEGainEmptyTest", "[DecisionTreeRegressorTest]") arma::rowvec weights = arma::ones(10); arma::rowvec responses; - MSEGain Gain; - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); - - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + MSEGain f; + REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); + REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } /** @@ -111,10 +107,9 @@ TEST_CASE("MSEGainHandCalculation", "[DecisionTreeRegressorTest]") const double gain = -27.08999; const double weightedGain = -27.53960; - MSEGain Gain; - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(gain).margin(1e-5)); - REQUIRE(Gain.Evaluate(responses, weights) == + MSEGain f; + REQUIRE(f.Evaluate(responses, weights) == Approx(gain).margin(1e-5)); + REQUIRE(f.Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); } @@ -127,9 +122,8 @@ TEST_CASE("MADGainPerfectTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; responses.ones(10); - MADGain Gain; - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + MADGain f; + REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } /** @@ -148,8 +142,8 @@ TEST_CASE("MADGainNormalTest", "[DecisionTreeRegressorTest") theoreticalGain /= (double) responses.n_elem; // Calculated gain. - MADGain Gain; - const double calculatedGain = Gain.Evaluate(responses, weights); + MADGain f; + const double calculatedGain = f.Evaluate(responses, weights); REQUIRE(calculatedGain == Approx(theoreticalGain).margin(1e-5)); } @@ -162,12 +156,9 @@ TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]") arma::rowvec weights = arma::ones(10); arma::rowvec responses; - MADGain Gain; - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); - - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + MADGain f; + REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); + REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } /** @@ -183,10 +174,9 @@ TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]") const double gain = -4.1; const double weightedGain = -3.8592; - MADGain Gain; - REQUIRE(Gain.Evaluate(responses, weights) == - Approx(gain).margin(1e-5)); - REQUIRE(Gain.Evaluate(responses, weights) == + MADGain f; + REQUIRE(f.Evaluate(responses, weights) == Approx(gain).margin(1e-5)); + REQUIRE(f.Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); } @@ -213,14 +203,13 @@ TEST_CASE("AllCategoricalSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( - bestGain, predictor, 2, responses, weights, 3, 1e-7, splitInfo, aux, - Gain); + bestGain, predictor, 2, responses, weights, 3, 1e-7, splitInfo, aux, f); const double weightedGain = AllCategoricalSplit::SplitIfBetter(bestGain, predictor, 2, - responses, weights, 3, 1e-7, splitInfo, aux, Gain); + responses, weights, 3, 1e-7, splitInfo, aux, f); // Make sure that a split was made. REQUIRE(gain > bestGain); @@ -246,11 +235,10 @@ TEST_CASE("AllCategoricalSplitMinSamplesTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( - bestGain, predictors, 4, responses, weights, 4, 1e-7, splitInfo, aux, - Gain); + bestGain, predictors, 4, responses, weights, 4, 1e-7, splitInfo, aux, f); // Make sure it's not split. REQUIRE(gain == DBL_MAX); @@ -279,14 +267,14 @@ TEST_CASE("AllCategoricalSplitNoGainTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = AllCategoricalSplit::SplitIfBetter( bestGain, predictors, 10, responses, weights, 10, 1e-7, - splitInfo, aux, Gain); + splitInfo, aux, f); const double weightedGain = AllCategoricalSplit::SplitIfBetter(bestGain, predictors, - 10, responses, weights, 10, 1e-7, splitInfo, aux, Gain); + 10, responses, weights, 10, 1e-7, splitInfo, aux, f); // Make sure that there was no split. REQUIRE(gain == DBL_MAX); @@ -311,13 +299,13 @@ TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_", BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MADGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MADGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( - bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux, Gain); + bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux, f); const double weightedGain = BestBinaryNumericSplit::SplitIfBetter(bestGain, predictors, - responses, weights, 3, 1e-7, splitInfo, aux, Gain); + responses, weights, 3, 1e-7, splitInfo, aux, f); // Make sure that a split was made. REQUIRE(gain > bestGain); @@ -348,14 +336,14 @@ TEST_CASE("BestBinaryNumericSplitMinSamplesTest_", BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( - bestGain, predictors, responses, weights, 8, 1e-7, splitInfo, aux, Gain); + bestGain, predictors, responses, weights, 8, 1e-7, splitInfo, aux, f); // This should make no difference because it won't split at all. const double weightedGain = BestBinaryNumericSplit::SplitIfBetter(bestGain, - predictors, responses, weights, 8, 1e-7, splitInfo, aux, Gain); + predictors, responses, weights, 8, 1e-7, splitInfo, aux, f); // Make sure that no split was made. REQUIRE(gain == DBL_MAX); @@ -383,11 +371,10 @@ TEST_CASE("BestBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = BestBinaryNumericSplit::SplitIfBetter( - bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux, - Gain); + bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux, f); // Make sure there was no split. REQUIRE(gain == DBL_MAX); @@ -409,13 +396,13 @@ TEST_CASE("RandomBinaryNumericSplitAlwaysSplit_", RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( - bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux, Gain); + bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux, f); const double weightedGain = RandomBinaryNumericSplit::SplitIfBetter(bestGain, values, - responses, weights, 1, 1e-7, splitInfo, aux, Gain); + responses, weights, 1, 1e-7, splitInfo, aux, f); // Make sure that split was made. REQUIRE(gain != DBL_MAX); @@ -437,14 +424,14 @@ TEST_CASE("RandomBinaryNumericSplitMinSamplesTest_", RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( - bestGain, values, responses, weights, 8, 1e-7, splitInfo, aux, Gain); + bestGain, values, responses, weights, 8, 1e-7, splitInfo, aux, f); // This should make no difference because it won't split at all. const double weightedGain = RandomBinaryNumericSplit::SplitIfBetter(bestGain, values, - responses, weights, 8, 1e-7, splitInfo, aux, Gain); + responses, weights, 8, 1e-7, splitInfo, aux, f); // Make sure that no split was made. REQUIRE(gain == DBL_MAX); @@ -472,11 +459,10 @@ TEST_CASE("RandomBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - MSEGain Gain; - const double bestGain = Gain.Evaluate(responses, weights); + MSEGain f; + const double bestGain = f.Evaluate(responses, weights); const double gain = RandomBinaryNumericSplit::SplitIfBetter( - bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, Gain, - true); + bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, f, true); // Make sure there was no split. REQUIRE(gain == DBL_MAX); From 7a771b4e5a3b821dc25c99bb0c9b1f38145f941d Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Tue, 20 Jul 2021 21:07:22 +0530 Subject: [PATCH 10/13] Made MADGain::Evaluate static --- src/mlpack/methods/decision_tree/mad_gain.hpp | 12 +++++------ .../tests/decision_tree_regressor_test.cpp | 20 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/mlpack/methods/decision_tree/mad_gain.hpp b/src/mlpack/methods/decision_tree/mad_gain.hpp index d73ecba4cc..e915b41825 100644 --- a/src/mlpack/methods/decision_tree/mad_gain.hpp +++ b/src/mlpack/methods/decision_tree/mad_gain.hpp @@ -43,10 +43,10 @@ class MADGain * @param end End index. */ template - double Evaluate(const VecType& values, - const WeightVecType& weights, - const size_t begin, - const size_t end) + static double Evaluate(const VecType& values, + const WeightVecType& weights, + const size_t begin, + const size_t end) { double mad = 0.0; @@ -89,8 +89,8 @@ class MADGain * @param weights Weights associated to each value. */ template - double Evaluate(const VecType& values, - const WeightVecType& weights) + static double Evaluate(const VecType& values, + const WeightVecType& weights) { // Corner case: if there are no elements, the impurity is zero. if (values.n_elem == 0) diff --git a/src/mlpack/tests/decision_tree_regressor_test.cpp b/src/mlpack/tests/decision_tree_regressor_test.cpp index 25df7a3e0e..ce32f90ed8 100644 --- a/src/mlpack/tests/decision_tree_regressor_test.cpp +++ b/src/mlpack/tests/decision_tree_regressor_test.cpp @@ -122,8 +122,8 @@ TEST_CASE("MADGainPerfectTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; responses.ones(10); - MADGain f; - REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); + REQUIRE(MADGain::Evaluate(responses, weights) == + Approx(0.0).margin(1e-5)); } /** @@ -142,8 +142,7 @@ TEST_CASE("MADGainNormalTest", "[DecisionTreeRegressorTest") theoreticalGain /= (double) responses.n_elem; // Calculated gain. - MADGain f; - const double calculatedGain = f.Evaluate(responses, weights); + const double calculatedGain = MADGain::Evaluate(responses, weights); REQUIRE(calculatedGain == Approx(theoreticalGain).margin(1e-5)); } @@ -156,9 +155,10 @@ TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]") arma::rowvec weights = arma::ones(10); arma::rowvec responses; - MADGain f; - REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); - REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); + REQUIRE(MADGain::Evaluate(responses, weights) == + Approx(0.0).margin(1e-5)); + REQUIRE(MADGain::Evaluate(responses, weights) == + Approx(0.0).margin(1e-5)); } /** @@ -174,9 +174,9 @@ TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]") const double gain = -4.1; const double weightedGain = -3.8592; - MADGain f; - REQUIRE(f.Evaluate(responses, weights) == Approx(gain).margin(1e-5)); - REQUIRE(f.Evaluate(responses, weights) == + REQUIRE(MADGain::Evaluate(responses, weights) == + Approx(gain).margin(1e-5)); + REQUIRE(MADGain::Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); } From a4081bf0c8029f70b1a9d0a36851d3285fccd43d Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Thu, 22 Jul 2021 10:56:28 +0530 Subject: [PATCH 11/13] Improved documentation. --- src/mlpack/methods/decision_tree/mad_gain.hpp | 4 +++- src/mlpack/methods/decision_tree/mse_gain.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/decision_tree/mad_gain.hpp b/src/mlpack/methods/decision_tree/mad_gain.hpp index e915b41825..49f0223716 100644 --- a/src/mlpack/methods/decision_tree/mad_gain.hpp +++ b/src/mlpack/methods/decision_tree/mad_gain.hpp @@ -100,7 +100,9 @@ class MADGain } /** - * Calculates the output value for each leaf node for prediction. + * Returns the output value for each leaf node for prediction. The output + * value is calculated as the average of all the points in that leaf node. + * This calculation is specific to regression trees only. */ template double OutputLeafValue(const ResponsesType& responses, diff --git a/src/mlpack/methods/decision_tree/mse_gain.hpp b/src/mlpack/methods/decision_tree/mse_gain.hpp index af1368881b..5cc8876625 100644 --- a/src/mlpack/methods/decision_tree/mse_gain.hpp +++ b/src/mlpack/methods/decision_tree/mse_gain.hpp @@ -96,7 +96,9 @@ class MSEGain } /** - * Calculates the output value for each leaf node for prediction. + * Returns the output value for each leaf node for prediction. The output + * value is calculated as the average of all the points in that leaf node. + * This calculation is specific to regression trees only. */ template double OutputLeafValue(const ResponsesType& responses, From 1db1c7e64dae24a2f9c7f92b6f4db5b5aac71eae Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Sat, 24 Jul 2021 17:43:20 +0530 Subject: [PATCH 12/13] Add documentation for fitnessFunnction Parameter --- .../methods/decision_tree/all_categorical_split.hpp | 2 ++ .../decision_tree/best_binary_numeric_split.hpp | 2 ++ .../decision_tree/decision_tree_regressor.hpp | 12 ++++++++++++ .../decision_tree/random_binary_numeric_split.hpp | 2 ++ 4 files changed, 18 insertions(+) diff --git a/src/mlpack/methods/decision_tree/all_categorical_split.hpp b/src/mlpack/methods/decision_tree/all_categorical_split.hpp index 3dc9e096c6..2b2c5d71e5 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split.hpp @@ -91,6 +91,8 @@ class AllCategoricalSplit * @param minimumGainSplit Minimum gain split. * @param aux Auxiliary split information, which may be modified on a * successful split. + * @param fitnessFunction The FitnessFunction object instance. It it used to + * evaluate the gain for the split. */ template diff --git a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp index c84f8e04bd..b966b44f38 100644 --- a/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp +++ b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp @@ -104,6 +104,8 @@ class BestBinaryNumericSplit * @param splitInfo Stores split information on a successful split. * @param aux Auxiliary split information, which may be modified on a * successful split. + * @param fitnessFunction The FitnessFunction object instance. It it used to + * evaluate the gain for the split. */ template diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp index 6dfd53ecf4..8611a319bc 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp @@ -276,6 +276,8 @@ class DecisionTreeRegressor : * @param minimumGainSplit Minimum gain for the node to split. * @param maximumDepth Maximum depth for the tree. * @param dimensionSelector Instantiated dimension selection policy. + * @param fitnessFunction Instantiated fitnessFunction. It is used to + * evaluate the fitness score for splitting each node. * @return The final entropy of decision tree. */ template @@ -303,6 +305,8 @@ class DecisionTreeRegressor : * @param minimumGainSplit Minimum gain for the node to split. * @param maximumDepth Maximum depth for the tree. * @param dimensionSelector Instantiated dimension selection policy. + * @param fitnessFunction Instantiated fitnessFunction. It is used to + * evaluate the fitness score for splitting each node. * @return The final entropy of decision tree. */ template @@ -333,6 +337,8 @@ class DecisionTreeRegressor : * @param minimumGainSplit Minimum gain for the node to split. * @param maximumDepth Maximum depth for the tree. * @param dimensionSelector Instantiated dimension selection policy. + * @param fitnessFunction Instantiated fitnessFunction. It is used to + * evaluate the fitness score for splitting each node. * @return The final entropy of decision tree. */ template @@ -365,6 +371,8 @@ class DecisionTreeRegressor : * @param minimumGainSplit Minimum gain for the node to split. * @param maximumDepth Maximum depth for the tree. * @param dimensionSelector Instantiated dimension selection policy. + * @param fitnessFunction Instantiated fitnessFunction. It is used to + * evaluate the fitness score for splitting each node. * @return The final entropy of decision tree. */ template @@ -473,6 +481,8 @@ class DecisionTreeRegressor : * @param minimumLeafSize Minimum number of points in each leaf node. * @param minimumGainSplit Minimum gain for the node to split. * @param maximumDepth Maximum depth for the tree. + * @param fitnessFunction Instantiated fitnessFunction. It is used to + * evaluate the fitness score for splitting each node. * @return The final entropy of decision tree. */ template @@ -501,6 +511,8 @@ class DecisionTreeRegressor : * @param minimumLeafSize Minimum number of points in each leaf node. * @param minimumGainSplit Minimum gain for the node to split. * @param maximumDepth Maximum depth for the tree. + * @param fitnessFunction Instantiated fitnessFunction. It is used to + * evaluate the fitness score for splitting each node. * @return The final entropy of decision tree. */ template diff --git a/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp b/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp index 9078c8b858..eef24fd5b5 100644 --- a/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp +++ b/src/mlpack/methods/decision_tree/random_binary_numeric_split.hpp @@ -107,6 +107,8 @@ class RandomBinaryNumericSplit * @param splitInfo Stores split information on a successful split. * @param aux Auxiliary split information, which may be modified on a * successful split. + * @param fitnessFunction The FitnessFunction object instance. It it used to + * evaluate the gain for the split. * @param splitIfBetterGain When set to true, it will split only when gain is * better than the current best gain. Otherwise, it always makes a * split regardless of gain. From 91c609af89ef313a92dcfb724e72cb883f2b1f2e Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Tue, 27 Jul 2021 08:42:50 +0530 Subject: [PATCH 13/13] Made MSEGain::Evaluate static function --- src/mlpack/methods/decision_tree/mse_gain.hpp | 12 ++++----- .../tests/decision_tree_regressor_test.cpp | 25 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/mlpack/methods/decision_tree/mse_gain.hpp b/src/mlpack/methods/decision_tree/mse_gain.hpp index 5cc8876625..8f46a9bf11 100644 --- a/src/mlpack/methods/decision_tree/mse_gain.hpp +++ b/src/mlpack/methods/decision_tree/mse_gain.hpp @@ -41,10 +41,10 @@ class MSEGain * @param end End index. */ template - double Evaluate(const VecType& values, - const WeightVecType& weights, - const size_t begin, - const size_t end) + static double Evaluate(const VecType& values, + const WeightVecType& weights, + const size_t begin, + const size_t end) { double mse = 0.0; @@ -85,8 +85,8 @@ class MSEGain * @param weights Weights associated to each value. */ template - double Evaluate(const VecType& values, - const WeightVecType& weights) + static double Evaluate(const VecType& values, + const WeightVecType& weights) { // Corner case: if there are no elements, the impurity is zero. if (values.n_elem == 0) diff --git a/src/mlpack/tests/decision_tree_regressor_test.cpp b/src/mlpack/tests/decision_tree_regressor_test.cpp index ce32f90ed8..df810b0f36 100644 --- a/src/mlpack/tests/decision_tree_regressor_test.cpp +++ b/src/mlpack/tests/decision_tree_regressor_test.cpp @@ -77,8 +77,8 @@ TEST_CASE("MSEGainPerfectTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; responses.ones(10); - MSEGain f; - REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); + REQUIRE(MSEGain::Evaluate(responses, weights) == + Approx(0.0).margin(1e-5)); } /** @@ -89,9 +89,10 @@ TEST_CASE("MSEGainEmptyTest", "[DecisionTreeRegressorTest]") arma::rowvec weights = arma::ones(10); arma::rowvec responses; - MSEGain f; - REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); - REQUIRE(f.Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); + REQUIRE(MSEGain::Evaluate(responses, weights) == + Approx(0.0).margin(1e-5)); + REQUIRE(MSEGain::Evaluate(responses, weights) == + Approx(0.0).margin(1e-5)); } /** @@ -107,9 +108,9 @@ TEST_CASE("MSEGainHandCalculation", "[DecisionTreeRegressorTest]") const double gain = -27.08999; const double weightedGain = -27.53960; - MSEGain f; - REQUIRE(f.Evaluate(responses, weights) == Approx(gain).margin(1e-5)); - REQUIRE(f.Evaluate(responses, weights) == + REQUIRE(MSEGain::Evaluate(responses, weights) == + Approx(gain).margin(1e-5)); + REQUIRE(MSEGain::Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); } @@ -123,7 +124,7 @@ TEST_CASE("MADGainPerfectTest", "[DecisionTreeRegressorTest]") responses.ones(10); REQUIRE(MADGain::Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + Approx(0.0).margin(1e-5)); } /** @@ -156,9 +157,9 @@ TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]") arma::rowvec responses; REQUIRE(MADGain::Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + Approx(0.0).margin(1e-5)); REQUIRE(MADGain::Evaluate(responses, weights) == - Approx(0.0).margin(1e-5)); + Approx(0.0).margin(1e-5)); } /** @@ -175,7 +176,7 @@ TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]") const double weightedGain = -3.8592; REQUIRE(MADGain::Evaluate(responses, weights) == - Approx(gain).margin(1e-5)); + Approx(gain).margin(1e-5)); REQUIRE(MADGain::Evaluate(responses, weights) == Approx(weightedGain).margin(1e-5)); }