contrib/mul/clsfy/clsfy_rbf_parzen.cxx
Go to the documentation of this file.
00001 // This is mul/clsfy/clsfy_rbf_parzen.cxx
00002 #include "clsfy_rbf_parzen.h"
00003 //:
00004 // \file
00005 // \author
00006 //   Copyright: (C) 2000 British Telecommunications plc
00007 
00008 #include <vcl_string.h>
00009 #include <vcl_algorithm.h>
00010 #include <vcl_cmath.h>
00011 #include <vcl_cassert.h>
00012 #include <vsl/vsl_binary_io.h>
00013 #include <vsl/vsl_vector_io.h>
00014 #include <vnl/io/vnl_io_vector.h>
00015 
00016 //=======================================================================
00017 //: Return the classification of the given probe vector.
00018 unsigned clsfy_rbf_parzen::classify(const vnl_vector<double> &input) const
00019 {
00020   const unsigned nTrainingVecs = trainInputs_.size();
00021   double sumWeightings=0.0, sumPredictions=0.0, weight;
00022 
00023   if (power_ == 2) // optimise common case
00024     for (unsigned i = 0; i < nTrainingVecs; i++)
00025     {
00026       weight = vcl_exp(gamma_ * vnl_vector_ssd(input, trainInputs_[i]));
00027 
00028       sumWeightings += weight;
00029       sumPredictions += weight * trainOutputs_[i];
00030     }
00031   else
00032   {
00033     double gamma = - 0.5 * vcl_pow(-2*gamma_, 0.5*power_);
00034     double p = power_ / 2.0;
00035     for (unsigned i = 0; i < nTrainingVecs; i++)
00036     {
00037       weight = vcl_exp(gamma * vcl_pow(vnl_vector_ssd(input, trainInputs_[i]), p) );
00038 
00039       sumWeightings += weight;
00040       sumPredictions += weight * trainOutputs_[i];
00041     }
00042   }
00043   return sumPredictions * 2 > sumWeightings ? 1 : 0;
00044 }
00045 
00046 //=======================================================================
00047 //: Set the training data.
00048 void clsfy_rbf_parzen::set(const vcl_vector<vnl_vector<double> > &inputs,
00049                            const vcl_vector<unsigned> &outputs)
00050 {
00051   assert(*vcl_max_element(outputs.begin(), outputs.end()) <= 1); // The class labels must be 0 or 1.
00052   assert(inputs.size() == outputs.size());
00053   trainInputs_ = inputs;
00054   trainOutputs_ = outputs;
00055 }
00056 
00057 //=======================================================================
00058 //: Return a probability like value that the input being in each class.
00059 // output(i) i<<nClasses, contains the probability that the input is in class i
00060 void clsfy_rbf_parzen::class_probabilities(vcl_vector<double>& outputs,
00061                                            vnl_vector<double>const& input) const
00062 {
00063   const unsigned nTrainingVecs = trainInputs_.size();
00064   double sumWeightings=0.0, sumPredictions=0.0, weight;
00065 
00066   if (power_ == 2) // optimise common case
00067     for (unsigned i = 0; i < nTrainingVecs; i++)
00068     {
00069       weight = vcl_exp(gamma_ * vnl_vector_ssd(input, trainInputs_[i]));
00070 
00071       sumWeightings += weight;
00072       sumPredictions += weight * trainOutputs_[i];
00073     }
00074   else
00075   {
00076     double gamma = - 0.5 * vcl_pow(-2*gamma_, 0.5*power_);
00077     double p = power_ / 2.0;
00078     for (unsigned i = 0; i < nTrainingVecs; i++)
00079     {
00080       weight = vcl_exp(gamma * vcl_pow(vnl_vector_ssd(input, trainInputs_[i]), p) );
00081 
00082       sumWeightings += weight;
00083       sumPredictions += weight * trainOutputs_[i];
00084     }
00085   }
00086   outputs.resize(1);
00087   outputs[0] = sumPredictions / sumWeightings;
00088 }
00089 
00090 //=======================================================================
00091 //: Return the number of training vectors weighted by the windowing function.
00092 double clsfy_rbf_parzen::weightings(const vnl_vector<double> &input) const
00093 {
00094   const unsigned nTrainingVecs = trainInputs_.size();
00095   double sumWeightings=0.0;
00096 
00097   if (power_ == 2) // optimise common case
00098     for (unsigned i = 0; i < nTrainingVecs; i++)
00099       sumWeightings += vcl_exp(gamma_ * vnl_vector_ssd(input, trainInputs_[i]));
00100   else
00101   {
00102     double gamma = - 0.5 * vcl_pow(-2*gamma_, 0.5*power_);
00103     double p = power_ / 2.0;
00104     for (unsigned i = 0; i < nTrainingVecs; i++)
00105       sumWeightings += vcl_exp(gamma * vcl_pow(vnl_vector_ssd(input, trainInputs_[i]), p) );
00106   }
00107 
00108   return sumWeightings;
00109 }
00110 
00111 //=======================================================================
00112 //: The dimensionality of input vectors.
00113 unsigned clsfy_rbf_parzen::n_dims() const
00114 {
00115   if (trainInputs_.size() == 0)
00116     return 0;
00117   else
00118     return trainInputs_[0].size();
00119 }
00120 
00121 //=======================================================================
00122 //: This value has properties of a Log likelihood of being in class (binary classifiers only)
00123 // class probability = exp(logL) / (1+exp(logL))
00124 double clsfy_rbf_parzen::log_l(const vnl_vector<double> &input) const
00125 {
00126   vcl_vector<double> outputs(1);
00127   class_probabilities(outputs, input);
00128   double prob = outputs[0];
00129   return vcl_log(prob/(1.0-prob));
00130 }
00131 
00132 //=======================================================================
00133 //: Set the 1st standard deviation width of the RBF window.
00134 // The default value is 1. Really this could be better named as the RBF radius.
00135 void clsfy_rbf_parzen::set_rbf_width(double sigma)
00136 {
00137   assert(sigma > 0.0);
00138   width_ = sigma;
00139   gamma_ = -0.5/(sigma*sigma);
00140 }
00141 
00142 
00143 //=======================================================================
00144 //: The value p in the window function $exp(-1/(2*sigma^p) * |x-y|^p)$.
00145 // The value p affects the kurtosis, or peakyness of the window.
00146 // Towards 0 gives a more peaked central spike, and longer tail.
00147 // Toward +inf gives a broader peak, and shorter tail.
00148 // The default value is 2, giving a Gaussian distribution.
00149 void clsfy_rbf_parzen::set_power(double p)
00150 {
00151   assert(p > 0.0);
00152   power_ = p;
00153 }
00154 
00155 
00156 //=======================================================================
00157 
00158 vcl_string clsfy_rbf_parzen::is_a() const
00159 {
00160   return vcl_string("clsfy_rbf_parzen");
00161 }
00162 
00163 //=======================================================================
00164 
00165 bool clsfy_rbf_parzen::is_class(vcl_string const& s) const
00166 {
00167   return s == clsfy_rbf_parzen::is_a() || clsfy_classifier_base::is_class(s);
00168 }
00169 
00170 //=======================================================================
00171 
00172 short clsfy_rbf_parzen::version_no() const
00173 {
00174   return 2;
00175 }
00176 
00177 //=======================================================================
00178 
00179 clsfy_classifier_base* clsfy_rbf_parzen::clone() const
00180 {
00181   return new clsfy_rbf_parzen(*this);
00182 }
00183 
00184 //=======================================================================
00185 
00186 void clsfy_rbf_parzen::print_summary(vcl_ostream& os) const
00187 {
00188   os << trainInputs_.size() << " training samples, "
00189      << "Gaussian Width=" << rbf_width() << ", power=" << power_ << '\n';
00190 }
00191 
00192 //=======================================================================
00193 
00194 void clsfy_rbf_parzen::b_write(vsl_b_ostream& bfs) const
00195 {
00196   vsl_b_write(bfs,version_no());
00197   vsl_b_write(bfs,width_);
00198   vsl_b_write(bfs,power_);
00199   vsl_b_write(bfs,trainOutputs_);
00200   vsl_b_write(bfs,trainInputs_);
00201 }
00202 
00203 //=======================================================================
00204 
00205 void clsfy_rbf_parzen::b_read(vsl_b_istream& bfs)
00206 {
00207   if (!bfs) return;
00208 
00209   short version;
00210   vsl_b_read(bfs,version);
00211   switch (version)
00212   {
00213   case (1):
00214     vsl_b_read(bfs,gamma_);
00215     width_ = vcl_sqrt(-0.5/gamma_);
00216     vsl_b_read(bfs,power_);
00217     vsl_b_read(bfs,trainOutputs_);
00218     vsl_b_read(bfs,trainInputs_);
00219     break;
00220   case(2):
00221     vsl_b_read(bfs,width_);
00222     gamma_ = -0.5/(width_*width_);
00223     vsl_b_read(bfs,power_);
00224     vsl_b_read(bfs,trainOutputs_);
00225     vsl_b_read(bfs,trainInputs_);
00226     break;
00227   default:
00228     vcl_cerr << "I/O ERROR: clsfy_rbf_parzen::b_read(vsl_b_istream&)\n"
00229              << "           Unknown version number "<< version << "\n";
00230     bfs.is().clear(vcl_ios::badbit); // Set an unrecoverable IO error on stream
00231   }
00232 }