diff --git a/src/mlpack/methods/decision_tree/all_categorical_split.hpp b/src/mlpack/methods/decision_tree/all_categorical_split.hpp index 13911887a9..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 @@ -103,7 +105,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 cda19da51f..b09727a16b 100644 --- a/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp +++ b/src/mlpack/methods/decision_tree/all_categorical_split_impl.hpp @@ -125,7 +125,8 @@ double AllCategoricalSplit::SplitIfBetter( const size_t minimumLeafSize, const double minimumGainSplit, double& splitInfo, - AuxiliarySplitInfo& /* aux */) + AuxiliarySplitInfo& /* aux */, + FitnessFunction& fitnessFunction) { // Count the number of elements in each potential child. const double epsilon = 1e-7; // Tolerance for floating-point errors. @@ -190,7 +191,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.hpp b/src/mlpack/methods/decision_tree/best_binary_numeric_split.hpp index a39ac91d8f..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 @@ -118,7 +120,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 +157,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 0f20f97145..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 @@ -200,7 +200,8 @@ 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; @@ -270,9 +271,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); @@ -338,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.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor.hpp index 6ad75adc05..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 @@ -286,7 +288,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 @@ -302,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 @@ -311,7 +316,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 @@ -331,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 @@ -343,6 +351,7 @@ class DecisionTreeRegressor : const size_t maximumDepth = 0, DimensionSelectionType dimensionSelector = DimensionSelectionType(), + FitnessFunction fitnessFunction = FitnessFunction(), const std::enable_if_t::type>::value>* = 0); @@ -362,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 @@ -373,6 +384,7 @@ class DecisionTreeRegressor : const size_t maximumDepth = 0, DimensionSelectionType dimensionSelector = DimensionSelectionType(), + FitnessFunction fitnessFunction = FitnessFunction(), const std::enable_if_t::type>::value>* = 0); @@ -455,13 +467,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 @@ -476,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 @@ -488,7 +495,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 @@ -503,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 @@ -514,7 +524,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 31a63fedd0..029a5ff57c 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. @@ -605,7 +609,8 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), + double bestGain = fitnessFunction.template Evaluate( + 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(); @@ -634,23 +639,25 @@ 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, splitPointOrPrediction, - *this); + *this, + fitnessFunction); } else if (datasetInfo.Type(i) == data::Datatype::numeric) { dimGain = NumericSplit::template SplitIfBetter(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, splitPointOrPrediction, - *this); + *this, + fitnessFunction); } // If the splitter reported that it did not split, move to the next @@ -755,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.cols(begin, begin + count - 1), + UseWeights ? weights.subvec(begin, begin + count - 1) : weights); } return -bestGain; @@ -784,7 +792,8 @@ double DecisionTreeRegressor( - responses.subvec(begin, begin + count - 1), + double bestGain = fitnessFunction.template Evaluate( + responses.cols(begin, begin + count - 1), UseWeights ? weights.subvec(begin, begin + count - 1) : weights); size_t bestDim = data.n_rows; // This means "no split". @@ -818,7 +827,8 @@ 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.cols(begin, begin + count - 1), + UseWeights ? weights.subvec(begin, begin + count - 1) : weights); } return -bestGain; @@ -965,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 5e2e519dc4..49f0223716 100644 --- a/src/mlpack/methods/decision_tree/mad_gain.hpp +++ b/src/mlpack/methods/decision_tree/mad_gain.hpp @@ -98,6 +98,30 @@ class MADGain return Evaluate(values, weights, 0, values.n_elem); } + + /** + * 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, + 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 2516351d80..8f46a9bf11 100644 --- a/src/mlpack/methods/decision_tree/mse_gain.hpp +++ b/src/mlpack/methods/decision_tree/mse_gain.hpp @@ -95,6 +95,30 @@ class MSEGain return Evaluate(values, weights, 0, values.n_elem); } + /** + * 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, + 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. 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 9d86c69e12..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. @@ -121,6 +123,7 @@ class RandomBinaryNumericSplit const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& aux, + 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 4d459798b1..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,6 +149,7 @@ double RandomBinaryNumericSplit::SplitIfBetter( const double minimumGainSplit, double& splitInfo, AuxiliarySplitInfo& /* aux */, + FitnessFunction& fitnessFunction, const bool splitIfBetterGain) { double bestFoundGain = std::min(bestGain + minimumGainSplit, 0.0); @@ -230,9 +231,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..df810b0f36 100644 --- a/src/mlpack/tests/decision_tree_regressor_test.cpp +++ b/src/mlpack/tests/decision_tree_regressor_test.cpp @@ -88,9 +88,9 @@ TEST_CASE("MSEGainEmptyTest", "[DecisionTreeRegressorTest]") { arma::rowvec weights = arma::ones(10); arma::rowvec responses; + REQUIRE(MSEGain::Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); - REQUIRE(MSEGain::Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } @@ -107,6 +107,7 @@ TEST_CASE("MSEGainHandCalculation", "[DecisionTreeRegressorTest]") // Hand calculated gain values. const double gain = -27.08999; const double weightedGain = -27.53960; + REQUIRE(MSEGain::Evaluate(responses, weights) == Approx(gain).margin(1e-5)); REQUIRE(MSEGain::Evaluate(responses, weights) == @@ -142,8 +143,7 @@ TEST_CASE("MADGainNormalTest", "[DecisionTreeRegressorTest") theoreticalGain /= (double) responses.n_elem; // Calculated gain. - const double calculatedGain = - MADGain::Evaluate(responses, weights); + const double calculatedGain = MADGain::Evaluate(responses, weights); REQUIRE(calculatedGain == Approx(theoreticalGain).margin(1e-5)); } @@ -155,9 +155,9 @@ TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]") { arma::rowvec weights = arma::ones(10); arma::rowvec responses; + REQUIRE(MADGain::Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); - REQUIRE(MADGain::Evaluate(responses, weights) == Approx(0.0).margin(1e-5)); } @@ -174,6 +174,7 @@ TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]") // Hand calculated gain values. const double gain = -4.1; const double weightedGain = -3.8592; + REQUIRE(MADGain::Evaluate(responses, weights) == Approx(gain).margin(1e-5)); REQUIRE(MADGain::Evaluate(responses, weights) == @@ -203,12 +204,13 @@ TEST_CASE("AllCategoricalSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + 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); + responses, weights, 3, 1e-7, splitInfo, aux, f); // Make sure that a split was made. REQUIRE(gain > bestGain); @@ -234,9 +236,10 @@ TEST_CASE("AllCategoricalSplitMinSamplesTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + bestGain, predictors, 4, responses, weights, 4, 1e-7, splitInfo, aux, f); // Make sure it's not split. REQUIRE(gain == DBL_MAX); @@ -265,13 +268,14 @@ TEST_CASE("AllCategoricalSplitNoGainTest_", "[DecisionTreeRegressorTest]") AllCategoricalSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + splitInfo, aux, f); const double weightedGain = AllCategoricalSplit::SplitIfBetter(bestGain, predictors, - 10, responses, weights, 10, 1e-7, splitInfo, aux); + 10, responses, weights, 10, 1e-7, splitInfo, aux, f); // Make sure that there was no split. REQUIRE(gain == DBL_MAX); @@ -296,12 +300,13 @@ TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_", BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MADGain::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); + bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux, f); const double weightedGain = BestBinaryNumericSplit::SplitIfBetter(bestGain, predictors, - responses, weights, 3, 1e-7, splitInfo, aux); + responses, weights, 3, 1e-7, splitInfo, aux, f); // Make sure that a split was made. REQUIRE(gain > bestGain); @@ -332,13 +337,14 @@ TEST_CASE("BestBinaryNumericSplitMinSamplesTest_", BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + 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); + predictors, responses, weights, 8, 1e-7, splitInfo, aux, f); // Make sure that no split was made. REQUIRE(gain == DBL_MAX); @@ -366,9 +372,10 @@ TEST_CASE("BestBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") BestBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux, f); // Make sure there was no split. REQUIRE(gain == DBL_MAX); @@ -390,12 +397,13 @@ TEST_CASE("RandomBinaryNumericSplitAlwaysSplit_", RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux, f); const double weightedGain = RandomBinaryNumericSplit::SplitIfBetter(bestGain, values, - responses, weights, 1, 1e-7, splitInfo, aux); + responses, weights, 1, 1e-7, splitInfo, aux, f); // Make sure that split was made. REQUIRE(gain != DBL_MAX); @@ -417,13 +425,14 @@ TEST_CASE("RandomBinaryNumericSplitMinSamplesTest_", RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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); + 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); + responses, weights, 8, 1e-7, splitInfo, aux, f); // Make sure that no split was made. REQUIRE(gain == DBL_MAX); @@ -451,9 +460,10 @@ TEST_CASE("RandomBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]") RandomBinaryNumericSplit::AuxiliarySplitInfo aux; // Call the method to do the splitting. - const double bestGain = MSEGain::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, true); + bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, f, true); // Make sure there was no split. REQUIRE(gain == DBL_MAX);