001/*
002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.tribuo.classification.dtree;
018
019import com.oracle.labs.mlrg.olcut.config.Config;
020import org.tribuo.Dataset;
021import org.tribuo.Trainer;
022import org.tribuo.classification.Label;
023import org.tribuo.classification.dtree.impl.ClassifierTrainingNode;
024import org.tribuo.classification.dtree.impurity.GiniIndex;
025import org.tribuo.classification.dtree.impurity.LabelImpurity;
026import org.tribuo.common.tree.AbstractCARTTrainer;
027import org.tribuo.common.tree.AbstractTrainingNode;
028import org.tribuo.provenance.TrainerProvenance;
029import org.tribuo.provenance.impl.TrainerProvenanceImpl;
030
031/**
032 * A {@link org.tribuo.Trainer} that uses an approximation of the CART algorithm to build a decision tree.
033 * <p>
034 * See:
035 * <pre>
036 * J. Friedman, T. Hastie, &amp; R. Tibshirani.
037 * "The Elements of Statistical Learning"
038 * Springer 2001. <a href="http://web.stanford.edu/~hastie/ElemStatLearn/">PDF</a>
039 * </pre>
040 */
041public class CARTClassificationTrainer extends AbstractCARTTrainer<Label> {
042
043    /**
044     * Impurity measure used to determine split quality.
045     */
046    @Config(description = "The impurity measure used to determine split quality.")
047    private LabelImpurity impurity = new GiniIndex();
048
049    /**
050     * Creates a CART Trainer.
051     *
052     * @param maxDepth The maximum depth of the tree.
053     * @param minChildWeight The minimum node weight to consider it for a split.
054     * @param minImpurityDecrease The minimum decrease in impurity necessary to split a node.
055     * @param fractionFeaturesInSplit The fraction of features available in each split.
056     * @param useRandomSplitPoints Whether to choose split points for features at random.
057     * @param impurity Impurity measure to determine split quality. See {@link LabelImpurity}.
058     * @param seed The RNG seed.
059     */
060    public CARTClassificationTrainer(
061            int maxDepth,
062            float minChildWeight,
063            float minImpurityDecrease,
064            float fractionFeaturesInSplit,
065            boolean useRandomSplitPoints,
066            LabelImpurity impurity,
067            long seed
068    ) {
069        super(maxDepth, minChildWeight, minImpurityDecrease, fractionFeaturesInSplit, useRandomSplitPoints, seed);
070        this.impurity = impurity;
071        postConfig();
072    }
073
074    /**
075     * Creates a CART Trainer.
076     * <p>
077     * Sets the impurity to the {@link GiniIndex}, uses all the features,
078     * builds an arbitrary depth tree, computes the exact split point
079     * and sets the minimum number of examples in a leaf to {@link #MIN_EXAMPLES}.
080     */
081    public CARTClassificationTrainer() {
082        this(Integer.MAX_VALUE);
083    }
084
085    /**
086     * Creates a CART trainer.
087     * <p>
088     * Sets the impurity to the {@link GiniIndex}, uses all the features,
089     * computes the exact split point and sets the minimum number of
090     * examples in a leaf to {@link #MIN_EXAMPLES}.
091     * @param maxDepth The maximum depth of the tree.
092     */
093    public CARTClassificationTrainer(int maxDepth) {
094        this(maxDepth, MIN_EXAMPLES, 0.0f, 1.0f, false, new GiniIndex(), Trainer.DEFAULT_SEED);
095    }
096
097    /**
098     * Creates a CART Trainer.
099     * <p>
100     * Sets the impurity to the {@link GiniIndex}.
101     * @param maxDepth The maximum depth of the tree.
102     * @param fractionFeaturesInSplit The fraction of features available in each split.
103     * @param seed The seed for the RNG.
104     */
105    public CARTClassificationTrainer(int maxDepth, float fractionFeaturesInSplit, long seed) {
106        this(maxDepth, MIN_EXAMPLES, 0.0f, fractionFeaturesInSplit, false, new GiniIndex(), seed);
107    }
108
109    /**
110     * Creates a CART Trainer.
111     * <p>
112     * Sets the impurity to the {@link GiniIndex}. Computes the exact split point.
113     * @param maxDepth The maximum depth of the tree.
114     * @param fractionFeaturesInSplit The fraction of features available in each split.
115     * @param useRandomSplitPoints Whether to choose split points for features at random.
116     * @param seed The seed for the RNG.
117     */
118    public CARTClassificationTrainer(int maxDepth, float fractionFeaturesInSplit,
119                                     boolean useRandomSplitPoints, long seed) {
120        this(maxDepth, MIN_EXAMPLES, 0.0f, fractionFeaturesInSplit, useRandomSplitPoints, new GiniIndex(), seed);
121    }
122
123    /**
124     * Creates a CART Trainer.
125     * <p>
126     * Computes the exact split point.
127     * @param maxDepth The maximum depth of the tree.
128     * @param minChildWeight The minimum node weight to consider it for a split.
129     * @param minImpurityDecrease The minimum decrease in impurity necessary to split a node.
130     * @param fractionFeaturesInSplit The fraction of features available in each split.
131     * @param impurity Impurity measure to determine split quality. See {@link LabelImpurity}.
132     * @param seed The RNG seed.
133     */
134    public CARTClassificationTrainer(
135            int maxDepth,
136            float minChildWeight,
137            float minImpurityDecrease,
138            float fractionFeaturesInSplit,
139            LabelImpurity impurity,
140            long seed
141    ) {
142        this(maxDepth, minChildWeight, minImpurityDecrease, fractionFeaturesInSplit, false, impurity, seed);
143    }
144
145    @Override
146    protected AbstractTrainingNode<Label> mkTrainingNode(Dataset<Label> examples,
147                                                         AbstractTrainingNode.LeafDeterminer leafDeterminer) {
148        return new ClassifierTrainingNode(impurity, examples, leafDeterminer);
149    }
150
151    @Override
152    public String toString() {
153        StringBuilder buffer = new StringBuilder();
154
155        buffer.append("CARTClassificationTrainer(maxDepth=");
156        buffer.append(maxDepth);
157        buffer.append(",minChildWeight=");
158        buffer.append(minChildWeight);
159        buffer.append(",minImpurityDecrease=");
160        buffer.append(minImpurityDecrease);
161        buffer.append(",fractionFeaturesInSplit=");
162        buffer.append(fractionFeaturesInSplit);
163        buffer.append(",useRandomSplitPoints=");
164        buffer.append(useRandomSplitPoints);
165        buffer.append(",impurity=");
166        buffer.append(impurity.toString());
167        buffer.append(",seed=");
168        buffer.append(seed);
169        buffer.append(")");
170
171        return buffer.toString();
172    }
173
174    @Override
175    public TrainerProvenance getProvenance() {
176        return new TrainerProvenanceImpl(this);
177    }
178}