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.common.tree; 018 019import com.oracle.labs.mlrg.olcut.config.PropertyException; 020import org.tribuo.Output; 021import org.tribuo.ensemble.BaggingTrainer; 022import org.tribuo.ensemble.EnsembleCombiner; 023 024import java.util.logging.Logger; 025 026/** 027 * A trainer which produces a random forest. 028 * <p> 029 * Random Forests are basically bagged trees, with feature subsampling at each of the nodes. 030 * An exception will be thrown if the user does not supply a decision tree trainer with feature subsampling turned on 031 * and random splitting turned off. 032 * <p> 033 * See: 034 * <pre> 035 * J. Friedman, T. Hastie, & R. Tibshirani. 036 * "The Elements of Statistical Learning" 037 * Springer 2001. <a href="http://web.stanford.edu/~hastie/ElemStatLearn/">PDF</a> 038 * </pre> 039 */ 040public class RandomForestTrainer<T extends Output<T>> extends BaggingTrainer<T> { 041 042 private static final Logger logger = Logger.getLogger(RandomForestTrainer.class.getName()); 043 044 /** 045 * For the configuration system. 046 */ 047 private RandomForestTrainer() { } 048 049 /** 050 * Constructs a RandomForestTrainer with the default seed {@link org.tribuo.Trainer#DEFAULT_SEED}. 051 * <p> 052 * Throws {@link PropertyException} if the trainer is not set to subsample the features. 053 * @param trainer The tree trainer. 054 * @param combiner The combining function for the ensemble. 055 * @param numMembers The number of ensemble members to train. 056 */ 057 public RandomForestTrainer(DecisionTreeTrainer<T> trainer, EnsembleCombiner<T> combiner, int numMembers) { 058 super(trainer,combiner,numMembers); 059 postConfig(); 060 } 061 062 /** 063 * Constructs a RandomForestTrainer with the supplied seed, trainer, combining function and number of members. 064 * <p> 065 * Throws {@link PropertyException} if the trainer is not set to subsample the features. 066 * @param trainer The tree trainer. 067 * @param combiner The combining function for the ensemble. 068 * @param numMembers The number of ensemble members to train. 069 * @param seed The RNG seed. 070 */ 071 public RandomForestTrainer(DecisionTreeTrainer<T> trainer, EnsembleCombiner<T> combiner, int numMembers, long seed) { 072 super(trainer,combiner,numMembers,seed); 073 postConfig(); 074 } 075 076 /** 077 * Used by the OLCUT configuration system, and should not be called by external code. 078 */ 079 @Override 080 public void postConfig() { 081 super.postConfig(); 082 if (!(innerTrainer instanceof DecisionTreeTrainer)) { 083 throw new PropertyException("","innerTrainer","RandomForestTrainer requires a decision tree innerTrainer"); 084 } 085 086 DecisionTreeTrainer<T> t = (DecisionTreeTrainer<T>) innerTrainer; 087 if (t.getFractionFeaturesInSplit() == 1f) { 088 throw new PropertyException("","innerTrainer","RandomForestTrainer requires that the decision tree " + 089 "innerTrainer have fractional features in split."); 090 } 091 092 if (t.getUseRandomSplitPoints()) { 093 throw new PropertyException("","innerTrainer","RandomForestTrainer requires that the decision tree " + 094 "use non-random splitting, but useRandomSplits was true. If you want random splits, use " + 095 "ExtraTreesTrainer instead."); 096 } 097 } 098 099 @Override 100 protected String ensembleName() { 101 return "random-forest-ensemble"; 102 } 103 104 @Override 105 public String toString() { 106 StringBuilder buffer = new StringBuilder(); 107 108 buffer.append("RandomForestTrainer("); 109 buffer.append("innerTrainer="); 110 buffer.append(innerTrainer.toString()); 111 buffer.append(",combiner="); 112 buffer.append(combiner.toString()); 113 buffer.append(",numMembers="); 114 buffer.append(numMembers); 115 buffer.append(",seed="); 116 buffer.append(seed); 117 buffer.append(")"); 118 119 return buffer.toString(); 120 } 121 122}