diff --git a/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp new file mode 100644 index 0000000000..9ba0623341 --- /dev/null +++ b/src/mlpack/methods/decision_tree/decision_tree_regressor_impl.hpp @@ -0,0 +1,427 @@ +/** + * @file methods/decision_tree/decision_tree_regressor_impl.hpp + * @author Rishabh Garg + * + * Implementation of decision tree regressor class. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef MLPACK_METHODS_DECISION_TREE_DECISION_TREE_REGRESSOR_IMPL_HPP +#define MLPACK_METHODS_DECISION_TREE_DECISION_TREE_REGRESSOR_IMPL_HPP + +#include "decision_tree_regressor.hpp" + +namespace mlpack { +namespace tree { + +//! Construct, don't train. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +DecisionTreeRegressor::DecisionTreeRegressor() : + splitDimension(0), + dimensionTypeOrMajorityClass(0), + classProbabilities(numClasses) +{ + // Initialize utility vector. + classProbabilities.fill(1.0 / (double) numClasses); +} + +//! Construct and train without weight. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +template +DecisionTreeRegressor::DecisionTreeRegressor( + MatType data, + const data::DatasetInfo& datasetInfo, + LabelsType labels, + const size_t minimumLeafSize, + const double minimumGainSplit, + const size_t maximumDepth, + DimensionSelectionType dimensionSelector) +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + + // Set the correct dimensionality for the dimension selector. + dimensionSelector.Dimensions() = tmpData.n_rows; + + // Pass off work to the Train() method. + arma::rowvec weights; // Fake weights, not used. + Train(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, numClasses, + weights, minimumLeafSize, minimumGainSplit, maximumDepth, + dimensionSelector); +} + +//! Construct and train without weight on numeric data. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +template +DecisionTreeRegressor::DecisionTreeRegressor( + MatType data, + LabelsType labels, + const size_t minimumLeafSize, + const double minimumGainSplit, + const size_t maximumDepth, + DimensionSelectionType dimensionSelector) +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + + // Set the correct dimensionality for the dimension selector. + dimensionSelector.Dimensions() = tmpData.n_rows; + + // Pass off work to the Train() method. + arma::rowvec weights; // Fake weights, not used. + Train(tmpData, 0, tmpData.n_cols, tmpLabels, numClasses, weights, + minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector); +} + +//! Construct and train with weights. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +template +DecisionTreeRegressor::DecisionTreeRegressor( + MatType data, + const data::DatasetInfo& datasetInfo, + LabelsType labels, + WeightsType weights, + const size_t minimumLeafSize, + const double minimumGainSplit, + const size_t maximumDepth, + DimensionSelectionType dimensionSelector, + const std::enable_if_t::type>::value>*) +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + using TrueWeightsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + TrueWeightsType tmpWeights(std::move(weights)); + + // Set the correct dimensionality for the dimension selector. + dimensionSelector.Dimensions() = tmpData.n_rows; + + // Pass off work to the weighted Train() method. + Train(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, numClasses, + tmpWeights, minimumLeafSize, minimumGainSplit, maximumDepth, + dimensionSelector); +} + +//! Construct and train on numeric data with weights. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +template +DecisionTreeRegressor::DecisionTreeRegressor( + MatType data, + LabelsType labels, + WeightsType weights, + const size_t minimumLeafSize, + const double minimumGainSplit, + const size_t maximumDepth, + DimensionSelectionType dimensionSelector, + const std::enable_if_t< + arma::is_arma_type< + typename std::remove_reference< + WeightsType>::type>::value>*) +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + using TrueWeightsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + TrueWeightsType tmpWeights(std::move(weights)); + + // Set the correct dimensionality for the dimension selector. + dimensionSelector.Dimensions() = tmpData.n_rows; + + // Pass off work to the weighted Train() method. + Train(tmpData, 0, tmpData.n_cols, tmpLabels, numClasses, tmpWeights, + minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector); +} + +//! Take ownership of another tree and train with weights. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +template +DecisionTreeRegressor::DecisionTreeRegressor( + const DecisionTreeRegressor& other, + MatType data, + const data::DatasetInfo& datasetInfo, + LabelsType labels, + const size_t numClasses, + WeightsType weights, + const size_t minimumLeafSize, + const double minimumGainSplit, + const std::enable_if_t::type>::value>*): + NumericAuxiliarySplitInfo(other), + CategoricalAuxiliarySplitInfo(other) +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + using TrueWeightsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + TrueWeightsType tmpWeights(std::move(weights)); + + // Pass off work to the weighted Train() method. + Train(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, numClasses, + tmpWeights, minimumLeafSize, minimumGainSplit); +} + +//! Take ownership of another tree and train with weights. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +template +DecisionTreeRegressor::DecisionTreeRegressor( + const DecisionTreeRegressor& other, + MatType data, + LabelsType labels, + WeightsType weights, + const size_t minimumLeafSize, + const double minimumGainSplit, + const size_t maximumDepth, + DimensionSelectionType dimensionSelector, + const std::enable_if_t::type>::value>*): + NumericAuxiliarySplitInfo(other), + CategoricalAuxiliarySplitInfo(other) // other info does need to copy +{ + using TrueMatType = typename std::decay::type; + using TrueLabelsType = typename std::decay::type; + using TrueWeightsType = typename std::decay::type; + + // Copy or move data. + TrueMatType tmpData(std::move(data)); + TrueLabelsType tmpLabels(std::move(labels)); + TrueWeightsType tmpWeights(std::move(weights)); + + // Set the correct dimensionality for the dimension selector. + dimensionSelector.Dimensions() = tmpData.n_rows; + + // Pass off work to the weighted Train() method. + Train(tmpData, 0, tmpData.n_cols, tmpLabels, numClasses, tmpWeights, + minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector); +} + +//! Copy another tree. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +DecisionTreeRegressor::DecisionTreeRegressor( + const DecisionTreeRegressor& other) : + NumericAuxiliarySplitInfo(other), + CategoricalAuxiliarySplitInfo(other), + splitDimension(other.splitDimension), + dimensionTypeOrMajorityClass(other.dimensionTypeOrMajorityClass), + classProbabilities(other.classProbabilities) +{ + // Copy each child. + for (size_t i = 0; i < other.children.size(); ++i) + children.push_back(new DecisionTreeRegressor(*other.children[i])); +} + +//! Take ownership of another tree. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +DecisionTreeRegressor::DecisionTreeRegressor( + DecisionTreeRegressor&& other) : + NumericAuxiliarySplitInfo(std::move(other)), + CategoricalAuxiliarySplitInfo(std::move(other)), + children(std::move(other.children)), + splitDimension(other.splitDimension), + dimensionTypeOrMajorityClass(other.dimensionTypeOrMajorityClass), + classProbabilities(std::move(other.classProbabilities)) +{ + // Reset the other object. + other.classProbabilities.ones(1); // One class, P(1) = 1. +} + +//! Copy another tree. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +DecisionTreeRegressor& +DecisionTreeRegressor::operator=(const DecisionTreeRegressor& other) +{ + if (this == &other) + return *this; // Nothing to copy. + + // Clean memory if needed. + for (size_t i = 0; i < children.size(); ++i) + delete children[i]; + children.clear(); + + // Copy everything from the other tree. + splitDimension = other.splitDimension; + dimensionTypeOrMajorityClass = other.dimensionTypeOrMajorityClass; + classProbabilities = other.classProbabilities; + + // Copy the children. + for (size_t i = 0; i < other.children.size(); ++i) + children.push_back(new DecisionTree(*other.children[i])); + + // Copy the auxiliary info. + NumericAuxiliarySplitInfo::operator=(other); + CategoricalAuxiliarySplitInfo::operator=(other); + + return *this; +} + +//! Take ownership of another tree. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +DecisionTreeRegressor& +DecisionTreeRegressor::operator=(DecisionTreeRegressor&& other) +{ + if (this == &other) + return *this; // Nothing to move. + + // Clean memory if needed. + for (size_t i = 0; i < children.size(); ++i) + delete children[i]; + children.clear(); + + // Take ownership of the other tree's components. + children = std::move(other.children); + splitDimension = other.splitDimension; + dimensionTypeOrMajorityClass = other.dimensionTypeOrMajorityClass; + classProbabilities = std::move(other.classProbabilities); + + // Reset the class probabilities of the other object. + other.classProbabilities.ones(1); // One class, P(1) = 1. + + // Take ownership of the auxiliary info. + NumericAuxiliarySplitInfo::operator=(std::move(other)); + CategoricalAuxiliarySplitInfo::operator=(std::move(other)); + + return *this; +} + +//! Clean up memory. +template class NumericSplitType, + template class CategoricalSplitType, + typename DimensionSelectionType, + bool NoRecursion> +DecisionTreeRegressor::~DecisionTreeRegressor() +{ + for (size_t i = 0; i < children.size(); ++i) + delete children[i]; +} + + +} // namespace tree +} // namespace mlpack + +#endif