Changed labels to responses throughtout regression tree codebase
This commit is contained in:
@@ -74,8 +74,8 @@ class BestBinaryNumericSplit
|
||||
* @param bestGain Best gain seen so far (we'll only split if we find gain
|
||||
* better than this).
|
||||
* @param data The dimension of data points to check for a split in.
|
||||
* @param labels Labels for each point.
|
||||
* @param weights Weights associated with labels.
|
||||
* @param responses Responses for each point.
|
||||
* @param weights Weights associated with responses.
|
||||
* @param minimumLeafSize Minimum number of points in a leaf node for
|
||||
* splitting.
|
||||
* @param minimumGainSplit Minimum gain split.
|
||||
@@ -87,7 +87,7 @@ class BestBinaryNumericSplit
|
||||
static double SplitIfBetter(
|
||||
const double bestGain,
|
||||
const VecType& data,
|
||||
const arma::Row<double>& labels,
|
||||
const arma::rowvec& responses,
|
||||
const WeightVecType& weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
|
||||
@@ -189,7 +189,7 @@ template<bool UseWeights, typename VecType, typename WeightVecType>
|
||||
double BestBinaryNumericSplit<FitnessFunction>::SplitIfBetter(
|
||||
const double bestGain,
|
||||
const VecType& data,
|
||||
const arma::Row<double>& labels,
|
||||
const arma::rowvec& responses,
|
||||
const WeightVecType& weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -204,10 +204,10 @@ double BestBinaryNumericSplit<FitnessFunction>::SplitIfBetter(
|
||||
|
||||
// Next, sort the data.
|
||||
arma::uvec sortedIndices = arma::sort_index(data);
|
||||
arma::Row<double> sortedLabels(labels.n_elem);
|
||||
arma::rowvec sortedResponses(responses.n_elem);
|
||||
arma::rowvec sortedWeights;
|
||||
for (size_t i = 0; i < sortedLabels.n_elem; ++i)
|
||||
sortedLabels[i] = labels[sortedIndices[i]];
|
||||
for (size_t i = 0; i < sortedResponses.n_elem; ++i)
|
||||
sortedResponses[i] = responses[sortedIndices[i]];
|
||||
|
||||
// Sanity check: if the first element is the same as the last, we can't split
|
||||
// in this dimension.
|
||||
@@ -217,9 +217,9 @@ double BestBinaryNumericSplit<FitnessFunction>::SplitIfBetter(
|
||||
// Only initialize if we are using weights.
|
||||
if (UseWeights)
|
||||
{
|
||||
sortedWeights.set_size(sortedLabels.n_elem);
|
||||
// The weights must keep the same order as the labels.
|
||||
for (size_t i = 0; i < sortedLabels.n_elem; ++i)
|
||||
sortedWeights.set_size(sortedResponses.n_elem);
|
||||
// The weights must keep the same order as the responses.
|
||||
for (size_t i = 0; i < sortedResponses.n_elem; ++i)
|
||||
sortedWeights[i] = weights[sortedIndices[i]];
|
||||
}
|
||||
|
||||
@@ -260,16 +260,18 @@ double BestBinaryNumericSplit<FitnessFunction>::SplitIfBetter(
|
||||
if (data[sortedIndices[index]] == data[sortedIndices[index - 1]])
|
||||
continue;
|
||||
|
||||
/* TODO: The following function calculates the gain for each split each time from scratch
|
||||
This can be greatly improved using advanced techniques like prefix sum and
|
||||
prefix sum of squares etc. This will have drastic effects on runtime and is
|
||||
definitely something we would want in future.
|
||||
/* TODO: The following function calculates the gain for each split each
|
||||
time from scratch. This can be greatly improved using advanced
|
||||
techniques like prefix sum and prefix sum of squares etc. This
|
||||
will have drastic effects on runtime and is definitely something
|
||||
we would want in future.
|
||||
*/
|
||||
// Calculate the gain for the left and right child.
|
||||
const double leftGain = FitnessFunction::template Evaluate<UseWeights>(sortedLabels,
|
||||
sortedWeights, 0, index);
|
||||
const double rightGain = FitnessFunction::template Evaluate<UseWeights>(sortedLabels,
|
||||
sortedWeights, index, labels.n_elem);
|
||||
const double leftGain = FitnessFunction::template
|
||||
Evaluate<UseWeights>(sortedResponses, sortedWeights, 0, index);
|
||||
const double rightGain = FitnessFunction::template
|
||||
Evaluate<UseWeights>(sortedResponses, sortedWeights, index,
|
||||
responses.n_elem);
|
||||
|
||||
double gain;
|
||||
if (UseWeights)
|
||||
@@ -280,7 +282,7 @@ double BestBinaryNumericSplit<FitnessFunction>::SplitIfBetter(
|
||||
{
|
||||
// Calculate the gain at this split point.
|
||||
gain = double(index) * leftGain +
|
||||
double(sortedLabels.n_elem - index) * rightGain;
|
||||
double(sortedResponses.n_elem - index) * rightGain;
|
||||
}
|
||||
|
||||
// Corner case: is this the best possible split?
|
||||
|
||||
@@ -56,25 +56,25 @@ class DecisionTreeRegressor :
|
||||
DecisionTreeRegressor();
|
||||
|
||||
/**
|
||||
* Construct the decision tree on the given data and labels, where the data
|
||||
* can be both numeric and categorical. Setting minimumLeafSize and
|
||||
* Construct the decision tree on the given data and responses, where the
|
||||
* data can be both numeric and categorical. Setting minimumLeafSize and
|
||||
* minimumGainSplit too small may cause the tree to overfit, but setting them
|
||||
* too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data or labels are no longer needed to avoid copies.
|
||||
* Use std::move if data or responses are no longer needed to avoid copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param datasetInfo Type information for each dimension of the dataset.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
DecisionTreeRegressor(MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
@@ -82,23 +82,23 @@ class DecisionTreeRegressor :
|
||||
DimensionSelectionType());
|
||||
|
||||
/**
|
||||
* Construct the decision tree on the given data and labels, assuming that
|
||||
* Construct the decision tree on the given data and responses, assuming that
|
||||
* the data is all of the numeric type. Setting minimumLeafSize and
|
||||
* minimumGainSplit too small may cause the tree to overfit, but setting them
|
||||
* too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data or labels are no longer needed to avoid copies.
|
||||
* Use std::move if data or responses are no longer needed to avoid copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
DecisionTreeRegressor(MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
@@ -106,28 +106,28 @@ class DecisionTreeRegressor :
|
||||
DimensionSelectionType());
|
||||
|
||||
/**
|
||||
* Construct the decision tree on the given data and labels with weights,
|
||||
* Construct the decision tree on the given data and responses with weights,
|
||||
* where the data can be both numeric and categorical. Setting minimumLeafSize
|
||||
* and minimumGainSplit too small may cause the tree to overfit, but setting
|
||||
* them too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data, labels or weights are no longer needed to avoid
|
||||
* Use std::move if data, responses or weights are no longer needed to avoid
|
||||
* copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param datasetInfo Type information for each dimension of the dataset.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param weights The weight list of given label.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
@@ -137,26 +137,26 @@ class DecisionTreeRegressor :
|
||||
typename std::remove_reference<WeightsType>::type>::value>* = 0);
|
||||
|
||||
/**
|
||||
* Construct the decision tree on the given data and labels with weights,
|
||||
* Construct the decision tree on the given data and responses with weights,
|
||||
* assuming that the data is all of the numeric type. Setting minimumLeafSize
|
||||
* and minimumGainSplit too small may cause the tree to overfit, but setting
|
||||
* them too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data, labels or weights are no longer needed to avoid
|
||||
* Use std::move if data, responses or weights are no longer needed to avoid
|
||||
* copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param weights The Weight list of given labels.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
@@ -167,27 +167,28 @@ class DecisionTreeRegressor :
|
||||
|
||||
/**
|
||||
* Take ownership of another decision tree and train on the given data and
|
||||
* labels with weights, where the data can be both numeric and categorical.
|
||||
* Setting minimumLeafSize and minimumGainSplit too small may cause the
|
||||
* tree to overfit, but setting them too large may cause it to underfit.
|
||||
* responses with weights, where the data can be both numeric and
|
||||
* categorical. Setting minimumLeafSize and minimumGainSplit too small may
|
||||
* cause the tree to overfit, but setting them too large may cause it to
|
||||
* underfit.
|
||||
*
|
||||
* Use std::move if data, labels or weights are no longer needed to avoid
|
||||
* Use std::move if data, responses or weights are no longer needed to avoid
|
||||
* copies.
|
||||
*
|
||||
* @param other Tree to take ownership of.
|
||||
* @param data Dataset to train on.
|
||||
* @param datasetInfo Type information for each dimension of the dataset.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param weights The weight list of given label.
|
||||
* @param minimumLeafSize Minimum number of points in each leaf node.
|
||||
* @param minimumGainSplit Minimum gain for the node to split.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor(
|
||||
const DecisionTreeRegressor& other,
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
@@ -195,27 +196,27 @@ class DecisionTreeRegressor :
|
||||
typename std::remove_reference<WeightsType>::type>::value>* = 0);
|
||||
|
||||
/**
|
||||
* Take ownership of another decision tree and train on the given data and labels
|
||||
* with weights, assuming that the data is all of the numeric type. Setting
|
||||
* minimumLeafSize and minimumGainSplit too small may cause the tree to
|
||||
* overfit, but setting them too large may cause it to underfit.
|
||||
* Take ownership of another decision tree and train on the given data and
|
||||
* responses with weights, assuming that the data is all of the numeric type.
|
||||
* Setting minimumLeafSize and minimumGainSplit too small may cause the tree
|
||||
* to overfit, but setting them too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data, labels or weights are no longer needed to avoid
|
||||
* Use std::move if data, responses or weights are no longer needed to avoid
|
||||
* copies.
|
||||
* @param other Tree to take ownership of.
|
||||
* @param data Dataset to train on.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param weights The Weight list of given labels.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor(
|
||||
const DecisionTreeRegressor& other,
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
@@ -261,26 +262,26 @@ class DecisionTreeRegressor :
|
||||
|
||||
/**
|
||||
* Train the decision tree on the given data. This will overwrite the
|
||||
* existing model. The data may have numeric and categorical types, specified
|
||||
* existing model. The data may have numeric and categorical types, specified
|
||||
* by the datasetInfo parameter. Setting minimumLeafSize and
|
||||
* minimumGainSplit too small may cause the tree to overfit, but setting them
|
||||
* too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data or labels are no longer needed to avoid copies.
|
||||
* Use std::move if data or responses are no longer needed to avoid copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param datasetInfo Type information for each dimension.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The final entropy of decision tree.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
double Train(MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
@@ -293,19 +294,19 @@ class DecisionTreeRegressor :
|
||||
* minimumGainSplit too small may cause the tree to overfit, but setting them
|
||||
* too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data or labels are no longer needed to avoid copies.
|
||||
* Use std::move if data or responses are no longer needed to avoid copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @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 dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The final entropy of decision tree.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
double Train(MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
const size_t maximumDepth = 0,
|
||||
@@ -319,12 +320,12 @@ class DecisionTreeRegressor :
|
||||
* minimumGainSplit too small may cause the tree to overfit, but setting them
|
||||
* too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data, labels or weights are no longer needed to avoid
|
||||
* Use std::move if data, responses or weights are no longer needed to avoid
|
||||
* copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param datasetInfo Type information for each dimension.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param weights Weights of all the labels
|
||||
* @param minimumLeafSize Minimum number of points in each leaf node.
|
||||
* @param minimumGainSplit Minimum gain for the node to split.
|
||||
@@ -332,10 +333,10 @@ class DecisionTreeRegressor :
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The final entropy of decision tree.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
double Train(MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
@@ -351,11 +352,11 @@ class DecisionTreeRegressor :
|
||||
* minimumLeafSize and minimumGainSplit too small may cause the tree to
|
||||
* overfit, but setting them too large may cause it to underfit.
|
||||
*
|
||||
* Use std::move if data, labels or weights are no longer needed to avoid
|
||||
* Use std::move if data, responses or weights are no longer needed to avoid
|
||||
* copies.
|
||||
*
|
||||
* @param data Dataset to train on.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param weights Weights of all the labels
|
||||
* @param minimumLeafSize Minimum number of points in each leaf node.
|
||||
* @param minimumGainSplit Minimum gain for the node to split.
|
||||
@@ -363,9 +364,9 @@ class DecisionTreeRegressor :
|
||||
* @param dimensionSelector Instantiated dimension selection policy.
|
||||
* @return The final entropy of decision tree.
|
||||
*/
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
double Train(MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize = 10,
|
||||
const double minimumGainSplit = 1e-7,
|
||||
@@ -386,7 +387,7 @@ class DecisionTreeRegressor :
|
||||
|
||||
/**
|
||||
* Make prediction for the given points, using the entire tree. The predicted
|
||||
* labels for each point are stored in the given vector.
|
||||
* responses for each point are stored in the given vector.
|
||||
*
|
||||
* @param data Set of points to predict.
|
||||
* @param predictions This will be filled with predictions for each point.
|
||||
@@ -436,7 +437,7 @@ class DecisionTreeRegressor :
|
||||
size_t dimensionType;
|
||||
/**
|
||||
* This variable may hold different things. If the node has no children, then
|
||||
* it is guaranteed to hold the prediction label for that node. If the node
|
||||
* it is guaranteed to hold the prediction value for that node. If the node
|
||||
* has children, then it may be used arbitrarily by the split type's
|
||||
* CalculateDirection() and SplitIfBetter() function. In this case, it stores
|
||||
* the point at which the split was made.
|
||||
@@ -452,10 +453,10 @@ class DecisionTreeRegressor :
|
||||
CategoricalAuxiliarySplitInfo;
|
||||
|
||||
/**
|
||||
* Calculate the prediction label for the leaf nodes.
|
||||
* Calculate the prediction value for the leaf nodes.
|
||||
*/
|
||||
template<bool UseWeights, typename LabelsType, typename WeightsType>
|
||||
void CalculatePrediction(const LabelsType& labels,
|
||||
template<bool UseWeights, typename ResponsesType, typename WeightsType>
|
||||
void CalculatePrediction(const ResponsesType& responses,
|
||||
const WeightsType& weights);
|
||||
|
||||
/**
|
||||
@@ -468,19 +469,19 @@ class DecisionTreeRegressor :
|
||||
* this node.
|
||||
* @param count Number of points in this node.
|
||||
* @param datasetInfo Type information for each dimension.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param numClasses Number of classes in the dataset.
|
||||
* @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.
|
||||
* @return The final entropy of decision tree.
|
||||
*/
|
||||
template<bool UseWeights, typename MatType, typename LabelsType>
|
||||
template<bool UseWeights, typename MatType, typename ResponsesType>
|
||||
double Train(MatType& data,
|
||||
const size_t begin,
|
||||
const size_t count,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType& labels,
|
||||
ResponsesType& responses,
|
||||
const size_t numClasses,
|
||||
arma::rowvec& weights,
|
||||
const size_t minimumLeafSize,
|
||||
@@ -497,18 +498,18 @@ class DecisionTreeRegressor :
|
||||
* @param begin Index of the starting point in the dataset that belongs to
|
||||
* this node.
|
||||
* @param count Number of points in this node.
|
||||
* @param labels Labels for each training point.
|
||||
* @param responses Responses for each training point.
|
||||
* @param numClasses Number of classes in the dataset.
|
||||
* @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.
|
||||
* @return The final entropy of decision tree.
|
||||
*/
|
||||
template<bool UseWeights, typename MatType, typename LabelsType>
|
||||
template<bool UseWeights, typename MatType, typename ResponsesType>
|
||||
double Train(MatType& data,
|
||||
const size_t begin,
|
||||
const size_t count,
|
||||
LabelsType& labels,
|
||||
ResponsesType& responses,
|
||||
const size_t numClasses,
|
||||
arma::rowvec& weights,
|
||||
const size_t minimumLeafSize,
|
||||
|
||||
@@ -42,7 +42,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -50,25 +50,25 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
NoRecursion>::DecisionTreeRegressor(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
|
||||
// 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<false>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, 0,
|
||||
Train<false>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses, 0,
|
||||
weights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -79,32 +79,32 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
NoRecursion>::DecisionTreeRegressor(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
|
||||
// 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<false>(tmpData, 0, tmpData.n_cols, tmpLabels, 0, weights,
|
||||
Train<false>(tmpData, 0, tmpData.n_cols, tmpResponses, 0, weights,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -122,7 +122,7 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
NoRecursion>::DecisionTreeRegressor(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -132,19 +132,19 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
typename std::remove_reference<WeightsType>::type>::value>*)
|
||||
{
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
using TrueWeightsType = typename std::decay<WeightsType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
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<true>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, 0,
|
||||
Train<true>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses, 0,
|
||||
tmpWeights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -155,14 +155,14 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
NoRecursion>::DecisionTreeRegressor(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -174,19 +174,19 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
WeightsType>::type>::value>*)
|
||||
{
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
using TrueWeightsType = typename std::decay<WeightsType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
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<true>(tmpData, 0, tmpData.n_cols, tmpLabels, 0, tmpWeights,
|
||||
Train<true>(tmpData, 0, tmpData.n_cols, tmpResponses, 0, tmpWeights,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -205,7 +205,7 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
const DecisionTreeRegressor& other,
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -215,16 +215,16 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
CategoricalAuxiliarySplitInfo(other)
|
||||
{
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
using TrueWeightsType = typename std::decay<WeightsType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
TrueWeightsType tmpWeights(std::move(weights));
|
||||
|
||||
// Pass off work to the weighted Train() method.
|
||||
Train<true>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels, 0,
|
||||
Train<true>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses, 0,
|
||||
tmpWeights, minimumLeafSize, minimumGainSplit);
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -242,7 +242,7 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
NoRecursion>::DecisionTreeRegressor(
|
||||
const DecisionTreeRegressor& other,
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -255,19 +255,19 @@ DecisionTreeRegressor<FitnessFunction,
|
||||
CategoricalAuxiliarySplitInfo(other) // other info does need to copy
|
||||
{
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
using TrueWeightsType = typename std::decay<WeightsType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
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<true>(tmpData, 0, tmpData.n_cols, tmpLabels, 0, tmpWeights,
|
||||
Train<true>(tmpData, 0, tmpData.n_cols, tmpResponses, 0, tmpWeights,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth, dimensionSelector);
|
||||
}
|
||||
|
||||
@@ -421,7 +421,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
double DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -429,28 +429,28 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
// Sanity check on data.
|
||||
util::CheckSameSizes(data, labels, "DecisionTreeRegressor::Train()");
|
||||
util::CheckSameSizes(data, responses, "DecisionTreeRegressor::Train()");
|
||||
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
|
||||
// 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.
|
||||
return Train<false>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels,
|
||||
return Train<false>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses,
|
||||
0, weights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -461,35 +461,35 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType>
|
||||
template<typename MatType, typename ResponsesType>
|
||||
double DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
const size_t maximumDepth,
|
||||
DimensionSelectionType dimensionSelector)
|
||||
{
|
||||
// Sanity check on data.
|
||||
util::CheckSameSizes(data, labels, "DecisionTreeRegressor::Train()");
|
||||
util::CheckSameSizes(data, responses, "DecisionTreeRegressor::Train()");
|
||||
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
|
||||
// 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.
|
||||
return Train<false>(tmpData, 0, tmpData.n_cols, tmpLabels, 0,
|
||||
return Train<false>(tmpData, 0, tmpData.n_cols, responses, 0,
|
||||
weights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -500,7 +500,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
double DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -508,7 +508,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -520,22 +520,22 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
WeightsType>::type>::value>*)
|
||||
{
|
||||
// Sanity check on data.
|
||||
util::CheckSameSizes(data, labels, "DecisionTreeRegressor::Train()");
|
||||
util::CheckSameSizes(data, responses, "DecisionTreeRegressor::Train()");
|
||||
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
using TrueWeightsType = typename std::decay<WeightsType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
TrueWeightsType tmpWeights(std::move(weights));
|
||||
|
||||
// Set the correct dimensionality for the dimension selector.
|
||||
dimensionSelector.Dimensions() = tmpData.n_rows;
|
||||
|
||||
// Pass off work to the Train() method.
|
||||
return Train<true>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpLabels,
|
||||
return Train<true>(tmpData, 0, tmpData.n_cols, datasetInfo, tmpResponses,
|
||||
0, tmpWeights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -546,14 +546,14 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<typename MatType, typename LabelsType, typename WeightsType>
|
||||
template<typename MatType, typename ResponsesType, typename WeightsType>
|
||||
double DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
NoRecursion>::Train(
|
||||
MatType data,
|
||||
LabelsType labels,
|
||||
ResponsesType responses,
|
||||
WeightsType weights,
|
||||
const size_t minimumLeafSize,
|
||||
const double minimumGainSplit,
|
||||
@@ -565,22 +565,22 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
WeightsType>::type>::value>*)
|
||||
{
|
||||
// Sanity check on data.
|
||||
util::CheckSameSizes(data, labels, "DecisionTreeRegressor::Train()");
|
||||
util::CheckSameSizes(data, responses, "DecisionTreeRegressor::Train()");
|
||||
|
||||
using TrueMatType = typename std::decay<MatType>::type;
|
||||
using TrueLabelsType = typename std::decay<LabelsType>::type;
|
||||
using TrueResponsesType = typename std::decay<ResponsesType>::type;
|
||||
using TrueWeightsType = typename std::decay<WeightsType>::type;
|
||||
|
||||
// Copy or move data.
|
||||
TrueMatType tmpData(std::move(data));
|
||||
TrueLabelsType tmpLabels(std::move(labels));
|
||||
TrueResponsesType tmpResponses(std::move(responses));
|
||||
TrueWeightsType tmpWeights(std::move(weights));
|
||||
|
||||
// Set the correct dimensionality for the dimension selector.
|
||||
dimensionSelector.Dimensions() = tmpData.n_rows;
|
||||
|
||||
// Pass off work to the Train() method.
|
||||
return Train<true>(tmpData, 0, tmpData.n_cols, tmpLabels, 0,
|
||||
return Train<true>(tmpData, 0, tmpData.n_cols, tmpResponses, 0,
|
||||
tmpWeights, minimumLeafSize, minimumGainSplit, maximumDepth,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -591,7 +591,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<bool UseWeights, typename MatType, typename LabelsType>
|
||||
template<bool UseWeights, typename MatType, typename ResponsesType>
|
||||
double DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -601,7 +601,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
const size_t begin,
|
||||
const size_t count,
|
||||
const data::DatasetInfo& datasetInfo,
|
||||
LabelsType& labels,
|
||||
ResponsesType& responses,
|
||||
const size_t numClasses,
|
||||
arma::rowvec& weights,
|
||||
const size_t minimumLeafSize,
|
||||
@@ -618,7 +618,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
// We'll cache the best numeric and categorical split auxiliary information in
|
||||
// numericAux and categoricalAux (and clear them later if we make no split),
|
||||
double bestGain = FitnessFunction::template Evaluate<UseWeights>(
|
||||
labels.subvec(begin, begin + count - 1),
|
||||
responses.subvec(begin, begin + count - 1),
|
||||
numClasses,
|
||||
UseWeights ? weights.subvec(begin, begin + count - 1) : weights);
|
||||
size_t bestDim = datasetInfo.Dimensionality(); // This means "no split".
|
||||
@@ -635,7 +635,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
dimGain = CategoricalSplit::template SplitIfBetter<UseWeights>(bestGain,
|
||||
data.cols(begin, begin + count - 1).row(i),
|
||||
datasetInfo.NumMappings(i),
|
||||
labels.subvec(begin, begin + count - 1),
|
||||
responses.subvec(begin, begin + count - 1),
|
||||
numClasses,
|
||||
UseWeights ? weights.subvec(begin, begin + count - 1) : weights,
|
||||
minimumLeafSize,
|
||||
@@ -647,7 +647,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
{
|
||||
dimGain = NumericSplit::template SplitIfBetter<UseWeights>(bestGain,
|
||||
data.cols(begin, begin + count - 1).row(i),
|
||||
labels.subvec(begin, begin + count - 1),
|
||||
responses.subvec(begin, begin + count - 1),
|
||||
UseWeights ? weights.subvec(begin, begin + count - 1) : weights,
|
||||
minimumLeafSize,
|
||||
minimumGainSplit,
|
||||
@@ -722,7 +722,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
{
|
||||
childAssignments.swap_cols(currentCol - begin, j - begin);
|
||||
data.swap_cols(currentCol, j);
|
||||
labels.swap_cols(currentCol, j);
|
||||
responses.swap_cols(currentCol, j);
|
||||
if (UseWeights)
|
||||
weights.swap_cols(currentCol, j);
|
||||
++currentCol;
|
||||
@@ -734,7 +734,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
if (NoRecursion)
|
||||
{
|
||||
child->Train<UseWeights>(data, currentChildBegin,
|
||||
currentCol - currentChildBegin, datasetInfo, labels, numClasses,
|
||||
currentCol - currentChildBegin, datasetInfo, responses, numClasses,
|
||||
weights, currentCol - currentChildBegin, minimumGainSplit,
|
||||
maximumDepth - 1, dimensionSelector);
|
||||
}
|
||||
@@ -742,7 +742,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
{
|
||||
// During recursion entropy of child node may change.
|
||||
double childGain = child->Train<UseWeights>(data, currentChildBegin,
|
||||
currentCol - currentChildBegin, datasetInfo, labels, numClasses,
|
||||
currentCol - currentChildBegin, datasetInfo, responses, numClasses,
|
||||
weights, minimumLeafSize, minimumGainSplit, maximumDepth - 1,
|
||||
dimensionSelector);
|
||||
bestGain += double(childCounts[i]) / double(count) * (-childGain);
|
||||
@@ -758,7 +758,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
|
||||
// Calculate prediction label because we are a leaf.
|
||||
CalculatePrediction<UseWeights>(
|
||||
labels.subvec(begin, begin + count - 1),
|
||||
responses.subvec(begin, begin + count - 1),
|
||||
UseWeights ? weights.subvec(begin, begin + count - 1) : weights);
|
||||
std::cout << "Number of points in leaf: " << count <<
|
||||
" Prediction: " << splitPointOrPrediction << std::endl;
|
||||
@@ -773,7 +773,7 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<bool UseWeights, typename MatType, typename LabelsType>
|
||||
template<bool UseWeights, typename MatType, typename ResponsesType>
|
||||
double DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
@@ -782,7 +782,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
MatType& data,
|
||||
const size_t begin,
|
||||
const size_t count,
|
||||
LabelsType& labels,
|
||||
ResponsesType& responses,
|
||||
const size_t numClasses,
|
||||
arma::rowvec& weights,
|
||||
const size_t minimumLeafSize,
|
||||
@@ -804,7 +804,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
// information. Later we'll overwrite classProbabilities to the empirical
|
||||
// class probabilities if we do not split.
|
||||
double bestGain = FitnessFunction::template Evaluate<UseWeights>(
|
||||
labels.subvec(begin, begin + count - 1),
|
||||
responses.subvec(begin, begin + count - 1),
|
||||
numClasses,
|
||||
UseWeights ? weights.subvec(begin, begin + count - 1) : weights);
|
||||
size_t bestDim = data.n_rows; // This means "no split".
|
||||
@@ -817,7 +817,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
const double dimGain = NumericSplitType<FitnessFunction>::template
|
||||
SplitIfBetter<UseWeights>(bestGain,
|
||||
data.cols(begin, begin + count - 1).row(i),
|
||||
labels.cols(begin, begin + count - 1),
|
||||
responses.cols(begin, begin + count - 1),
|
||||
UseWeights ?
|
||||
weights.cols(begin, begin + count - 1) :
|
||||
weights,
|
||||
@@ -882,7 +882,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
{
|
||||
childAssignments.swap_cols(currentCol - begin, j - begin);
|
||||
data.swap_cols(currentCol, j);
|
||||
labels.swap_cols(currentCol, j);
|
||||
responses.swap_cols(currentCol, j);
|
||||
if (UseWeights)
|
||||
weights.swap_cols(currentCol, j);
|
||||
++currentCol;
|
||||
@@ -894,7 +894,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
if (NoRecursion)
|
||||
{
|
||||
child->Train<UseWeights>(data, currentChildBegin,
|
||||
currentCol - currentChildBegin, labels, numClasses, weights,
|
||||
currentCol - currentChildBegin, responses, numClasses, weights,
|
||||
currentCol - currentChildBegin, minimumGainSplit, maximumDepth - 1,
|
||||
dimensionSelector);
|
||||
}
|
||||
@@ -902,7 +902,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
{
|
||||
// During recursion entropy of child node may change.
|
||||
double childGain = child->Train<UseWeights>(data, currentChildBegin,
|
||||
currentCol - currentChildBegin, labels, numClasses, weights,
|
||||
currentCol - currentChildBegin, responses, numClasses, weights,
|
||||
minimumLeafSize, minimumGainSplit, maximumDepth - 1,
|
||||
dimensionSelector);
|
||||
bestGain += double(childCounts[i]) / double(count) * (-childGain);
|
||||
@@ -917,7 +917,7 @@ double DecisionTreeRegressor<FitnessFunction,
|
||||
|
||||
// Calculate prediction label because we are a leaf.
|
||||
CalculatePrediction<UseWeights>(
|
||||
labels.subvec(begin, begin + count - 1),
|
||||
responses.subvec(begin, begin + count - 1),
|
||||
UseWeights ? weights.subvec(begin, begin + count - 1) : weights);
|
||||
std::cout << "Number of points in leaf: " << count <<
|
||||
" Prediction: " << splitPointOrPrediction << std::endl;
|
||||
@@ -980,25 +980,27 @@ template<typename FitnessFunction,
|
||||
template<typename> class CategoricalSplitType,
|
||||
typename DimensionSelectionType,
|
||||
bool NoRecursion>
|
||||
template<bool UseWeights, typename LabelsType, typename WeightsType>
|
||||
template<bool UseWeights, typename ResponsesType, typename WeightsType>
|
||||
void DecisionTreeRegressor<FitnessFunction,
|
||||
NumericSplitType,
|
||||
CategoricalSplitType,
|
||||
DimensionSelectionType,
|
||||
NoRecursion
|
||||
>::CalculatePrediction(const LabelsType& labels, const WeightsType& weights)
|
||||
>::CalculatePrediction(const ResponsesType& responses,
|
||||
const WeightsType& weights)
|
||||
{
|
||||
if (UseWeights)
|
||||
{
|
||||
double accWeights, weightedSum;
|
||||
WeightedSum(labels, weights, 0, labels.n_elem, accWeights, weightedSum);
|
||||
WeightedSum(responses, weights, 0, responses.n_elem, accWeights,
|
||||
weightedSum);
|
||||
splitPointOrPrediction = weightedSum / accWeights;
|
||||
}
|
||||
else
|
||||
{
|
||||
double sum;
|
||||
Sum(labels, 0, labels.n_elem, sum);
|
||||
splitPointOrPrediction = sum / labels.n_elem;
|
||||
Sum(responses, 0, responses.n_elem, sum);
|
||||
splitPointOrPrediction = sum / responses.n_elem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,16 +34,16 @@ class MADGain
|
||||
* Evaluate the mean absolute deviation gain from begin to end index. Note
|
||||
* that gain can be slightly greater than 0 due to floating-point
|
||||
* representation issues. Thus if you are checking for perfect fit, be sure
|
||||
* to use 'gain >= 0.0'. Not 'gain == 0.0'. The labels should always be of
|
||||
* to use 'gain >= 0.0'. Not 'gain == 0.0'. The values should always be of
|
||||
* type arma::Row<double> or arma::rowvec.
|
||||
*
|
||||
* @param labels Set of labels to evaluate MAD gain on.
|
||||
* @param weights Weight of labels.
|
||||
* @param values Set of values to evaluate MAD gain on.
|
||||
* @param weights Weights associated to each value.
|
||||
* @param begin Start index.
|
||||
* @param end End index.
|
||||
*/
|
||||
template<bool UseWeights, typename WeightVecType>
|
||||
static double Evaluate(const arma::rowvec& labels,
|
||||
static double Evaluate(const arma::rowvec& values,
|
||||
const WeightVecType& weights,
|
||||
const size_t begin,
|
||||
const size_t end)
|
||||
@@ -55,7 +55,7 @@ class MADGain
|
||||
double accWeights = 0.0;
|
||||
double weightedMean = 0.0;
|
||||
|
||||
WeightedSum(labels, weights, begin, end, accWeights, weightedMean);
|
||||
WeightedSum(values, weights, begin, end, accWeights, weightedMean);
|
||||
|
||||
// Catch edge case: if there are no weights, the impurity is zero.
|
||||
if (accWeights == 0.0)
|
||||
@@ -65,18 +65,18 @@ class MADGain
|
||||
|
||||
for (size_t i = begin; i < end; ++i)
|
||||
{
|
||||
mad += weights[i] * (std::abs(labels[i] - weightedMean));
|
||||
mad += weights[i] * (std::abs(values[i] - weightedMean));
|
||||
}
|
||||
mad /= accWeights;
|
||||
}
|
||||
else
|
||||
{
|
||||
double mean = 0.0;
|
||||
Sum(labels, begin, end, mean);
|
||||
Sum(values, begin, end, mean);
|
||||
mean /= (double) (end - begin);
|
||||
|
||||
for (size_t i = begin; i < end; ++i)
|
||||
mad += std::abs(labels[i] - mean);
|
||||
mad += std::abs(values[i] - mean);
|
||||
|
||||
mad /= (double) (end - begin);
|
||||
}
|
||||
@@ -87,19 +87,19 @@ class MADGain
|
||||
/**
|
||||
* Evaluate the MAD gain on the complete vector.
|
||||
*
|
||||
* @param labels Set of labels to evaluate MAD gain on.
|
||||
* @param weights Weights associated to each label.
|
||||
* @param values Set of values to evaluate MAD gain on.
|
||||
* @param weights Weights associated to each value.
|
||||
*/
|
||||
template<bool UseWeights, typename WeightVecType>
|
||||
static double Evaluate(const arma::rowvec& labels,
|
||||
static double Evaluate(const arma::rowvec& values,
|
||||
const size_t /* numClasses */,
|
||||
const WeightVecType& weights)
|
||||
{
|
||||
// Corner case: if there are no elements, the impurity is zero.
|
||||
if (labels.n_elem == 0)
|
||||
if (values.n_elem == 0)
|
||||
return 0.0;
|
||||
|
||||
return Evaluate<UseWeights>(labels, weights, 0, labels.n_elem);
|
||||
return Evaluate<UseWeights>(values, weights, 0, values.n_elem);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -29,19 +29,19 @@ class MSEGain
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Evaluate the mean squared error gain of labls from begin to end index.
|
||||
* Evaluate the mean squared error gain of values from begin to end index.
|
||||
* Note that gain can be slightly greater than 0 due to floating-point
|
||||
* representation issues. Thus if you are checking for perfect fit, be
|
||||
* sure to use 'gain >= 0.0' and not 'gain == 0.0'. The labels vector should
|
||||
* always be of type arma::Row<double> or arma::rowvec.
|
||||
* sure to use 'gain >= 0.0' and not 'gain == 0.0'. The values vector
|
||||
* should always be of type arma::Row<double> or arma::rowvec.
|
||||
*
|
||||
* @param labels Set of labels to evaluate MAD gain on.
|
||||
* @param weights Weight of labels.
|
||||
* @param values Set of values to evaluate MAD gain on.
|
||||
* @param weights Weights associated to each value.
|
||||
* @param begin Start index.
|
||||
* @param end End index.
|
||||
*/
|
||||
template<bool UseWeights, typename WeightVecType>
|
||||
static double Evaluate(const arma::rowvec& labels,
|
||||
static double Evaluate(const arma::rowvec& values,
|
||||
const WeightVecType& weights,
|
||||
const size_t begin,
|
||||
const size_t end)
|
||||
@@ -52,7 +52,7 @@ class MSEGain
|
||||
{
|
||||
double accWeights = 0.0;
|
||||
double weightedMean = 0.0;
|
||||
WeightedSum(labels, weights, begin, end, accWeights, weightedMean);
|
||||
WeightedSum(values, weights, begin, end, accWeights, weightedMean);
|
||||
|
||||
// Catch edge case: if there are no weights, the impurity is zero.
|
||||
if (accWeights == 0.0)
|
||||
@@ -61,18 +61,18 @@ class MSEGain
|
||||
weightedMean /= accWeights;
|
||||
|
||||
for (size_t i = begin; i < end; ++i)
|
||||
mse += weights[i] * std::pow(labels[i] - weightedMean, 2);
|
||||
mse += weights[i] * std::pow(values[i] - weightedMean, 2);
|
||||
|
||||
mse /= accWeights;
|
||||
}
|
||||
else
|
||||
{
|
||||
double mean = 0.0;
|
||||
Sum(labels, begin, end, mean);
|
||||
Sum(values, begin, end, mean);
|
||||
mean /= (double) (end - begin);
|
||||
|
||||
for (size_t i = begin; i < end; ++i)
|
||||
mse += std::pow(labels[i] - mean, 2);
|
||||
mse += std::pow(values[i] - mean, 2);
|
||||
|
||||
mse /= (double) (end - begin);
|
||||
}
|
||||
@@ -83,19 +83,19 @@ class MSEGain
|
||||
/**
|
||||
* Evaluate the MSE gain on the complete vector.
|
||||
*
|
||||
* @param labels Set of labels to evaluate MAD gain on.
|
||||
* @param weights Weights associated to each label.
|
||||
* @param values Set of values to evaluate MSE gain on.
|
||||
* @param weights Weights associated to each value.
|
||||
*/
|
||||
template<bool UseWeights, typename WeightVecType>
|
||||
static double Evaluate(const arma::rowvec& labels,
|
||||
static double Evaluate(const arma::rowvec& values,
|
||||
const size_t /* numClasses */,
|
||||
const WeightVecType& weights)
|
||||
{
|
||||
// Corner case: if there are no elements, the impurity is zero.
|
||||
if (labels.n_elem == 0)
|
||||
if (values.n_elem == 0)
|
||||
return 0.0;
|
||||
|
||||
return Evaluate<UseWeights>(labels, weights, 0, labels.n_elem);
|
||||
return Evaluate<UseWeights>(values, weights, 0, values.n_elem);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -28,56 +28,56 @@ using namespace mlpack::distribution;
|
||||
|
||||
/**
|
||||
* Creates dataset with 5 groups with all the points in same group have exactly
|
||||
* same label.
|
||||
* same responses.
|
||||
*/
|
||||
void CreateMultiSplitData(arma::mat& d, arma::rowvec& l, const size_t count,
|
||||
void CreateMultiSplitData(arma::mat& d, arma::rowvec& r, const size_t count,
|
||||
arma::rowvec& values)
|
||||
{
|
||||
d = arma::mat(10, count, arma::fill::randu);
|
||||
l = arma::rowvec(count);
|
||||
r = arma::rowvec(count);
|
||||
|
||||
// Group 1.
|
||||
for (size_t i = 0; i < count / 5; i++)
|
||||
{
|
||||
d(3, i) = i;
|
||||
l(i) = values[0];
|
||||
r(i) = values[0];
|
||||
}
|
||||
// Group 2.
|
||||
for (size_t i = count / 5; i < (count / 5) * 2; i++)
|
||||
{
|
||||
d(3, i) = i;
|
||||
l(i) = values[1];
|
||||
r(i) = values[1];
|
||||
}
|
||||
// Group 3.
|
||||
for (size_t i = (count / 5) * 2; i < (count / 5) * 3; i++)
|
||||
{
|
||||
d(3, i) = i;
|
||||
l(i) = values[2];
|
||||
r(i) = values[2];
|
||||
}
|
||||
// Group 4.
|
||||
for (size_t i = (count / 5) * 3; i < (count / 5) * 4; i++)
|
||||
{
|
||||
d(3, i) = i;
|
||||
l(i) = values[3];
|
||||
r(i) = values[3];
|
||||
}
|
||||
// Group 5.
|
||||
for (size_t i = (count / 5) * 4; i < count; i++)
|
||||
{
|
||||
d(3, i) = i;
|
||||
l(i) = values[4];
|
||||
r(i) = values[4];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the MSE gain is zero when the labels are perfect.
|
||||
* Make sure the MSE gain is zero when the responses are perfect.
|
||||
*/
|
||||
TEST_CASE("MSEGainPerfectTest", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec weights(10, arma::fill::ones);
|
||||
arma::rowvec labels;
|
||||
labels.ones(10);
|
||||
arma::rowvec responses;
|
||||
responses.ones(10);
|
||||
|
||||
REQUIRE(MSEGain::Evaluate<false>(labels, 0, weights) ==
|
||||
REQUIRE(MSEGain::Evaluate<false>(responses, 0, weights) ==
|
||||
Approx(0.0).margin(1e-5));
|
||||
}
|
||||
|
||||
@@ -87,11 +87,11 @@ TEST_CASE("MSEGainPerfectTest", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("MSEGainEmptyTest", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(10);
|
||||
arma::rowvec labels;
|
||||
REQUIRE(MSEGain::Evaluate<false>(labels, 0, weights) ==
|
||||
arma::rowvec responses;
|
||||
REQUIRE(MSEGain::Evaluate<false>(responses, 0, weights) ==
|
||||
Approx(0.0).margin(1e-5));
|
||||
|
||||
REQUIRE(MSEGain::Evaluate<true>(labels, 0, weights) ==
|
||||
REQUIRE(MSEGain::Evaluate<true>(responses, 0, weights) ==
|
||||
Approx(0.0).margin(1e-5));
|
||||
}
|
||||
|
||||
@@ -101,48 +101,49 @@ TEST_CASE("MSEGainEmptyTest", "[DecisionTreeRegressorTest]")
|
||||
*/
|
||||
TEST_CASE("MSEGainHandCalculation", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec labels = {4., 2., 3., 4., 13., 6., 20., 8., 9., 10.};
|
||||
arma::rowvec responses = {4., 2., 3., 4., 13., 6., 20., 8., 9., 10.};
|
||||
arma::rowvec weights = {0.3, 0.3, 0.3, 0.3, 0.3, 0.7, 0.7, 0.7, 0.7, 0.7};
|
||||
|
||||
// Hand calculated gain values.
|
||||
const double gain = -27.08999;
|
||||
const double weightedGain = -27.53960;
|
||||
REQUIRE(MSEGain::Evaluate<false>(labels, 0, weights) ==
|
||||
REQUIRE(MSEGain::Evaluate<false>(responses, 0, weights) ==
|
||||
Approx(gain).margin(1e-5));
|
||||
REQUIRE(MSEGain::Evaluate<true>(labels, 0, weights) ==
|
||||
REQUIRE(MSEGain::Evaluate<true>(responses, 0, weights) ==
|
||||
Approx(weightedGain).margin(1e-5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the MAD gain is zero when the labels are perfect.
|
||||
* Make sure the MAD gain is zero when the responses are perfect.
|
||||
*/
|
||||
TEST_CASE("MADGainPerfectTest", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec weights(10, arma::fill::ones);
|
||||
arma::rowvec labels;
|
||||
labels.ones(10);
|
||||
arma::rowvec responses;
|
||||
responses.ones(10);
|
||||
|
||||
REQUIRE(MADGain::Evaluate<false>(labels, 0, weights) ==
|
||||
REQUIRE(MADGain::Evaluate<false>(responses, 0, weights) ==
|
||||
Approx(0.0).margin(1e-5));
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that when mean of labels is zero, MAD_gain = mean of
|
||||
* Make sure that when mean of responses is zero, MAD_gain = mean of
|
||||
* absolute values of the distribution.
|
||||
*/
|
||||
TEST_CASE("MADGainNormalTest", "[DecisionTreeRegressorTest")
|
||||
{
|
||||
arma::rowvec weights(10, arma::fill::ones);
|
||||
arma::rowvec labels = { 1, 2, 3, 4, 5, -1, -2, -3, -4, -5 }; // Mean = 0.
|
||||
arma::rowvec responses = { 1, 2, 3, 4, 5, -1, -2, -3, -4, -5 }; // Mean = 0.
|
||||
|
||||
// Theoretical gain.
|
||||
double theoreticalGain = 0.0;
|
||||
for (size_t i = 0; i < labels.n_elem; ++i)
|
||||
theoreticalGain -= std::abs(labels[i]);
|
||||
theoreticalGain /= (double) labels.n_elem;
|
||||
for (size_t i = 0; i < responses.n_elem; ++i)
|
||||
theoreticalGain -= std::abs(responses[i]);
|
||||
theoreticalGain /= (double) responses.n_elem;
|
||||
|
||||
// Calculated gain.
|
||||
const double calculatedGain = MADGain::Evaluate<false>(labels, 0, weights);
|
||||
const double calculatedGain =
|
||||
MADGain::Evaluate<false>(responses, 0, weights);
|
||||
|
||||
REQUIRE(calculatedGain == Approx(theoreticalGain).margin(1e-5));
|
||||
}
|
||||
@@ -153,11 +154,11 @@ TEST_CASE("MADGainNormalTest", "[DecisionTreeRegressorTest")
|
||||
TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(10);
|
||||
arma::rowvec labels;
|
||||
REQUIRE(MADGain::Evaluate<false>(labels, 0, weights) ==
|
||||
arma::rowvec responses;
|
||||
REQUIRE(MADGain::Evaluate<false>(responses, 0, weights) ==
|
||||
Approx(0.0).margin(1e-5));
|
||||
|
||||
REQUIRE(MADGain::Evaluate<true>(labels, 0, weights) ==
|
||||
REQUIRE(MADGain::Evaluate<true>(responses, 0, weights) ==
|
||||
Approx(0.0).margin(1e-5));
|
||||
}
|
||||
|
||||
@@ -167,15 +168,15 @@ TEST_CASE("MADGainEmptyTest", "[DecisionTreeRegressorTest]")
|
||||
*/
|
||||
TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec labels = {4., 2., 3., 4., 13., 6., 20., 8., 9., 10.};
|
||||
arma::rowvec responses = {4., 2., 3., 4., 13., 6., 20., 8., 9., 10.};
|
||||
arma::rowvec weights = {0.3, 0.3, 0.3, 0.3, 0.3, 0.7, 0.7, 0.7, 0.7, 0.7};
|
||||
|
||||
// Hand calculated gain values.
|
||||
const double gain = -4.1;
|
||||
const double weightedGain = -3.8592;
|
||||
REQUIRE(MADGain::Evaluate<false>(labels, 0, weights) ==
|
||||
REQUIRE(MADGain::Evaluate<false>(responses, 0, weights) ==
|
||||
Approx(gain).margin(1e-5));
|
||||
REQUIRE(MADGain::Evaluate<true>(labels, 0, weights) ==
|
||||
REQUIRE(MADGain::Evaluate<true>(responses, 0, weights) ==
|
||||
Approx(weightedGain).margin(1e-5));
|
||||
}
|
||||
|
||||
@@ -186,28 +187,28 @@ TEST_CASE("MADGainHandCalculation", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("AllCategoricalSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::vec predictor(100);
|
||||
arma::rowvec labels(100);
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec responses(100);
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
for (size_t i = 0; i < 100; i+=2)
|
||||
{
|
||||
predictor[i] = 0;
|
||||
labels[i] = 5.0;
|
||||
responses[i] = 5.0;
|
||||
predictor[i + 1] = 1;
|
||||
labels[i + 1] = 100;
|
||||
responses[i + 1] = 100;
|
||||
}
|
||||
|
||||
double splitInfo;
|
||||
AllCategoricalSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 0, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 0, weights);
|
||||
const double gain = AllCategoricalSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, predictor, 2, labels, 0, weights, 3, 1e-7, splitInfo, aux);
|
||||
bestGain, predictor, 2, responses, 0, weights, 3, 1e-7, splitInfo, aux);
|
||||
const double weightedGain =
|
||||
AllCategoricalSplit<MSEGain>::SplitIfBetter<true>(bestGain, predictor, 2,
|
||||
labels, 0, weights, 3, 1e-7, splitInfo, aux);
|
||||
responses, 0, weights, 3, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure that a split was made.
|
||||
REQUIRE(gain > bestGain);
|
||||
@@ -225,17 +226,17 @@ TEST_CASE("AllCategoricalSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("AllCategoricalSplitMinSamplesTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec predictors = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3};
|
||||
arma::rowvec labels = {0, 0, 0, 2, 2, 2, 1, 1, 1, 2, 2, 2};
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec responses = {0, 0, 0, 2, 2, 2, 1, 1, 1, 2, 2, 2};
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
double splitInfo;
|
||||
AllCategoricalSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 0, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 0, weights);
|
||||
const double gain = AllCategoricalSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, predictors, 4, labels, 0, weights, 4, 1e-7, splitInfo, aux);
|
||||
bestGain, predictors, 4, responses, 0, weights, 4, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure it's not split.
|
||||
REQUIRE(gain == DBL_MAX);
|
||||
@@ -247,30 +248,30 @@ TEST_CASE("AllCategoricalSplitMinSamplesTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("AllCategoricalSplitNoGainTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec predictors(300);
|
||||
arma::rowvec labels(300);
|
||||
arma::rowvec responses(300);
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(300);
|
||||
|
||||
for (size_t i = 0; i < 300; i += 3)
|
||||
{
|
||||
predictors[i] = int(i / 3) % 10;
|
||||
labels[i] = -0.5;
|
||||
responses[i] = -0.5;
|
||||
predictors[i + 1] = int(i / 3) % 10;
|
||||
labels[i + 1] = 0;
|
||||
responses[i + 1] = 0;
|
||||
predictors[i + 2] = int(i / 3) % 10;
|
||||
labels[i + 2] = 0.5;
|
||||
responses[i + 2] = 0.5;
|
||||
}
|
||||
|
||||
double splitInfo;
|
||||
AllCategoricalSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 0, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 0, weights);
|
||||
const double gain = AllCategoricalSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, predictors, 10, labels, 0, weights, 10, 1e-7,
|
||||
bestGain, predictors, 10, responses, 0, weights, 10, 1e-7,
|
||||
splitInfo, aux);
|
||||
const double weightedGain =
|
||||
AllCategoricalSplit<MSEGain>::SplitIfBetter<true>(bestGain, predictors,
|
||||
10, labels, 0, predictors, 10, 1e-7, splitInfo, aux);
|
||||
10, responses, 0, predictors, 10, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure that there was no split.
|
||||
REQUIRE(gain == DBL_MAX);
|
||||
@@ -281,23 +282,26 @@ TEST_CASE("AllCategoricalSplitNoGainTest_", "[DecisionTreeRegressorTest]")
|
||||
* Check that the BestBinaryNumericSplit will split on an obviously splittable
|
||||
* dimension.
|
||||
*/
|
||||
TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_",
|
||||
"[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec predictors = { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
|
||||
arma::rowvec labels = { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec predictors =
|
||||
{ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
|
||||
arma::rowvec responses =
|
||||
{ 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
double splitInfo;
|
||||
BestBinaryNumericSplit<MADGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MADGain::Evaluate<false>(labels, 0, weights);
|
||||
const double bestGain = MADGain::Evaluate<false>(responses, 0, weights);
|
||||
const double gain = BestBinaryNumericSplit<MADGain>::SplitIfBetter<false>(
|
||||
bestGain, predictors, labels, weights, 3, 1e-7, splitInfo, aux);
|
||||
bestGain, predictors, responses, weights, 3, 1e-7, splitInfo, aux);
|
||||
const double weightedGain =
|
||||
BestBinaryNumericSplit<MADGain>::SplitIfBetter<true>(bestGain, predictors,
|
||||
labels, weights, 3, 1e-7, splitInfo, aux);
|
||||
responses, weights, 3, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure that a split was made.
|
||||
REQUIRE(gain > bestGain);
|
||||
@@ -315,23 +319,26 @@ TEST_CASE("BestBinaryNumericSplitSimpleSplitTest_", "[DecisionTreeRegressorTest]
|
||||
* Check that the BestBinaryNumericSplit won't split if not enough points are
|
||||
* given.
|
||||
*/
|
||||
TEST_CASE("BestBinaryNumericSplitMinSamplesTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("BestBinaryNumericSplitMinSamplesTest_",
|
||||
"[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec predictors = { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
|
||||
arma::rowvec labels = { 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec predictors =
|
||||
{ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 };
|
||||
arma::rowvec responses =
|
||||
{ 0.5, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
|
||||
double splitInfo;
|
||||
BestBinaryNumericSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 0, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 0, weights);
|
||||
const double gain = BestBinaryNumericSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, predictors, labels, weights, 8, 1e-7, splitInfo, aux);
|
||||
bestGain, predictors, responses, weights, 8, 1e-7, splitInfo, aux);
|
||||
// This should make no difference because it won't split at all.
|
||||
const double weightedGain =
|
||||
BestBinaryNumericSplit<MSEGain>::SplitIfBetter<true>(bestGain, predictors,
|
||||
labels, weights, 8, 1e-7, splitInfo, aux);
|
||||
BestBinaryNumericSplit<MSEGain>::SplitIfBetter<true>(bestGain,
|
||||
predictors, responses, weights, 8, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure that no split was made.
|
||||
REQUIRE(gain == DBL_MAX);
|
||||
@@ -339,30 +346,29 @@ TEST_CASE("BestBinaryNumericSplitMinSamplesTest_", "[DecisionTreeRegressorTest]"
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the BestBinaryNumericSplit doesn't split a dimension that gives no
|
||||
* gain.
|
||||
* Check that the BestBinaryNumericSplit doesn't split a dimension that gives
|
||||
* no gain.
|
||||
*/
|
||||
TEST_CASE("BestBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::rowvec predictors(100);
|
||||
arma::rowvec labels(100);
|
||||
arma::rowvec responses(100);
|
||||
arma::rowvec weights;
|
||||
for (size_t i = 0; i < 100; i += 2)
|
||||
{
|
||||
predictors[i] = i;
|
||||
labels[i] = 0.0;
|
||||
responses[i] = 0.0;
|
||||
predictors[i + 1] = i;
|
||||
labels[i + 1] = 1.0;
|
||||
responses[i + 1] = 1.0;
|
||||
}
|
||||
|
||||
double splitInfo;
|
||||
BestBinaryNumericSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 0, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 0, weights);
|
||||
const double gain = BestBinaryNumericSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, predictors, labels, weights, 10, 1e-7, splitInfo,
|
||||
aux);
|
||||
bestGain, predictors, responses, weights, 10, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure there was no split.
|
||||
REQUIRE(gain == DBL_MAX);
|
||||
@@ -376,20 +382,20 @@ TEST_CASE("RandomBinaryNumericSplitAlwaysSplit_",
|
||||
"[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::vec values("0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0");
|
||||
arma::rowvec labels("0 0 0 0 0 1 1 1 1 1 1");
|
||||
arma::rowvec responses("0 0 0 0 0 1 1 1 1 1 1");
|
||||
arma::rowvec weights;
|
||||
weights.ones(labels.n_elem);
|
||||
weights.ones(responses.n_elem);
|
||||
|
||||
double splitInfo;
|
||||
RandomBinaryNumericSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 2, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 2, weights);
|
||||
const double gain = RandomBinaryNumericSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, values, labels, weights, 1, 1e-7, splitInfo, aux);
|
||||
bestGain, values, responses, weights, 1, 1e-7, splitInfo, aux);
|
||||
const double weightedGain =
|
||||
RandomBinaryNumericSplit<MSEGain>::SplitIfBetter<true>(bestGain, values,
|
||||
labels, weights, 1, 1e-7, splitInfo, aux);
|
||||
responses, weights, 1, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure that split was made.
|
||||
REQUIRE(gain != DBL_MAX);
|
||||
@@ -404,20 +410,20 @@ TEST_CASE("RandomBinaryNumericSplitMinSamplesTest_",
|
||||
"[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::vec values("0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0");
|
||||
arma::rowvec labels("0 0 0 0 0 1 1 1 1 1 1");
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec responses("0 0 0 0 0 1 1 1 1 1 1");
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
|
||||
double splitInfo;
|
||||
RandomBinaryNumericSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 2, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 2, weights);
|
||||
const double gain = RandomBinaryNumericSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, values, labels, weights, 8, 1e-7, splitInfo, aux);
|
||||
bestGain, values, responses, weights, 8, 1e-7, splitInfo, aux);
|
||||
// This should make no difference because it won't split at all.
|
||||
const double weightedGain =
|
||||
RandomBinaryNumericSplit<MSEGain>::SplitIfBetter<true>(bestGain, values,
|
||||
labels, weights, 8, 1e-7, splitInfo, aux);
|
||||
responses, weights, 8, 1e-7, splitInfo, aux);
|
||||
|
||||
// Make sure that no split was made.
|
||||
REQUIRE(gain == DBL_MAX);
|
||||
@@ -431,23 +437,23 @@ TEST_CASE("RandomBinaryNumericSplitMinSamplesTest_",
|
||||
TEST_CASE("RandomBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::vec values(100);
|
||||
arma::Row<double> labels(100);
|
||||
arma::rowvec responses(100);
|
||||
arma::rowvec weights;
|
||||
for (size_t i = 0; i < 100; i += 2)
|
||||
{
|
||||
values[i] = i;
|
||||
labels[i] = 0.0;
|
||||
responses[i] = 0.0;
|
||||
values[i + 1] = i;
|
||||
labels[i + 1] = 1.0;
|
||||
responses[i + 1] = 1.0;
|
||||
}
|
||||
|
||||
double splitInfo;
|
||||
RandomBinaryNumericSplit<MSEGain>::AuxiliarySplitInfo aux;
|
||||
|
||||
// Call the method to do the splitting.
|
||||
const double bestGain = MSEGain::Evaluate<false>(labels, 2, weights);
|
||||
const double bestGain = MSEGain::Evaluate<false>(responses, 2, weights);
|
||||
const double gain = RandomBinaryNumericSplit<MSEGain>::SplitIfBetter<false>(
|
||||
bestGain, values, labels, weights, 10, 1e-7, splitInfo, aux, true);
|
||||
bestGain, values, responses, weights, 10, 1e-7, splitInfo, aux, true);
|
||||
|
||||
// Make sure there was no split.
|
||||
REQUIRE(gain == DBL_MAX);
|
||||
@@ -460,48 +466,48 @@ TEST_CASE("RandomBinaryNumericSplitNoGainTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("BasicConstructionTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat dataset(10, 100, arma::fill::randu);
|
||||
arma::Row<double> labels(100);
|
||||
arma::rowvec responses(100);
|
||||
for (size_t i = 0; i < 50; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 0.0;
|
||||
responses[i] = 0.0;
|
||||
}
|
||||
for (size_t i = 50; i < 100; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 1.0;
|
||||
responses[i] = 1.0;
|
||||
}
|
||||
|
||||
// Use default parameters.
|
||||
DecisionTreeRegressor<> d(dataset, labels);
|
||||
DecisionTreeRegressor<> d(dataset, responses);
|
||||
|
||||
// Now require that we have some children.
|
||||
REQUIRE(d.NumChildren() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a tree with weighted labels.
|
||||
* Construct a tree with weighted responses.
|
||||
*/
|
||||
TEST_CASE("BasicConstructionTestWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat dataset(10, 100, arma::fill::randu);
|
||||
arma::Row<double> labels(100);
|
||||
arma::rowvec responses(100);
|
||||
for (size_t i = 0; i < 50; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 0.0;
|
||||
responses[i] = 0.0;
|
||||
}
|
||||
for (size_t i = 50; i < 100; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 1.0;
|
||||
responses[i] = 1.0;
|
||||
}
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
// Use default parameters.
|
||||
DecisionTreeRegressor<> wd(dataset, labels, weights);
|
||||
DecisionTreeRegressor<> d(dataset, labels);
|
||||
DecisionTreeRegressor<> wd(dataset, responses, weights);
|
||||
DecisionTreeRegressor<> d(dataset, responses);
|
||||
|
||||
// Now require that we have some children.
|
||||
REQUIRE(wd.NumChildren() > 0);
|
||||
@@ -515,53 +521,53 @@ TEST_CASE("BasicConstructionTestWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("PerfectTrainingSet_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat dataset(10, 100, arma::fill::randu);
|
||||
arma::Row<double> labels(100);
|
||||
arma::rowvec responses(100);
|
||||
for (size_t i = 0; i < 50; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 0.0;
|
||||
responses[i] = 0.0;
|
||||
}
|
||||
for (size_t i = 50; i < 100; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 1.0;
|
||||
responses[i] = 1.0;
|
||||
}
|
||||
|
||||
DecisionTreeRegressor<> d(dataset, labels, 1, 0.0); // Minimum leaf size of 1.
|
||||
// Minimum leaf size of 1.
|
||||
DecisionTreeRegressor<> d(dataset, responses, 1, 0.0);
|
||||
|
||||
// Make sure that we can get perfect accuracy on the training set.
|
||||
// Make sure that we can get perfect fit on the training set.
|
||||
for (size_t i = 0; i < 100; ++i)
|
||||
{
|
||||
double prediction;
|
||||
prediction = d.Predict(dataset.col(i));
|
||||
|
||||
REQUIRE(prediction == Approx(labels[i]).epsilon(1e-7));
|
||||
REQUIRE(prediction == Approx(responses[i]).epsilon(1e-7));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the decision tree with weighted labels
|
||||
* Construct the decision tree with weighted responses.
|
||||
*/
|
||||
TEST_CASE("PerfectTrainingSetWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
// Completely random dataset with no structure.
|
||||
arma::mat dataset(10, 100, arma::fill::randu);
|
||||
arma::Row<double> labels(100);
|
||||
arma::rowvec responses(100);
|
||||
for (size_t i = 0; i < 50; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 0.0;
|
||||
responses[i] = 0.0;
|
||||
}
|
||||
for (size_t i = 50; i < 100; ++i)
|
||||
{
|
||||
dataset(3, i) = i;
|
||||
labels[i] = 1.0;
|
||||
responses[i] = 1.0;
|
||||
}
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
weights.ones();
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(responses.n_elem);
|
||||
|
||||
// Minimum leaf size of 1.
|
||||
DecisionTreeRegressor<> d(dataset, labels, weights, 1, 0.0);
|
||||
DecisionTreeRegressor<> d(dataset, responses, weights, 1, 0.0);
|
||||
|
||||
// This part of code is dupliacte with no weighted one.
|
||||
for (size_t i = 0; i < 100; ++i)
|
||||
@@ -569,7 +575,7 @@ TEST_CASE("PerfectTrainingSetWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
size_t prediction;
|
||||
prediction = d.Predict(dataset.col(i));
|
||||
|
||||
REQUIRE(prediction == Approx(labels[i]).epsilon(1e-7));
|
||||
REQUIRE(prediction == Approx(responses[i]).epsilon(1e-7));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,18 +585,18 @@ TEST_CASE("PerfectTrainingSetWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("CategoricalBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat d;
|
||||
arma::rowvec l;
|
||||
arma::rowvec r;
|
||||
data::DatasetInfo di;
|
||||
MockCategoricalData(d, l, di);
|
||||
MockCategoricalData(d, r, di);
|
||||
|
||||
// Split into a training set and a test set.
|
||||
arma::mat trainingData = d.cols(0, 1999);
|
||||
arma::mat testData = d.cols(2000, 3999);
|
||||
arma::rowvec trainingLabels = l.subvec(0, 1999);
|
||||
arma::rowvec testLabels = l.subvec(2000, 3999);
|
||||
arma::rowvec trainingResponses = r.subvec(0, 1999);
|
||||
arma::rowvec testResponses = r.subvec(2000, 3999);
|
||||
|
||||
// Build the tree.
|
||||
DecisionTreeRegressor<> tree(trainingData, di, trainingLabels, 10);
|
||||
DecisionTreeRegressor<> tree(trainingData, di, trainingResponses, 10);
|
||||
|
||||
// Now evaluate the quality of predictions.
|
||||
arma::rowvec predictions;
|
||||
@@ -599,7 +605,7 @@ TEST_CASE("CategoricalBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
REQUIRE(predictions.n_elem == testData.n_cols);
|
||||
|
||||
// Make sure we get reasonable rmse.
|
||||
const double rmse = RMSE(predictions, testLabels);
|
||||
const double rmse = RMSE(predictions, testResponses);
|
||||
REQUIRE(rmse < 1.0);
|
||||
}
|
||||
|
||||
@@ -610,21 +616,21 @@ TEST_CASE("CategoricalBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("CategoricalBuildTestWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat d;
|
||||
arma::rowvec l;
|
||||
arma::rowvec r;
|
||||
data::DatasetInfo di;
|
||||
MockCategoricalData(d, l, di);
|
||||
MockCategoricalData(d, r, di);
|
||||
|
||||
// Split into a training set and a test set.
|
||||
arma::mat trainingData = d.cols(0, 1999);
|
||||
arma::mat testData = d.cols(2000, 3999);
|
||||
arma::rowvec trainingLabels = l.subvec(0, 1999);
|
||||
arma::rowvec testLabels = l.subvec(2000, 3999);
|
||||
arma::rowvec trainingResponses = r.subvec(0, 1999);
|
||||
arma::rowvec testResponses = r.subvec(2000, 3999);
|
||||
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(
|
||||
trainingLabels.n_elem);
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(trainingResponses.n_elem);
|
||||
|
||||
// Build the tree.
|
||||
DecisionTreeRegressor<> tree(trainingData, di, trainingLabels, weights, 10);
|
||||
DecisionTreeRegressor<> tree(trainingData, di, trainingResponses, weights,
|
||||
10);
|
||||
|
||||
// Now evaluate the quality of predictions.
|
||||
arma::rowvec predictions;
|
||||
@@ -633,7 +639,7 @@ TEST_CASE("CategoricalBuildTestWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
REQUIRE(predictions.n_elem == testData.n_cols);
|
||||
|
||||
// Make sure we get reasonable rmse.
|
||||
const double rmse = RMSE(predictions, testLabels);
|
||||
const double rmse = RMSE(predictions, testResponses);
|
||||
REQUIRE(rmse < 1.0);
|
||||
}
|
||||
|
||||
@@ -689,19 +695,19 @@ TEST_CASE("CategoricalBuildTestWithWeight_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("CategoricalWeightedBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat d;
|
||||
arma::rowvec l;
|
||||
arma::rowvec r;
|
||||
data::DatasetInfo di;
|
||||
MockCategoricalData(d, l, di);
|
||||
MockCategoricalData(d, r, di);
|
||||
|
||||
// Split into a training set and a test set.
|
||||
arma::mat trainingData = d.cols(0, 1999);
|
||||
arma::mat testData = d.cols(2000, 3999);
|
||||
arma::rowvec trainingLabels = l.subvec(0, 1999);
|
||||
arma::rowvec testLabels = l.subvec(2000, 3999);
|
||||
arma::rowvec trainingResponses = r.subvec(0, 1999);
|
||||
arma::rowvec testResponses = r.subvec(2000, 3999);
|
||||
|
||||
// Now create random points.
|
||||
arma::mat randomNoise(5, 2000);
|
||||
arma::rowvec randomLabels(2000);
|
||||
arma::rowvec randomResponses(2000);
|
||||
for (size_t i = 0; i < 2000; ++i)
|
||||
{
|
||||
randomNoise(0, i) = math::Random();
|
||||
@@ -709,7 +715,7 @@ TEST_CASE("CategoricalWeightedBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
randomNoise(2, i) = math::Random();
|
||||
randomNoise(3, i) = math::RandInt(0, 2);
|
||||
randomNoise(4, i) = math::RandInt(0, 5);
|
||||
randomLabels[i] = math::Random(-10, 18);
|
||||
randomResponses[i] = math::Random(-10, 18);
|
||||
}
|
||||
|
||||
// Generate weights.
|
||||
@@ -720,10 +726,11 @@ TEST_CASE("CategoricalWeightedBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
weights[i] = math::Random(0.0, 0.001);
|
||||
|
||||
arma::mat fullData = arma::join_rows(trainingData, randomNoise);
|
||||
arma::rowvec fullLabels = arma::join_rows(trainingLabels, randomLabels);
|
||||
arma::rowvec fullResponses = arma::join_rows(trainingResponses,
|
||||
randomResponses);
|
||||
|
||||
// Build the tree.
|
||||
DecisionTreeRegressor<> tree(fullData, di, fullLabels, weights, 10);
|
||||
DecisionTreeRegressor<> tree(fullData, di, fullResponses, weights, 10);
|
||||
|
||||
// Now evaluate the quality of predictions.
|
||||
arma::rowvec predictions;
|
||||
@@ -732,7 +739,7 @@ TEST_CASE("CategoricalWeightedBuildTest_", "[DecisionTreeRegressorTest]")
|
||||
REQUIRE(predictions.n_elem == testData.n_cols);
|
||||
|
||||
// Make sure we get reasonable rmse.
|
||||
const double rmse = RMSE(predictions, testLabels);
|
||||
const double rmse = RMSE(predictions, testResponses);
|
||||
REQUIRE(rmse < 1.5);
|
||||
}
|
||||
|
||||
@@ -856,29 +863,30 @@ TEST_CASE("SimpleGeneralizationTest_", "[DecisionTreeRegressorTest]")
|
||||
// Loading data.
|
||||
data::DatasetInfo info;
|
||||
arma::mat trainData, testData;
|
||||
arma::Row<double> trainLabels, testLabels;
|
||||
arma::rowvec trainResponses, testResponses;
|
||||
arma::rowvec weights = arma::ones<arma::rowvec>(355);
|
||||
LoadBostonHousingDataset(trainData, testData, trainLabels, testLabels, info);
|
||||
LoadBostonHousingDataset(trainData, testData, trainResponses, testResponses,
|
||||
info);
|
||||
|
||||
// Build decision tree.
|
||||
DecisionTreeRegressor<MSEGain> d(trainData, info, trainLabels);
|
||||
DecisionTreeRegressor<MSEGain> d(trainData, info, trainResponses);
|
||||
|
||||
// Get the predicted test labels.
|
||||
// Get the predicted test responses.
|
||||
arma::Row<double> predictions;
|
||||
d.Predict(testData, predictions);
|
||||
|
||||
REQUIRE(predictions.n_elem == testData.n_cols);
|
||||
|
||||
// Figure out rmse.
|
||||
double rmse = RMSE(predictions, testLabels);
|
||||
double rmse = RMSE(predictions, testResponses);
|
||||
|
||||
// REQUIRE(rmse < 9.21);
|
||||
// std::cout << predictions << std::endl << testLabels;
|
||||
// std::cout << predictions << std::endl << testResponses;
|
||||
arma::Row<double> trainPred;
|
||||
d.Predict(trainData, trainPred);
|
||||
// std::cout << trainPred;
|
||||
|
||||
std::cout << "Train RMSE: " << RMSE(trainLabels, trainPred) << std::endl;
|
||||
std::cout << "Train RMSE: " << RMSE(trainResponses, trainPred) << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -959,21 +967,21 @@ TEST_CASE("SimpleGeneralizationTest_", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("MultiSplitTest1", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat dataset;
|
||||
arma::rowvec labels;
|
||||
arma::rowvec responses;
|
||||
arma::rowvec values = {0.0, 1.0, 2.0, 1.0, 0.0};
|
||||
|
||||
CreateMultiSplitData(dataset, labels, 1000, values);
|
||||
CreateMultiSplitData(dataset, responses, 1000, values);
|
||||
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
// Minimum leaf size of 1.
|
||||
DecisionTreeRegressor<> d(dataset, labels, weights, 2, 0.0);
|
||||
DecisionTreeRegressor<> d(dataset, responses, weights, 2, 0.0);
|
||||
arma::rowvec preds;
|
||||
d.Predict(dataset, preds);
|
||||
|
||||
for (size_t i = 0; i < labels.n_elem; ++i)
|
||||
REQUIRE(preds[i] == labels[i]);
|
||||
for (size_t i = 0; i < responses.n_elem; ++i)
|
||||
REQUIRE(preds[i] == responses[i]);
|
||||
|
||||
REQUIRE(d.NumLeaves() == 5);
|
||||
}
|
||||
@@ -985,21 +993,21 @@ TEST_CASE("MultiSplitTest1", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("MultiSplitTest2", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat dataset;
|
||||
arma::rowvec labels;
|
||||
arma::rowvec responses;
|
||||
arma::rowvec values = {0.0, 1.0, 2.0, 1.0, 0.0};
|
||||
|
||||
CreateMultiSplitData(dataset, labels, 100, values);
|
||||
CreateMultiSplitData(dataset, responses, 100, values);
|
||||
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
// Minimum leaf size of 1.
|
||||
DecisionTreeRegressor<> d(dataset, labels, weights, 2, 0.0);
|
||||
DecisionTreeRegressor<> d(dataset, responses, weights, 2, 0.0);
|
||||
arma::rowvec preds;
|
||||
d.Predict(dataset, preds);
|
||||
|
||||
for (size_t i = 0; i < labels.n_elem; ++i)
|
||||
REQUIRE(preds[i] == labels[i]);
|
||||
for (size_t i = 0; i < responses.n_elem; ++i)
|
||||
REQUIRE(preds[i] == responses[i]);
|
||||
|
||||
REQUIRE(d.NumLeaves() == 5);
|
||||
}
|
||||
@@ -1027,21 +1035,21 @@ TEST_CASE("MultiSplitTest2", "[DecisionTreeRegressorTest]")
|
||||
TEST_CASE("MultiSplitTest3", "[DecisionTreeRegressorTest]")
|
||||
{
|
||||
arma::mat dataset;
|
||||
arma::Row<double> labels;
|
||||
arma::Row<double> responses;
|
||||
arma::rowvec values = {0.0, 5.0, 10.0, 15.0, 20.0};
|
||||
|
||||
CreateMultiSplitData(dataset, labels, 500, values);
|
||||
CreateMultiSplitData(dataset, responses, 500, values);
|
||||
|
||||
arma::rowvec weights(labels.n_elem);
|
||||
arma::rowvec weights(responses.n_elem);
|
||||
weights.ones();
|
||||
|
||||
// Minimum leaf size of 1.
|
||||
DecisionTreeRegressor<> d(dataset, labels, weights, 2, 0.0);
|
||||
DecisionTreeRegressor<> d(dataset, responses, weights, 2, 0.0);
|
||||
arma::rowvec preds;
|
||||
d.Predict(dataset, preds);
|
||||
|
||||
for (size_t i = 0; i < labels.n_elem; ++i)
|
||||
REQUIRE(preds[i] == labels[i]);
|
||||
for (size_t i = 0; i < responses.n_elem; ++i)
|
||||
REQUIRE(preds[i] == responses[i]);
|
||||
|
||||
REQUIRE(d.NumLeaves() == 5);
|
||||
}
|
||||
|
||||
@@ -83,20 +83,20 @@ inline void LogisticRegressionTestData(arma::mat& data,
|
||||
|
||||
inline void LoadBostonHousingDataset(arma::mat& trainData,
|
||||
arma::mat& testData,
|
||||
arma::Row<double>& trainLabels,
|
||||
arma::Row<double>& testLabels,
|
||||
arma::rowvec& trainResponses,
|
||||
arma::rowvec& testResponses,
|
||||
data::DatasetInfo& info)
|
||||
{
|
||||
arma::mat dataset;
|
||||
arma::Row<double> labels;
|
||||
arma::rowvec responses;
|
||||
|
||||
if (!data::Load("boston_housing_price.csv", dataset, info))
|
||||
FAIL("Cannot load test dataset boston_housing_price.csv!");
|
||||
if (!data::Load("boston_housing_price_labels.csv", labels))
|
||||
FAIL("Cannot load test dataset boston_housing_price_labels.csv!");
|
||||
if (!data::Load("boston_housing_price_responses.csv", responses))
|
||||
FAIL("Cannot load test dataset boston_housing_price_responses.csv!");
|
||||
|
||||
data::Split(dataset, labels, trainData, testData,
|
||||
trainLabels, testLabels, 0.3);
|
||||
data::Split(dataset, responses, trainData, testData,
|
||||
trainResponses, testResponses, 0.3);
|
||||
// info.Type(3) = data::Datatype::categorical;
|
||||
// info.Type(8) = data::Datatype::categorical;
|
||||
|
||||
@@ -115,9 +115,9 @@ inline void LoadBostonHousingDataset(arma::mat& trainData,
|
||||
}
|
||||
|
||||
inline double RMSE(const arma::Row<double>& predictions,
|
||||
const arma::Row<double>& trueLabels)
|
||||
const arma::Row<double>& trueResponses)
|
||||
{
|
||||
double mse = arma::accu(arma::square(predictions - trueLabels)) /
|
||||
double mse = arma::accu(arma::square(predictions - trueResponses)) /
|
||||
predictions.n_elem;
|
||||
return sqrt(mse);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user