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 an Extremely Randomized Tree Ensemble. 028 * <p> 029 * Extremely Randomized Trees are similar to Random Forests, but they add an extra element of randomness in that 030 * the split points for features are also chosen randomly. As with Random Forests, feature subsampling is available at 031 * each of the nodes. 032 * An exception will be thrown if the inner trainer is not a decision tree trainer or if random splitting is turned off. 033 * <p> 034 * See: 035 * <pre> 036 * P. Geurts, D. Ernst, L. Wehenkel. 037 * "Extremely Randomized Trees" 038 * March 2006. <a href="https://link.springer.com/article/10.1007/s10994-006-6226-1">PDF</a> 039 * </pre> 040 * 041 */ 042public class ExtraTreesTrainer<T extends Output<T>> extends BaggingTrainer<T> { 043 044 private static final Logger logger = Logger.getLogger(ExtraTreesTrainer.class.getName()); 045 046 /** 047 * For the configuration system. 048 */ 049 private ExtraTreesTrainer() { } 050 051 /** 052 * Constructs an ExtraTreesTrainer with the default seed {@link org.tribuo.Trainer#DEFAULT_SEED}. 053 * <p> 054 * Throws {@link PropertyException} if the trainer is not set to use random split points. 055 * @param trainer The tree trainer. 056 * @param combiner The combining function for the ensemble. 057 * @param numMembers The number of ensemble members to train. 058 */ 059 public ExtraTreesTrainer(DecisionTreeTrainer<T> trainer, EnsembleCombiner<T> combiner, int numMembers) { 060 super(trainer,combiner,numMembers); 061 postConfig(); 062 } 063 064 /** 065 * Constructs an ExtraTreesTrainer with the supplied seed, trainer, combining function and number of members. 066 * <p> 067 * Throws {@link PropertyException} if the trainer is not set to use random split points. 068 * @param trainer The tree trainer. 069 * @param combiner The combining function for the ensemble. 070 * @param numMembers The number of ensemble members to train. 071 * @param seed The RNG seed. 072 */ 073 public ExtraTreesTrainer(DecisionTreeTrainer<T> trainer, EnsembleCombiner<T> combiner, int numMembers, long seed) { 074 super(trainer,combiner,numMembers,seed); 075 postConfig(); 076 } 077 078 @Override 079 public void postConfig() { 080 super.postConfig(); 081 if (!(innerTrainer instanceof DecisionTreeTrainer)) { 082 throw new PropertyException("","innerTrainer","ExtraTreesTrainer requires a decision tree innerTrainer"); 083 } 084 DecisionTreeTrainer<T> t = (DecisionTreeTrainer<T>) innerTrainer; 085 if (!t.getUseRandomSplitPoints()) { 086 throw new PropertyException("","innerTrainer","ExtraTreesTrainer requires that the decision tree " + 087 "innerTrainer have random split points turned on."); 088 } 089 } 090 091 @Override 092 protected String ensembleName() { 093 return "extra-trees-ensemble"; 094 } 095 096 @Override 097 public String toString() { 098 StringBuilder buffer = new StringBuilder(); 099 100 buffer.append("ExtraTreesTrainer("); 101 buffer.append("innerTrainer="); 102 buffer.append(innerTrainer.toString()); 103 buffer.append(",combiner="); 104 buffer.append(combiner.toString()); 105 buffer.append(",numMembers="); 106 buffer.append(numMembers); 107 buffer.append(",seed="); 108 buffer.append(seed); 109 buffer.append(")"); 110 111 return buffer.toString(); 112 } 113 114} 115