PLearn 0.1
|
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 :