PLearn 0.1
MultiTargetOneHotVMatrix.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // MultiTargetOneHotVMatrix.cc
00004 //
00005 // Copyright (C) 2004 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 /* *******************************************************      
00036    * $Id: MultiTargetOneHotVMatrix.cc,v 1.7 2005/03/16 18:26:25 delallea Exp $ 
00037    ******************************************************* */
00038 
00039 // Authors: Olivier Delalleau
00040 
00044 #include "MultiTargetOneHotVMatrix.h"
00045 #include <plearn/math/TMat_maths.h>
00046 
00047 namespace PLearn {
00048 using namespace std;
00049 
00051 // MultiTargetOneHotVMatrix //
00053 MultiTargetOneHotVMatrix::MultiTargetOneHotVMatrix()
00054 : missing_target(-FLT_MAX),
00055   reweight_targets(false),
00056   target_val("specific_target"),
00057   verbosity(1),
00058   hot_value(1),
00059   cold_value(0)
00060 {
00061 }
00062 
00063 PLEARN_IMPLEMENT_OBJECT(MultiTargetOneHotVMatrix,
00064     "This VMatrix transforms a multi-target source into a single target one with an added one-hot vector.",
00065     "The source VMatrix is given by its input part (in 'source'), and by its target part\n"
00066     "(in 'source_target'). The target being d-dimensional, each data point is repeated\n"
00067     "in this VMatrix as many times as it has non-missing targets. For each non-missing\n"
00068     "target, a one-hot vector (with a '1' corresponding to this target index) is added\n"
00069     "to the input part, and the target value (now 1-dimensional) is either the value for\n"
00070     "this target, or the maximum of all target values (depending on 'target_val').\n"
00071     "If the 'target_descriptor' option is set, it must be a VMat of length 'd', that\n"
00072     "gives an additional input descriptor to append to each example depending on the\n"
00073     "target. This VMat's first column must be the name of the target, which must\n"
00074     "correspond to a field name in 'source_target'.\n"
00075     "If one wants to set a weight, it must be set in 'source'.\n"
00076 );
00077 
00079 // declareOptions //
00081 void MultiTargetOneHotVMatrix::declareOptions(OptionList& ol)
00082 {
00083   // ### Declare all of this object's options here
00084   // ### For the "flags" of each option, you should typically specify  
00085   // ### one of OptionBase::buildoption, OptionBase::learntoption or 
00086   // ### OptionBase::tuningoption. Another possible flag to be combined with
00087   // ### is OptionBase::nosave
00088 
00089   declareOption(ol, "source_target", &MultiTargetOneHotVMatrix::source_target, OptionBase::buildoption,
00090       "The VMat containing the target information for each sample of 'source'.");
00091 
00092   declareOption(ol, "target_descriptor", &MultiTargetOneHotVMatrix::target_descriptor, OptionBase::buildoption,
00093       "The VMat containing the additional target descriptors (optional).");
00094 
00095   declareOption(ol, "missing_target", &MultiTargetOneHotVMatrix::missing_target, OptionBase::buildoption,
00096       "A target in the source VMatrix equal to this value will be treated as missing.");
00097 
00098   declareOption(ol, "reweight_targets", &MultiTargetOneHotVMatrix::reweight_targets, OptionBase::buildoption,
00099       "If set to 1, a weight column will be appended, with a weight of 1 for the most\n"
00100       "frequent target, and > 1 for other targets (=> equal weight to each target).");
00101 
00102   declareOption(ol, "target_val", &MultiTargetOneHotVMatrix::target_val, OptionBase::buildoption,
00103       "How the target value is computed:\n"
00104       " - 'max'             : the maximum of all targets\n"
00105       " - 'specific_target' : the value of the target considered");
00106 
00107   declareOption(ol, "verbosity", &MultiTargetOneHotVMatrix::verbosity, OptionBase::buildoption,
00108       "Controls the amount of output.");
00109 
00110   declareOption(ol, "hot_value", &MultiTargetOneHotVMatrix::hot_value, OptionBase::buildoption,
00111       "Hot value in one-hot representation. If it is the same as the cold_value,\n"
00112       "then the actual target value, as defined by the target_val option, is used.");
00113 
00114   declareOption(ol, "cold_value", &MultiTargetOneHotVMatrix::cold_value, OptionBase::buildoption,
00115       "Cold value in one-hot representation.");
00116 
00117   declareOption(ol, "source_and_target", &MultiTargetOneHotVMatrix::source_and_target, OptionBase::buildoption,
00118       "The VMat containing both the source (input) and target information.");
00119 
00120 
00121   // Now call the parent class' declareOptions
00122   inherited::declareOptions(ol);
00123 }
00124 
00126 // build //
00128 void MultiTargetOneHotVMatrix::build()
00129 {
00130   inherited::build();
00131   build_();
00132 }
00133 
00135 // build_ //
00137 void MultiTargetOneHotVMatrix::build_()
00138 {
00139   // ### This method should do the real building of the object,
00140   // ### according to set 'options', in *any* situation. 
00141   // ### Typical situations include:
00142   // ###  - Initial building of an object from a few user-specified options
00143   // ###  - Building of a "reloaded" object: i.e. from the complete set of all serialised options.
00144   // ###  - Updating or "re-building" of an object after a few "tuning" options have been modified.
00145   // ### You should assume that the parent class' build_() has already been called.
00146 
00147   if (source && source_target) {
00148     updateMtime(source);
00149     updateMtime(source_target);
00150     updateMtime(target_descriptor);
00151     updateMtime(source_and_target);
00152 
00153     if (source->targetsize() > 0)
00154       PLERROR("In MultiTargetOneHotVMatrix::build_ - The source VMatrix must have a targetsize <= 0");
00155     if (source->length() != source_target->length())
00156       PLERROR("In MultiTargetOneHotVMatrix::build_ - 'source' and 'source_target' must have same length");
00157     // We need to browse through the data.
00158     PP<ProgressBar> pb;
00159     if (verbosity >= 1)
00160       pb = new ProgressBar("Building new data view", source->length());
00161 //    int target_col = source->inputsize();
00162     Vec targets(source_target->width());
00163     int data_width = 3;
00164     if (target_descriptor)
00165       data_width++;
00166     if (reweight_targets)
00167       data_width++;
00168     data.resize(0, data_width);
00169     Vec data_row(data_width);
00170     int count = 0;
00171     TVec<int> count_targets;
00172     if (reweight_targets) {
00173       count_targets.resize(source_target->width());
00174       count_targets.clear();
00175     }
00176     for (int i = 0; i < source->length(); i++) {
00177       data_row[0] = i;
00178       source_target->getRow(i, targets);
00179       if (target_val == "max")
00180         data_row[2] = max(targets);
00181       for (int j = 0; j < targets.length(); j++) {
00182         data_row[1] = j;
00183         if (!is_missing(targets[j]) && targets[j] != missing_target) {
00184           count++;
00185           if (target_val == "specific_target")
00186             data_row[2] = targets[j];
00187           data.appendRow(data_row);
00188           if (reweight_targets)
00189             count_targets[j]++;
00190         }
00191       }
00192       if (pb)
00193         pb->update(i+1);
00194     }
00195     if (reweight_targets) {
00196       int max_target = argmax(count_targets);
00197       if (count_targets[max_target] == 0)
00198         PLERROR("In MultiTargetOneHotVMatrix::build_ - A target does not appear in the dataset, cannot reweight targets");
00199       Vec target_weights(count_targets.length());
00200       for (int i = 0; i < target_weights.length(); i++) {
00201         target_weights[i] = real(count_targets[max_target]) / real(count_targets[i]);
00202         if (verbosity >= 5)
00203           cout << "Weight for target " << i << ": " << target_weights[i]
00204                << " (count = " << count_targets[i] << ")" << endl;
00205       }
00206       for (int i = 0; i < data.length(); i++)
00207         data(i, data_width - 1) = target_weights[int(data(i, 1))];
00208     }
00209     source_inputsize = source->width();
00210     weightsize_ = 0;
00211     if (source->weightsize() > 0) {
00212       // There are weights.
00213       source_inputsize -= source->weightsize();
00214       weightsize_ = source->weightsize();
00215     }
00216 
00217     length_ = count;
00218     inputsize_ = source_inputsize + source_target->width();
00219     if (target_descriptor) {
00220       inputsize_ += target_descriptor->width() - 1;
00221       // Also build mapping from a target index to a row in 'target_descriptor'.
00222       int count_found = 0;
00223       TVec<int> map_target(source_target->width());
00224       for (int i = 0; i < target_descriptor->length(); i++) {
00225         string target_name = target_descriptor->getString(i, 0);
00226         int field_index = source_target->fieldIndex(target_name);
00227         if (field_index >= 0) {
00228           map_target[field_index] = i;
00229           count_found++;
00230         }
00231       }
00232       if (count_found != source_target->width())
00233         PLERROR("In MultiTargetOneHotVMatrix::build_ - Could not find all target descriptors in 'target_descriptor'");
00234       // Now fill 'data' accordingly.
00235       for (int i = 0; i < data.length(); i++)
00236         data(i, 3) = map_target[int(data(i, 1))];
00237     }
00238     targetsize_ = 1;
00239     width_ = inputsize_ + targetsize_ + weightsize_;
00240     // Add field names.
00241     TVec<VMField> source_infos = source->getFieldInfos();
00242     TVec<VMField> f_infos(source_infos.length());
00243     f_infos << source_infos;
00244     f_infos.resize(inputsize_);
00245     TVec<VMField> source_target_infos = source_target->getFieldInfos();
00246     f_infos.subVec(source_inputsize, source_target_infos.length()) << source_target_infos;
00247     if (target_descriptor) {
00248       TVec<VMField> target_des_infos = target_descriptor->getFieldInfos();
00249       f_infos.subVec(source_inputsize + source_target->width(), target_descriptor->width() - 1)
00250         << target_des_infos.subVec(1, target_des_infos.length() - 1);
00251     }
00252     f_infos.append(VMField(target_val, VMField::UnknownType));
00253     if (weightsize_ > 0) {
00254       f_infos.append(source_infos.subVec(
00255             source_infos.length() - source->weightsize(), source->weightsize()));
00256     }
00257     if (reweight_targets) {
00258       if (weightsize_ >= 0)
00259         weightsize_++;
00260       else
00261         weightsize_ = 1;
00262       f_infos.append(VMField("target_weight", VMField::UnknownType));
00263       width_++;
00264     }
00265     setFieldInfos(f_infos);
00266 //    setMetaInfoFromSource();
00267   }
00268   else if(source_and_target)
00269   {
00270     // We need to browse through the data.
00271     PP<ProgressBar> pb;
00272     if (verbosity >= 1)
00273       pb = new ProgressBar("Building new data view", source_and_target->length());
00274     //    int target_col = source->inputsize();
00275     Vec targets(source_and_target->targetsize());
00276     real weight;
00277     Vec input(source_and_target->inputsize());
00278     int data_width = 3;
00279     if (target_descriptor)
00280       data_width++;
00281     if (reweight_targets)
00282       data_width++;
00283     data.resize(0, data_width);
00284     Vec data_row(data_width);
00285     int count = 0;
00286     TVec<int> count_targets;
00287     if (reweight_targets) {
00288       count_targets.resize(source_and_target->targetsize());
00289       count_targets.clear();
00290     }
00291     for (int i = 0; i < source_and_target->length(); i++) {
00292       data_row[0] = i;
00293       source_and_target->getExample(i, input,targets,weight);
00294       if (target_val == "max")
00295         data_row[2] = max(targets);
00296       for (int j = 0; j < targets.length(); j++) {
00297         data_row[1] = j;
00298         if (!is_missing(targets[j]) && targets[j] != missing_target) {
00299           count++;
00300           if (target_val == "specific_target")
00301             data_row[2] = targets[j];
00302           data.appendRow(data_row);
00303           if (reweight_targets)
00304             count_targets[j]++;
00305         }
00306       }
00307       if (pb)
00308         pb->update(i+1);
00309     }
00310     if (reweight_targets) {
00311       int max_target = argmax(count_targets);
00312       if (count_targets[max_target] == 0)
00313         PLERROR("In MultiTargetOneHotVMatrix::build_ - A target does not appear in the dataset, cannot reweight targets");
00314       Vec target_weights(count_targets.length());
00315       for (int i = 0; i < target_weights.length(); i++) {
00316         target_weights[i] = real(count_targets[max_target]) / real(count_targets[i]);
00317         if (verbosity >= 5)
00318           cout << "Weight for target " << i << ": " << target_weights[i]
00319                << " (count = " << count_targets[i] << ")" << endl;
00320       }
00321       for (int i = 0; i < data.length(); i++)
00322         data(i, data_width - 1) = target_weights[int(data(i, 1))];
00323     }
00324     source_inputsize = source_and_target->inputsize();
00325     weightsize_ = 0;
00326     if (source_and_target->weightsize() > 0) {
00327       // There are weights.
00328       //  source_inputsize -= source_and_target->weightsize();
00329       weightsize_ = source_and_target->weightsize();
00330     }
00331 
00332     length_ = count;
00333     inputsize_ = source_inputsize + source_and_target->targetsize();
00334     if (target_descriptor) {
00335       inputsize_ += target_descriptor->width() - 1;
00336       // Also build mapping from a target index to a row in 'target_descriptor'.
00337       int count_found = 0;
00338       TVec<int> map_target(source_and_target->targetsize());
00339       for (int i = 0; i < target_descriptor->length(); i++) {
00340         string target_name = target_descriptor->getString(i, 0);
00341         int field_index = source_and_target->fieldIndex(target_name) - source_and_target->inputsize();
00342         if (field_index >= 0) {
00343           map_target[field_index] = i;
00344           count_found++;
00345         }
00346       }
00347       if (count_found != source_and_target->targetsize())
00348         PLERROR("In MultiTargetOneHotVMatrix::build_ - Could not find all target descriptors in 'target_descriptor'");
00349       // Now fill 'data' accordingly.
00350       for (int i = 0; i < data.length(); i++)
00351         data(i, 3) = map_target[int(data(i, 1))];
00352     }
00353     targetsize_ = 1;
00354     width_ = inputsize_ + targetsize_ + weightsize_;
00355     // Add field names.
00356     TVec<VMField> source_infos = source_and_target->getFieldInfos();
00357     TVec<VMField> f_infos(source_infos.length());
00358     f_infos << source_infos;
00359     f_infos.resize(inputsize_);
00360     //TVec<VMField> source_target_infos = source_target->getFieldInfos();
00361     //f_infos.subVec(source_inputsize, source_target_infos.length()) << source_target_infos;
00362     if (target_descriptor) {
00363       TVec<VMField> target_des_infos = target_descriptor->getFieldInfos();
00364       f_infos.subVec(source_inputsize + source_and_target->targetsize(), target_descriptor->width() - 1)
00365         << target_des_infos.subVec(1, target_des_infos.length() - 1);
00366     }
00367     f_infos.append(VMField(target_val, VMField::UnknownType));
00368     if (weightsize_ > 0) {
00369       f_infos.append(source_infos.subVec(
00370             source_infos.length() - source_and_target->weightsize(), source_and_target->weightsize()));
00371     }
00372     if (reweight_targets) {
00373       if (weightsize_ >= 0)
00374         weightsize_++;
00375       else
00376         weightsize_ = 1;
00377       f_infos.append(VMField("target_weight", VMField::UnknownType));
00378       width_++;
00379     }
00380     setFieldInfos(f_infos);
00381 //    setMetaInfoFromSource();
00382   }
00383     
00384   
00385 }
00386 
00388 // getNewRow //
00390 void MultiTargetOneHotVMatrix::getNewRow(int i, const Vec& v) const
00391 {
00392   PLASSERT( (source && source_target) || source_and_target);
00393   int is = source_inputsize;
00394   int ts;
00395   if(source_and_target)
00396   {
00397     ts = source_and_target->targetsize();
00398     // Get the input part.
00399     source_and_target->getSubRow(int(data(i,0)), 0, v.subVec(0, is));
00400   }
00401   else
00402   {
00403     ts = source_target->width();
00404     // Get the input part.
00405     source->getSubRow(int(data(i,0)), 0, v.subVec(0, is));
00406   }
00407   // Fill the one-hot vector.
00408   v.subVec(is, ts).fill(cold_value);
00409   if(hot_value == cold_value || (is_missing(cold_value) && is_missing(hot_value)))
00410     v[is + int(data(i, 1))] = data(i,2);
00411   else
00412     v[is + int(data(i, 1))] = hot_value;
00413   if (target_descriptor)
00414     // Fill the target descriptor.
00415     target_descriptor->getSubRow(int(data(i, 3)), 1,
00416                                  v.subVec(is + ts, target_descriptor->width() - 1));
00417   // Fill the target.
00418   v[inputsize_] = data(i, 2);
00419   // Fill the (potential) weight.
00420   if (weightsize_ > 0)
00421   {
00422     if(source_and_target)
00423       source_and_target->getSubRow(int(data(i, 0)), source_and_target->width()-source_and_target->weightsize(), v.subVec(inputsize_ + targetsize_, source_and_target->weightsize()));
00424     else
00425       source->getSubRow(int(data(i, 0)), is, v.subVec(inputsize_ + targetsize_, source->weightsize()));
00426   }
00427   if (reweight_targets)
00428     v[v.length() - 1] = data(i, 3);
00429 }
00430 
00432 // makeDeepCopyFromShallowCopy //
00434 void MultiTargetOneHotVMatrix::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00435 {
00436   inherited::makeDeepCopyFromShallowCopy(copies);
00437   deepCopyField(data, copies);
00438   deepCopyField(source_target, copies);
00439   deepCopyField(target_descriptor, copies);
00440   deepCopyField(source_and_target, copies);
00441 }
00442 
00443 } // end of namespace PLearn
00444 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines