PLearn 0.1
ReplicateSamplesVMatrix.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // ReplicateSamplesVMatrix.cc
00004 //
00005 // Copyright (C) 2008 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 "ReplicateSamplesVMatrix.h"
00041 #include <plearn/var/SumOverBagsVariable.h>
00042 
00043 namespace PLearn {
00044 using namespace std;
00045 
00046 PLEARN_IMPLEMENT_OBJECT(
00047     ReplicateSamplesVMatrix,
00048     "VMat that replicates samples in order to reweight classes evenly.",
00049     "If the class with most samples in the source VMat has n samples, then\n"
00050     "the first 'n-n_j' samples of class j (having n_j samples) will be\n"
00051     "replicated so that each class also has n samples. If required, samples\n"
00052     "will be replicated more than once.\n"
00053     "The class index is assumed to be the first element of the target. It\n"
00054     "can be either an integer (negative class indices are also allowed) or\n"
00055     "a missing value (all examples with missing values are considered as\n"
00056     "belonging to the same class).\n"
00057     "When the 'operate_on_bags' option is set to true, the bag information\n"
00058     "must be stored in the last element of the target.\n"
00059     "All samples are also shuffled so as to mix classes together."
00060 );
00061 
00063 // ReplicateSamplesVMatrix //
00065 ReplicateSamplesVMatrix::ReplicateSamplesVMatrix():
00066     operate_on_bags(false),
00067     bag_index(-1),
00068     seed(1827),
00069     replicate_missing_targets(true),
00070     replicate_negative_targets(true),
00071     random_gen(new PRandom())
00072 {}
00073 
00075 // declareOptions //
00077 void ReplicateSamplesVMatrix::declareOptions(OptionList& ol)
00078 {
00079     // ### Declare all of this object's options here.
00080     // ### For the "flags" of each option, you should typically specify
00081     // ### one of OptionBase::buildoption, OptionBase::learntoption or
00082     // ### OptionBase::tuningoption. If you don't provide one of these three,
00083     // ### this option will be ignored when loading values from a script.
00084     // ### You can also combine flags, for example with OptionBase::nosave:
00085     // ### (OptionBase::buildoption | OptionBase::nosave)
00086 
00087     declareOption(ol, "operate_on_bags",
00088                   &ReplicateSamplesVMatrix::operate_on_bags,
00089                   OptionBase::buildoption,
00090         "If set to 1, then bags in the source VMat will be taken into\n"
00091         "account so as to preserve their integrity. The classes will also be\n"
00092         "reweighted so that they have the same number of bags.");
00093 
00094     declareOption(ol, "bag_index",
00095                   &ReplicateSamplesVMatrix::bag_index,
00096                   OptionBase::buildoption,
00097         "Index of the target corresponding to the bag information (useful\n"
00098         "only when operate_on_bags is True). -1 means the last element.");
00099 
00100     declareOption(ol, "seed", &ReplicateSamplesVMatrix::seed,
00101                   OptionBase::buildoption,
00102         "Seed for the random number generator (to shuffle data).");
00103 
00104     declareOption(ol, "replicate_missing_targets", &ReplicateSamplesVMatrix::replicate_missing_targets,
00105                   OptionBase::buildoption,
00106         "Indication that samples with missing (NaN) targets should be replicated.");
00107 
00108     declareOption(ol, "replicate_negative_targets", &ReplicateSamplesVMatrix::replicate_negative_targets,
00109                   OptionBase::buildoption,
00110         "Indication that samples with negative targets should be replicated.");
00111 
00112     // Now call the parent class' declareOptions
00113     inherited::declareOptions(ol);
00114 }
00115 
00117 // build //
00119 void ReplicateSamplesVMatrix::build()
00120 {
00121     // ### Nothing to add here, simply calls build_
00122     inherited::build();
00123     build_();
00124 }
00125 
00127 // build_ //
00129 void ReplicateSamplesVMatrix::build_()
00130 {
00131     if (!source)
00132         return;
00133 
00134     PLCHECK_MSG(operate_on_bags || source->targetsize() >= 1,
00135             "In ReplicateSamplesVMatrix::build_ - The source VMat must have a "
00136             "targetsize at least 1 when not operating on bags, but its "
00137             "targetsize is " + tostring(source->targetsize()));
00138 
00139     PLCHECK_MSG(!operate_on_bags || source->targetsize() >= 2,
00140             "In ReplicateSamplesVMatrix::build_ - The source VMat must have a "
00141             "targetsize at least 2 when operating on bags, but its targetsize "
00142             "is " + tostring(source->targetsize()));
00143 
00144     updateMtime(indices_vmat);
00145     updateMtime(source);
00146 
00147     PLASSERT(bag_index < 0 || bag_index < source->targetsize());
00148 
00149     // Build the vector of indices.
00150     indices.resize(0);
00151     Vec input, target;
00152     real weight;
00153     TVec< TVec<int>  > class_indices;  // Indices of samples in each class.
00154     TVec<int> nan_indices; // Indices of missing class
00155     TVec< TVec<int> > negativeclass_indices;
00156     map<int, int> bag_sizes; // Map a source index to the size of its bag.
00157     int bag_start_idx = -1;
00158     int bag_idx = bag_index >= 0 ? bag_index : source->targetsize() - 1;
00159     for (int i = 0; i < source->length(); i++) {
00160         source->getExample(i, input, target, weight);
00161         real c_real = target[0];
00162         int c = int(round(c_real));
00163         if (!is_missing(c_real)) {
00164             if (c >= class_indices.length()) {
00165                 int n_to_add = c - class_indices.length() + 1;
00166                 for (int j = 0; j < n_to_add; j++)
00167                     class_indices.append(TVec<int>());
00168             }
00169             else if ( -c >= negativeclass_indices.length() ) {
00170                 int n_to_add = -c - negativeclass_indices.length() + 1;
00171                 for (int j = 0; j < n_to_add; j++)
00172                     negativeclass_indices.append(TVec<int>());
00173             }
00174         }
00175         
00176         if (!operate_on_bags || int(round(target[bag_idx])) &
00177                                 SumOverBagsVariable::TARGET_COLUMN_FIRST) {
00178             if( is_missing(c_real) )
00179                 nan_indices.append(i);
00180             else if( c>= 0 )
00181                 class_indices[c].append(i);
00182             else if( c< 0 )
00183                 negativeclass_indices[-c].append(i);
00184             else
00185                 PLERROR("In ReplicateSamplesVMatrix::build_ - Invalid class");
00186             indices.append(i);
00187             bag_sizes[i] = 0;
00188             bag_start_idx = i;
00189         }
00190         if (operate_on_bags)
00191             bag_sizes[bag_start_idx]++;
00192     }
00193 
00194     if( replicate_missing_targets && nan_indices.length() > 0  )
00195         class_indices.append( nan_indices );
00196     if( replicate_negative_targets && negativeclass_indices.length() > 0 )
00197         for(int c = 0; c < negativeclass_indices.length(); c ++ )
00198             if( negativeclass_indices[c].length() > 0 )
00199                 class_indices.append( negativeclass_indices[c] );
00200     int max_n = -1;
00201     for (int c = 0; c < class_indices.length(); c++) {
00202         if (class_indices[c].length() > max_n)
00203             max_n = class_indices[c].length();
00204         if (class_indices[c].isEmpty())
00205             PLERROR("In ReplicateSamplesVMatrix::build_ - Cannot replicate "
00206                     "samples for class %d since there are zero samples from "
00207                     "this class", c);
00208     }
00209     for (int c = 0; c < class_indices.length(); c++) {
00210         int n_replicated = max_n - class_indices[c].length();
00211         for (int i = 0; i < n_replicated; i++) {
00212             indices.append(class_indices[c][i % class_indices[c].length()]);
00213         }
00214     }
00215 
00216     // Shuffle data.
00217     random_gen->manual_seed(seed);
00218     random_gen->shuffleElements(indices);
00219 
00220     if (operate_on_bags) {
00221         // We now need to convert the list of start indices to the list of all
00222         // indices within each bag.
00223         TVec<int> start_idx = indices.copy();
00224         indices.resize(0);
00225         for (int i = 0; i < start_idx.length(); i++) {
00226             int start_i = start_idx[i];
00227             for (int j = 0; j < bag_sizes[start_i]; j++)
00228                 indices.append(start_i + j);
00229         }
00230     }
00231     
00232     // Re-build since indices have changed.
00233     inherited::build();
00234 }
00235 
00237 // makeDeepCopyFromShallowCopy //
00239 void ReplicateSamplesVMatrix::makeDeepCopyFromShallowCopy(CopiesMap& copies)
00240 {
00241     inherited::makeDeepCopyFromShallowCopy(copies);
00242     deepCopyField(random_gen, copies);
00243 }
00244 
00245 } // end of namespace PLearn
00246 
00247 
00248 /*
00249   Local Variables:
00250   mode:c++
00251   c-basic-offset:4
00252   c-file-style:"stroustrup"
00253   c-file-offsets:((innamespace . 0)(inline-open . 0))
00254   indent-tabs-mode:nil
00255   fill-column:79
00256   End:
00257 */
00258 // 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