PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // ToBagClassifier.cc 00004 // 00005 // Copyright (C) 2007 Olivier Delalleau 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions are met: 00009 // 00010 // 1. Redistributions of source code must retain the above copyright 00011 // notice, this list of conditions and the following disclaimer. 00012 // 00013 // 2. Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // 3. The name of the authors may not be used to endorse or promote 00018 // products derived from this software without specific prior written 00019 // permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // This file is part of the PLearn library. For more information on the PLearn 00033 // library, go to the PLearn Web site at www.plearn.org 00034 00035 // Authors: Olivier Delalleau 00036 00040 #include "ToBagClassifier.h" 00041 #include <plearn/var/SumOverBagsVariable.h> 00042 #include <plearn/vmat/SubVMatrix.h> 00043 00044 namespace PLearn { 00045 using namespace std; 00046 00047 PLEARN_IMPLEMENT_OBJECT( 00048 ToBagClassifier, 00049 "Makes an existing classifier operate on bags.", 00050 "Training is performed by simply removing bag information.\n" 00051 "For testing, a majority vote is performed on each bag: assuming the\n" 00052 "inner learner's output is made of the probabilities for each class,\n" 00053 "these probabilities are summed over a full bag, and the class with\n" 00054 "highest sum is taken as prediction.\n" 00055 "This learner can also compute the confusion matrix as a test cost, in\n" 00056 "addition to classification error. Each element of the confusion matrix\n" 00057 "is named 'cm_ij' with i the index of the true class, and j the index of\n" 00058 "the predicted class.\n" 00059 "The underlying classifier may choose to not make any prediction on some\n" 00060 "of the elements in the bag, in which case it should just return as\n" 00061 "output a vector of missing values."); 00062 00064 // ToBagClassifier // 00066 ToBagClassifier::ToBagClassifier(): 00067 n_classes(-1) 00068 {} 00069 00071 // declareOptions // 00073 void ToBagClassifier::declareOptions(OptionList& ol) 00074 { 00075 declareOption(ol, "n_classes", &ToBagClassifier::n_classes, 00076 OptionBase::buildoption, 00077 "Number of classes in the dataset. This option is required to\n" 00078 "compute the confusion matrix, but may be ignored otherwise."); 00079 00080 // Now call the parent class' declareOptions 00081 inherited::declareOptions(ol); 00082 } 00083 00085 // build_ // 00087 void ToBagClassifier::build_() 00088 { 00089 } 00090 00092 // build // 00094 void ToBagClassifier::build() 00095 { 00096 inherited::build(); 00097 build_(); 00098 } 00099 00101 // computeCostsFromOutputs // 00103 void ToBagClassifier::computeCostsFromOutputs(const Vec& input, 00104 const Vec& output, 00105 const Vec& target, 00106 Vec& costs) const 00107 { 00108 fillSubTarget(target); 00109 inherited::computeCostsFromOutputs(input, output, sub_target, costs); 00110 updateCostAndBagOutput(target, output, costs); 00111 } 00112 00114 // computeOutputAndCosts // 00116 void ToBagClassifier::computeOutputAndCosts(const Vec& input, 00117 const Vec& target, 00118 Vec& output, Vec& costs) const 00119 { 00120 fillSubTarget(target); 00121 inherited::computeOutputAndCosts(input, sub_target, output, costs); 00122 updateCostAndBagOutput(target, output, costs); 00123 } 00124 00126 // fillSubTarget // 00128 void ToBagClassifier::fillSubTarget(const Vec& target) const 00129 { 00130 sub_target.resize(target.length() - 1); 00131 sub_target << target.subVec(0, sub_target.length()); 00132 } 00133 00134 00136 // getTestCostNames // 00138 TVec<string> ToBagClassifier::getTestCostNames() const 00139 { 00140 TVec<string> costs; 00141 costs.append("class_error"); 00142 if (n_classes > 0) 00143 for (int i = 0; i < n_classes; i++) 00144 for (int j = 0; j < n_classes; j++) 00145 costs.append("cm_" + tostring(i) + tostring(j)); 00146 return costs; 00147 } 00148 00150 // makeDeepCopyFromShallowCopy // 00152 void ToBagClassifier::makeDeepCopyFromShallowCopy(CopiesMap& copies) 00153 { 00154 inherited::makeDeepCopyFromShallowCopy(copies); 00155 deepCopyField(sub_target, copies); 00156 deepCopyField(bag_output, copies); 00157 deepCopyField(votes, copies); 00158 } 00159 00161 // setTrainingSet // 00163 void ToBagClassifier::setTrainingSet(VMat training_set, bool call_forget) 00164 { 00165 // Remove bag information (last target). 00166 PLCHECK( training_set->weightsize() == 0 && 00167 training_set->extrasize() == 0 ); // Not compatible yet. 00168 PP<SubVMatrix> sub_train_set = new SubVMatrix(training_set, 0, 0, 00169 training_set->length(), 00170 training_set->width() - 1); 00171 sub_train_set->defineSizes(training_set->inputsize(), 00172 training_set->targetsize() - 1, 00173 training_set->weightsize(), 00174 training_set->extrasize()); 00175 setInnerLearnerTrainingSet(get_pointer(sub_train_set), call_forget); 00176 PLearner::setTrainingSet(training_set, call_forget); 00177 } 00178 00180 // targetsize // 00182 int ToBagClassifier::targetsize() const 00183 { 00184 return learner_->targetsize() + 1; 00185 } 00186 00188 // updateCostAndBagOutput // 00190 void ToBagClassifier::updateCostAndBagOutput(const Vec& target, 00191 const Vec& output, 00192 Vec& costs) const 00193 { 00194 costs.resize(nTestCosts()); 00195 costs.fill(MISSING_VALUE); 00196 00197 int bag_info = int(round(target.lastElement())); 00198 if (bag_info & SumOverBagsVariable::TARGET_COLUMN_FIRST) 00199 bag_output.resize(0, 0); 00200 00201 // Ignore missing outputs from learner. 00202 if (is_missing(output[0])) { 00203 #ifdef BOUNDCHECK 00204 for (int i = 1; i < output.length(); i++) { 00205 PLASSERT( is_missing(output[i]) ); 00206 } 00207 #endif 00208 return; 00209 } 00210 // Ensure the distribution probabilities sum to 1. We relax a 00211 // bit the default tolerance as probabilities using 00212 // exponentials could suffer numerical imprecisions. 00213 PLASSERT( is_equal( sum(output), 1., 1., 1e-5, 1e-5 ) ); 00214 bag_output.appendRow(output); 00215 if (bag_info & SumOverBagsVariable::TARGET_COLUMN_LAST) { 00216 // Perform majority vote. 00217 votes.resize(bag_output.width()); 00218 columnSum(bag_output, votes); 00219 int target_class = int(round(target[0])); 00220 int prediction = argmax(votes); 00221 if (prediction == target_class) 00222 costs[0] = 0; 00223 else 00224 costs[0] = 1; 00225 if (n_classes > 0) { 00226 int i_start = 1 + target_class * n_classes; 00227 costs.subVec(i_start, n_classes).fill(0); 00228 costs[i_start + prediction] = 1; 00229 } 00230 } 00231 } 00232 00233 } // end of namespace PLearn 00234 00235 /* 00236 Local Variables: 00237 mode:c++ 00238 c-basic-offset:4 00239 c-file-style:"stroustrup" 00240 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00241 indent-tabs-mode:nil 00242 fill-column:79 00243 End: 00244 */ 00245 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :