The `using` keyword improves readability simply be letting people read from left to right. Additionally some `typename` keywords have been removed, when they have not been required.
576 lines
24 KiB
C++
576 lines
24 KiB
C++
/**
|
|
* @file methods/hoeffding_trees/hoeffding_tree.hpp
|
|
* @author Ryan Curtin
|
|
*
|
|
* An implementation of the standard Hoeffding tree by Pedro Domingos and Geoff
|
|
* Hulten in ``Mining High-Speed Data Streams''.
|
|
*
|
|
* mlpack is free software; you may redistribute it and/or modify it under the
|
|
* terms of the 3-clause BSD license. You should have received a copy of the
|
|
* 3-clause BSD license along with mlpack. If not, see
|
|
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
|
|
*/
|
|
#ifndef MLPACK_METHODS_HOEFFDING_TREES_HOEFFDING_TREE_HPP
|
|
#define MLPACK_METHODS_HOEFFDING_TREES_HOEFFDING_TREE_HPP
|
|
|
|
#include <mlpack/core.hpp>
|
|
|
|
#include "categorical_split_info.hpp"
|
|
#include "numeric_split_info.hpp"
|
|
|
|
#include "gini_impurity.hpp"
|
|
#include "information_gain.hpp"
|
|
|
|
#include "hoeffding_numeric_split.hpp"
|
|
#include "binary_numeric_split.hpp"
|
|
|
|
#include "hoeffding_categorical_split.hpp"
|
|
|
|
namespace mlpack {
|
|
|
|
/**
|
|
* The HoeffdingTree object represents all of the necessary information for a
|
|
* Hoeffding-bound-based decision tree. This class is able to train on samples
|
|
* in streaming settings and batch settings, and perform splits based on the
|
|
* Hoeffding bound. The Hoeffding tree (also known as the "very fast decision
|
|
* tree" -- VFDT) is described in the following paper:
|
|
*
|
|
* @code
|
|
* @inproceedings{domingos2000mining,
|
|
* title={{Mining High-Speed Data Streams}},
|
|
* author={Domingos, P. and Hulten, G.},
|
|
* year={2000},
|
|
* booktitle={Proceedings of the Sixth ACM SIGKDD International Conference
|
|
* on Knowledge Discovery and Data Mining (KDD '00)},
|
|
* pages={71--80}
|
|
* }
|
|
* @endcode
|
|
*
|
|
* The class is modular, and takes three template parameters. The first,
|
|
* FitnessFunction, is the fitness function that should be used to determine
|
|
* whether a split is beneficial; examples might be GiniImpurity or
|
|
* HoeffdingInformationGain. The NumericSplitType determines how numeric
|
|
* attributes are handled, and the CategoricalSplitType determines how
|
|
* categorical attributes are handled. As far as the actual splitting goes,
|
|
* the meat of the splitting procedure will be contained in those two classes.
|
|
*
|
|
* @tparam FitnessFunction Fitness function to use.
|
|
* @tparam NumericSplitType Technique for splitting numeric features.
|
|
* @tparam CategoricalSplitType Technique for splitting categorical features.
|
|
*/
|
|
template<typename FitnessFunction = GiniImpurity,
|
|
template<typename> class NumericSplitType =
|
|
HoeffdingDoubleNumericSplit,
|
|
template<typename> class CategoricalSplitType =
|
|
HoeffdingCategoricalSplit
|
|
>
|
|
class HoeffdingTree
|
|
{
|
|
public:
|
|
//! Allow access to the numeric split type.
|
|
using NumericSplit = NumericSplitType<FitnessFunction>;
|
|
//! Allow access to the categorical split type.
|
|
using CategoricalSplit = CategoricalSplitType<FitnessFunction>;
|
|
|
|
/**
|
|
* Construct a Hoeffding tree with no data and no information. Be sure to
|
|
* call Train() before trying to use the tree.
|
|
*/
|
|
HoeffdingTree();
|
|
|
|
/**
|
|
* Construct the Hoeffding tree with the given parameters for training on
|
|
* numerical data, but training on no data. The dimensionMappings parameter
|
|
* is only used if it is desired that this node does not create its own
|
|
* dimensionMappings object (for instance, if this is a child of another node
|
|
* in the tree).
|
|
*
|
|
* @param numClasses Number of classes in the dataset.
|
|
* @param successProbability Probability of success required in Hoeffding
|
|
* bound before a split can happen.
|
|
* @param maxSamples Maximum number of samples before a split is forced.
|
|
* @param checkInterval Number of samples required before each split check.
|
|
* @param minSamples If the node has seen this many points or fewer, no split
|
|
* will be allowed.
|
|
* @param categoricalSplitIn Optional instantiated categorical split object.
|
|
* @param numericSplitIn Optional instantiated numeric split object.
|
|
* @param dimensionMappings Mappings from dimension indices to positions in
|
|
* numeric and categorical split vectors. If left NULL, a new one will
|
|
* be created.
|
|
*/
|
|
HoeffdingTree(const size_t dimensionality,
|
|
const size_t numClasses,
|
|
const double successProbability = 0.95,
|
|
const size_t maxSamples = 0,
|
|
const size_t checkInterval = 100,
|
|
const size_t minSamples = 100,
|
|
const CategoricalSplitType<FitnessFunction>& categoricalSplitIn
|
|
= CategoricalSplitType<FitnessFunction>(0, 0),
|
|
const NumericSplitType<FitnessFunction>& numericSplitIn =
|
|
NumericSplitType<FitnessFunction>(0),
|
|
std::unordered_map<size_t, std::pair<size_t, size_t>>*
|
|
dimensionMappings = NULL);
|
|
|
|
/**
|
|
* Construct the Hoeffding tree with the given parameters, but training on no
|
|
* data. The dimensionMappings parameter is only used if it is desired that
|
|
* this node does not create its own dimensionMappings object (for instance,
|
|
* if this is a child of another node in the tree).
|
|
*
|
|
* @param datasetInfo Information on the dataset (types of each feature).
|
|
* @param numClasses Number of classes in the dataset.
|
|
* @param successProbability Probability of success required in Hoeffding
|
|
* bound before a split can happen.
|
|
* @param maxSamples Maximum number of samples before a split is forced.
|
|
* @param checkInterval Number of samples required before each split check.
|
|
* @param minSamples If the node has seen this many points or fewer, no split
|
|
* will be allowed.
|
|
* @param categoricalSplitIn Optional instantiated categorical split object.
|
|
* @param numericSplitIn Optional instantiated numeric split object.
|
|
* @param dimensionMappings Mappings from dimension indices to positions in
|
|
* numeric and categorical split vectors. If left NULL, a new one will
|
|
* be created.
|
|
* @param copyDatasetInfo If true, then a copy of the datasetInfo will be
|
|
* made.
|
|
*/
|
|
HoeffdingTree(const data::DatasetInfo& datasetInfo,
|
|
const size_t numClasses,
|
|
const double successProbability = 0.95,
|
|
const size_t maxSamples = 0,
|
|
const size_t checkInterval = 100,
|
|
const size_t minSamples = 100,
|
|
const CategoricalSplitType<FitnessFunction>& categoricalSplitIn
|
|
= CategoricalSplitType<FitnessFunction>(0, 0),
|
|
const NumericSplitType<FitnessFunction>& numericSplitIn =
|
|
NumericSplitType<FitnessFunction>(0),
|
|
std::unordered_map<size_t, std::pair<size_t, size_t>>*
|
|
dimensionMappings = NULL,
|
|
const bool copyDatasetInfo = true);
|
|
|
|
/**
|
|
* Construct the Hoeffding tree with the given parameters and given training
|
|
* data, where the training data contains only numerical features. The tree
|
|
* may be trained either in batch mode (which looks at all points before
|
|
* splitting, and propagates these points to the created children for further
|
|
* training), or in streaming mode, where each point is only considered once.
|
|
* (In general, batch mode will give better-performing trees, but will have
|
|
* higher memory and runtime costs for the same dataset.)
|
|
*
|
|
* @param data Dataset to train on.
|
|
* @param labels Labels of each point in the dataset.
|
|
* @param numClasses Number of classes in the dataset.
|
|
* @param batchTraining Whether or not to train in batch.
|
|
* @param successProbability Probability of success required in Hoeffding
|
|
* bounds before a split can happen.
|
|
* @param maxSamples Maximum number of samples before a split is forced (0
|
|
* never forces a split); ignored in batch training mode.
|
|
* @param checkInterval Number of samples required before each split; ignored
|
|
* in batch training mode.
|
|
* @param minSamples If the node has seen this many points or fewer, no split
|
|
* will be allowed.
|
|
* @param categoricalSplitIn Optional instantiated categorical split object.
|
|
* @param numericSplitIn Optional instantiated numeric split object.
|
|
*/
|
|
template<typename MatType>
|
|
HoeffdingTree(const MatType& data,
|
|
const arma::Row<size_t>& labels,
|
|
const size_t numClasses,
|
|
const bool batchTraining = true,
|
|
const double successProbability = 0.95,
|
|
const size_t maxSamples = 0,
|
|
const size_t checkInterval = 100,
|
|
const size_t minSamples = 100,
|
|
const CategoricalSplitType<FitnessFunction>& categoricalSplitIn
|
|
= CategoricalSplitType<FitnessFunction>(0, 0),
|
|
const NumericSplitType<FitnessFunction>& numericSplitIn =
|
|
NumericSplitType<FitnessFunction>(0));
|
|
|
|
/**
|
|
* Construct the Hoeffding tree with the given parameters and given training
|
|
* data. The tree may be trained either in batch mode (which looks at all
|
|
* points before splitting, and propagates these points to the created
|
|
* children for further training), or in streaming mode, where each point is
|
|
* only considered once. (In general, batch mode will give better-performing
|
|
* trees, but will have higher memory and runtime costs for the same dataset.)
|
|
*
|
|
* @param data Dataset to train on.
|
|
* @param datasetInfo Information on the dataset (types of each feature).
|
|
* @param labels Labels of each point in the dataset.
|
|
* @param numClasses Number of classes in the dataset.
|
|
* @param batchTraining Whether or not to train in batch.
|
|
* @param successProbability Probability of success required in Hoeffding
|
|
* bounds before a split can happen.
|
|
* @param maxSamples Maximum number of samples before a split is forced (0
|
|
* never forces a split); ignored in batch training mode.
|
|
* @param checkInterval Number of samples required before each split; ignored
|
|
* in batch training mode.
|
|
* @param minSamples If the node has seen this many points or fewer, no split
|
|
* will be allowed.
|
|
* @param categoricalSplitIn Optional instantiated categorical split object.
|
|
* @param numericSplitIn Optional instantiated numeric split object.
|
|
*/
|
|
template<typename MatType>
|
|
HoeffdingTree(const MatType& data,
|
|
const data::DatasetInfo& datasetInfo,
|
|
const arma::Row<size_t>& labels,
|
|
const size_t numClasses,
|
|
const bool batchTraining = true,
|
|
const double successProbability = 0.95,
|
|
const size_t maxSamples = 0,
|
|
const size_t checkInterval = 100,
|
|
const size_t minSamples = 100,
|
|
const CategoricalSplitType<FitnessFunction>& categoricalSplitIn
|
|
= CategoricalSplitType<FitnessFunction>(0, 0),
|
|
const NumericSplitType<FitnessFunction>& numericSplitIn =
|
|
NumericSplitType<FitnessFunction>(0));
|
|
|
|
/**
|
|
* Copy another tree (warning: this will duplicate the tree entirely, and may
|
|
* use a lot of memory. Make sure it's what you want before you do it).
|
|
*
|
|
* @param other Tree to copy.
|
|
*/
|
|
HoeffdingTree(const HoeffdingTree& other);
|
|
|
|
/**
|
|
* Move another tree.
|
|
*
|
|
* @param other Tree to move.
|
|
*/
|
|
HoeffdingTree(HoeffdingTree&& other);
|
|
|
|
/**
|
|
* Copy assignment operator.
|
|
*
|
|
* @param other Tree to copy.
|
|
*/
|
|
HoeffdingTree& operator=(const HoeffdingTree& other);
|
|
|
|
/**
|
|
* Move assignment operator.
|
|
*
|
|
* @param other Tree to move.
|
|
*/
|
|
HoeffdingTree& operator=(HoeffdingTree&& other);
|
|
|
|
/**
|
|
* Clean up memory.
|
|
*/
|
|
~HoeffdingTree();
|
|
|
|
/**
|
|
* Train on a set of points, either in streaming mode or in batch mode, with
|
|
* the given labels. If `resetTree` is set to `true`, then reset the state of
|
|
* the tree to an empty tree before training.
|
|
*
|
|
* Note that the tree will be automatically reset if the dimensionality of
|
|
* `data` does not match the dimensionality that the tree was currently
|
|
* trained with. The tree will also be reset if `numClasses` is passed and
|
|
* differs from the existing setting.
|
|
*
|
|
* @param data Data points to train on.
|
|
* @param labels Labels of data points.
|
|
* @param numClasses The number of classes in `labels`. Passing this will
|
|
* reset the tree. If not given and `resetTree` is `true`, then the
|
|
* number of classes will be computed from `labels`.
|
|
* @param batchTraining If true, perform training in batch.
|
|
* @param successProbability Probability of success required in Hoeffding
|
|
* bounds before a split can happen.
|
|
* @param maxSamples Maximum number of samples before a split is forced (0
|
|
* never forces a split); ignored in batch training mode.
|
|
* @param checkInterval Number of samples required before each split; ignored
|
|
* in batch training mode.
|
|
* @param minSamples If the node has seen this many points or fewer, no split
|
|
* will be allowed.
|
|
*/
|
|
template<typename MatType>
|
|
void Train(const MatType& data,
|
|
const arma::Row<size_t>& labels,
|
|
const size_t numClasses = 0,
|
|
const bool batchTraining = true,
|
|
const std::optional<double> successProbability = std::nullopt,
|
|
const std::optional<size_t> maxSamples = std::nullopt,
|
|
const std::optional<size_t> checkInterval = std::nullopt);
|
|
|
|
template<typename MatType>
|
|
void Train(const MatType& data,
|
|
const arma::Row<size_t>& labels,
|
|
const size_t numClasses,
|
|
const bool batchTraining,
|
|
const double successProbability,
|
|
const size_t maxSamples,
|
|
const size_t checkInterval,
|
|
const size_t minSamples);
|
|
|
|
/**
|
|
* Train on a set of points, either in streaming mode or in batch mode, with
|
|
* the given labels. If `resetTree` is set to `true`, then reset the state of
|
|
* the tree to an empty tree before training.
|
|
*
|
|
* Note that the tree will be automatically reset if the dimensionality of
|
|
* `data` does not match the dimensionality that the tree was currently
|
|
* trained with. The tree will also be reset if `numClasses` is passed and
|
|
* differs from the existing setting.
|
|
*
|
|
* @param data Data points to train on.
|
|
* @param datasetInfo Information on the dataset (types of each feature).
|
|
* @param labels Labels of data points.
|
|
* @param numClasses The number of classes in `labels`. Passing this will
|
|
* reset the tree. If not given and `resetTree` is `true`, then the
|
|
* number of classes will be computed from `labels`.
|
|
* @param batchTraining If true, perform training in batch.
|
|
* @param successProbability Probability of success required in Hoeffding
|
|
* bounds before a split can happen.
|
|
* @param maxSamples Maximum number of samples before a split is forced (0
|
|
* never forces a split); ignored in batch training mode.
|
|
* @param checkInterval Number of samples required before each split; ignored
|
|
* in batch training mode.
|
|
* @param minSamples If the node has seen this many points or fewer, no split
|
|
* will be allowed.
|
|
*/
|
|
template<typename MatType>
|
|
void Train(const MatType& data,
|
|
const data::DatasetInfo& info,
|
|
const arma::Row<size_t>& labels,
|
|
const size_t numClasses = 0,
|
|
const bool batchTraining = true,
|
|
const std::optional<double> successProbability = std::nullopt,
|
|
const std::optional<size_t> maxSamples = std::nullopt,
|
|
const std::optional<size_t> checkInterval = std::nullopt);
|
|
|
|
template<typename MatType>
|
|
void Train(const MatType& data,
|
|
const data::DatasetInfo& info,
|
|
const arma::Row<size_t>& labels,
|
|
const size_t numClasses,
|
|
const bool batchTraining,
|
|
const double successProbability,
|
|
const size_t maxSamples,
|
|
const size_t checkInterval,
|
|
const size_t minSamples);
|
|
|
|
/**
|
|
* Train on a single point in streaming mode, with the given label. The tree
|
|
* will not be reset before training.
|
|
*
|
|
* @param point Point to train on.
|
|
* @param label Label of point to train on.
|
|
*/
|
|
template<typename VecType>
|
|
void Train(const VecType& point, const size_t label);
|
|
|
|
/**
|
|
* Check if a split would satisfy the conditions of the Hoeffding bound with
|
|
* the node's specified success probability. If so, the number of children
|
|
* that would be created is returned. If not, 0 is returned.
|
|
*/
|
|
size_t SplitCheck();
|
|
|
|
//! Get the splitting dimension (size_t(-1) if no split).
|
|
size_t SplitDimension() const { return splitDimension; }
|
|
|
|
//! Get the majority class.
|
|
size_t MajorityClass() const { return majorityClass; }
|
|
//! Modify the majority class.
|
|
size_t& MajorityClass() { return majorityClass; }
|
|
|
|
//! Get the probability of the majority class (based on training samples).
|
|
double MajorityProbability() const { return majorityProbability; }
|
|
//! Modify the probability of the majority class.
|
|
double& MajorityProbability() { return majorityProbability; }
|
|
|
|
//! Get the number of children.
|
|
size_t NumChildren() const { return children.size(); }
|
|
|
|
//! Get a child.
|
|
const HoeffdingTree& Child(const size_t i) const { return *children[i]; }
|
|
//! Modify a child.
|
|
HoeffdingTree& Child(const size_t i) { return *children[i]; }
|
|
|
|
//! Get the confidence required for a split.
|
|
double SuccessProbability() const { return successProbability; }
|
|
//! Modify the confidence required for a split.
|
|
void SuccessProbability(const double successProbability);
|
|
|
|
//! Get the minimum number of samples for a split.
|
|
size_t MinSamples() const { return minSamples; }
|
|
//! Modify the minimum number of samples for a split.
|
|
void MinSamples(const size_t minSamples);
|
|
|
|
//! Get the maximum number of samples before a split is forced.
|
|
size_t MaxSamples() const { return maxSamples; }
|
|
//! Modify the maximum number of samples before a split is forced.
|
|
void MaxSamples(const size_t maxSamples);
|
|
|
|
//! Get the number of samples before a split check is performed.
|
|
size_t CheckInterval() const { return checkInterval; }
|
|
//! Modify the number of samples before a split check is performed.
|
|
void CheckInterval(const size_t checkInterval);
|
|
|
|
//! Get the number of points seen so far.
|
|
size_t NumSamples() const { return numSamples; }
|
|
|
|
//! Get the number of classes the tree is trained on.
|
|
size_t NumClasses() const { return numClasses; }
|
|
|
|
/**
|
|
* Given a point and that this node is not a leaf, calculate the index of the
|
|
* child node this point would go towards. This method is primarily used by
|
|
* the Classify() function, but it can be used in a standalone sense too.
|
|
*
|
|
* @param point Point to classify.
|
|
*/
|
|
template<typename VecType>
|
|
size_t CalculateDirection(const VecType& point) const;
|
|
|
|
//! Get the size of the Hoeffding Tree.
|
|
size_t NumDescendants() const;
|
|
|
|
/**
|
|
* Classify the given point, using this node and the entire (sub)tree beneath
|
|
* it. The predicted label is returned.
|
|
*
|
|
* @param point Point to classify.
|
|
* @return Predicted label of point.
|
|
*/
|
|
template<typename VecType>
|
|
size_t Classify(const VecType& point) const;
|
|
|
|
/**
|
|
* Classify the given point and also return an estimate of the probability
|
|
* that the prediction is correct. (This estimate is simply the probability
|
|
* that a training point was from the majority class in the leaf that this
|
|
* point binned to.)
|
|
*
|
|
* @param point Point to classify.
|
|
* @param prediction Predicted label of point.
|
|
* @param probability An estimate of the probability that the prediction is
|
|
* correct.
|
|
*/
|
|
template<typename VecType>
|
|
void Classify(const VecType& point, size_t& prediction, double& probability)
|
|
const;
|
|
|
|
/**
|
|
* Classify the given points, using this node and the entire (sub)tree beneath
|
|
* it. The predicted labels for each point are returned.
|
|
*
|
|
* @param data Points to classify.
|
|
* @param predictions Predicted labels for each point.
|
|
*/
|
|
template<typename MatType>
|
|
void Classify(const MatType& data, arma::Row<size_t>& predictions) const;
|
|
|
|
/**
|
|
* Classify the given points, using this node and the entire (sub)tree beneath
|
|
* it. The predicted labels for each point are returned, as well as an
|
|
* estimate of the probability that the prediction is correct for each point.
|
|
* This estimate is simply the MajorityProbability() for the leaf that each
|
|
* point bins to.
|
|
*
|
|
* @param data Points to classify.
|
|
* @param predictions Predicted labels for each point.
|
|
* @param probabilities Probability estimates for each predicted label.
|
|
*/
|
|
template<typename MatType>
|
|
void Classify(const MatType& data,
|
|
arma::Row<size_t>& predictions,
|
|
arma::rowvec& probabilities) const;
|
|
|
|
/**
|
|
* Given that this node should split, create the children.
|
|
*/
|
|
void CreateChildren();
|
|
|
|
/**
|
|
* Reset the tree, keeping the number of classes and dimension information
|
|
* intact.
|
|
*/
|
|
void Reset();
|
|
|
|
/**
|
|
* Reset the tree, setting a new number of classes and dimensionality. This
|
|
* assumes all dimensions are numeric.
|
|
*/
|
|
void Reset(const size_t dimensionality, const size_t numClasses);
|
|
|
|
/**
|
|
* Reset the tree, setting a new number of classes and a new datasetInfo.
|
|
*/
|
|
void Reset(const data::DatasetInfo& datasetInfo, const size_t numClasses);
|
|
|
|
//! Serialize the split.
|
|
template<typename Archive>
|
|
void serialize(Archive& ar, const uint32_t /* version */);
|
|
|
|
private:
|
|
// We need to keep some information for before we have split.
|
|
|
|
//! Information for splitting of numeric features (used before split).
|
|
std::vector<NumericSplitType<FitnessFunction>> numericSplits;
|
|
//! Information for splitting of categorical features (used before split).
|
|
std::vector<CategoricalSplitType<FitnessFunction>> categoricalSplits;
|
|
|
|
//! This structure is owned by this node only if it is the root of the tree.
|
|
std::unordered_map<size_t, std::pair<size_t, size_t>>* dimensionMappings;
|
|
//! Indicates whether or not we own the mappings.
|
|
bool ownsMappings;
|
|
|
|
//! The number of samples seen so far by this node.
|
|
size_t numSamples;
|
|
//! The number of classes this node is trained on.
|
|
size_t numClasses;
|
|
//! The maximum number of samples we can see before splitting.
|
|
size_t maxSamples;
|
|
//! The number of samples that should be seen before checking for a split.
|
|
size_t checkInterval;
|
|
//! The minimum number of samples for splitting.
|
|
size_t minSamples;
|
|
//! The dataset information.
|
|
const data::DatasetInfo* datasetInfo;
|
|
//! Whether or not we own the dataset information.
|
|
bool ownsInfo;
|
|
//! The required probability of success for a split to be performed.
|
|
double successProbability;
|
|
|
|
// And we need to keep some information for after we have split.
|
|
|
|
//! The dimension that this node has split on.
|
|
size_t splitDimension;
|
|
//! The majority class of this node.
|
|
size_t majorityClass;
|
|
//! The empirical probability of a point this node saw having the majority
|
|
//! class.
|
|
double majorityProbability;
|
|
//! If the split is categorical, this holds the splitting information.
|
|
typename CategoricalSplitType<FitnessFunction>::SplitInfo categoricalSplit;
|
|
//! If the split is numeric, this holds the splitting information.
|
|
typename NumericSplitType<FitnessFunction>::SplitInfo numericSplit;
|
|
//! If the split has occurred, these are the children.
|
|
std::vector<HoeffdingTree*> children;
|
|
|
|
/**
|
|
* Perform training (typically after a reset, but not necessarily). This
|
|
* assumes datasetInfo and dimensionMappings are set correctly.
|
|
*/
|
|
template<typename MatType>
|
|
void TrainInternal(const MatType& data,
|
|
const arma::Row<size_t>& labels,
|
|
const bool batchTraining);
|
|
|
|
/**
|
|
* Reset the tree. This assumes datasetInfo is set correctly.
|
|
*/
|
|
void ResetTree(
|
|
const CategoricalSplitType<FitnessFunction>& categoricalSplitIn =
|
|
CategoricalSplitType<FitnessFunction>(0, 0),
|
|
const NumericSplitType<FitnessFunction>& numericSplitIn =
|
|
NumericSplitType<FitnessFunction>(0));
|
|
};
|
|
|
|
} // namespace mlpack
|
|
|
|
#include "hoeffding_tree_impl.hpp"
|
|
|
|
#endif
|