PLearn 0.1
ToBagClassifier.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines