#include <cstdlib>
#include <iostream>
#include <string>
#include <math.h>
#include "utils.h"
#include <float.h>
#include "onboostnn.h"
//using namespace std;
/* Constructor function. This sets the training example file and number
of base models. It also sets to NULL other variables to be used later. */
onboostnn::onboostnn(datafile* examples_to_train, long new_num_base_models,
int new_num_epochs, int new_num_hidden, float newlearningrate,
float newmomentumterm)
{
if (new_num_epochs > 0)
{
num_epochs = new_num_epochs;
}
else
{
num_epochs = 100;
}
if (new_num_hidden > 0)
{
num_hidden = new_num_hidden;
}
if ((examples_to_train != NULL) && (new_num_base_models > 0))
{
setup(examples_to_train, new_num_base_models, new_num_epochs,
new_num_hidden, newlearningrate, newmomentumterm);
}
else
{
training_examples = NULL;
basemodels = NULL;
lambda_correct = NULL;
lambda_wrong = NULL;
epsilons = NULL;
betas = NULL;
init_num_base_models = num_base_models = 0;
classifications = NULL;
votes = NULL;
}
}
/* Destructor function. */
onboostnn::~onboostnn()
{
delete [] basemodels;
basemodels = NULL;
delete [] lambda_correct;
lambda_correct = NULL;
delete [] lambda_wrong;
lambda_wrong = NULL;
delete [] epsilons;
epsilons = NULL;
delete [] betas;
betas = NULL;
delete [] classifications;
classifications = NULL;
delete [] votes;
votes = NULL;
}
/* set_training_example_file:
Input: datafile containing the training examples.
Output: None.
Sets the training example file data structure to point to examples_to_train.
*/
void onboostnn::set_training_example_file(datafile* examples_to_train)
{
training_examples = examples_to_train;
if (votes != NULL)
{
delete [] votes;
}
votes = new double[training_examples->NumClasses()];
}
/* setup:
Inputs: datafile data structure, number of base models to be trained.
Output: none
This function sets the training example datafile data structure to point to
examples_to_train and sets the number of base models to be trained to
new_num_base_models.
*/
void onboostnn::setup(datafile* examples_to_train, long new_num_base_models,
int new_num_epochs, int new_num_hidden,
float newlearningrate, float newmomentumterm)
{
training_examples = examples_to_train;
if (new_num_base_models > 0)
{
init_num_base_models = num_base_models = new_num_base_models;
// For the code below, see if you can just set up 'basemodels'
// as a *nnbp and then do basemodels[i] = new nnbp(blah, blah)
// for each i. This way, you can call the explicit-value
// constructor for all the base models rather than all these
// setter functions.
basemodels = new nnbp[init_num_base_models];
for (int i = 0; i < init_num_base_models; i++)
{
if (new_num_hidden > 0)
{
basemodels[i].set_num_hidden(new_num_hidden);
}
basemodels[i].set_training_file(training_examples);
if (new_num_epochs > 0)
{
basemodels[i].set_num_epochs(new_num_epochs);
}
basemodels[i].set_learning_rate(newlearningrate);
basemodels[i].set_momentum_term(newmomentumterm);
}
lambda_correct = new double[init_num_base_models];
lambda_wrong = new double[init_num_base_models];
epsilons = new double[init_num_base_models];
betas = new double[init_num_base_models];
for (int t = 0; t < init_num_base_models; t++)
{
lambda_correct[t] = 0.0;
lambda_wrong[t] = 0.0;
epsilons[t] = 0.0;
betas[t] = 0.0;
}
classifications = new ClassNo[init_num_base_models];
votes = new double[training_examples->NumClasses()];
}
else
{
std::cout << "ILLEGAL NUMBER OF BASE MODELS: "
<< new_num_base_models << "\n";
exit(1);
}
}
/* set_num_epochs: This function sets the number of epochs in the base models.
*/
void onboostnn::set_num_epochs(int new_num_epochs)
{
for (int t = 0; t < num_base_models; t++)
{
basemodels[t].set_num_epochs(new_num_epochs);
}
}
/* reset:
This function resets the data structures to make it look as though no
training was done. This means resetting the base models contained within
this ensemble. */
void onboostnn::reset()
{
for (int t = 0; t < init_num_base_models; t++)
{
basemodels[t].reset();
lambda_correct[t] = 0.0;
lambda_wrong[t] = 0.0;
epsilons[t] = 0.0;
betas[t] = 0.0;
}
num_base_models = init_num_base_models; // Forget the fact that we
// might have chosen to use fewer than the full set of base
// models.
}
// Do batch boosting with examples in datafile
// training_examples.
void onboostnn::trainbatch()
{
trainbatch(0, training_examples->NumItems());
}
// Do batch training with examples 'first' up to 'last' (these
// are indices into the trainingfile).
void onboostnn::trainbatch(long first, long last)
{
long numexamples = last-first;
long* sample = new long[numexamples];
Description* items = new Description[numexamples];
Boolean* correctp = new Boolean[numexamples];
double* weights = new double[numexamples];
// Initialize weights.
for (int j = 0; j < numexamples; j++)
{
weights[j] = 1.0;
}
// For each base model,...
for (int i = 0; i < init_num_base_models; i++)
{
/* Create training sample according to the weights. The array
'sample' contains indices into the training examples data
structure. */
sample = create_sample(sample, weights, first, last);
for (int j = 0; j < numexamples; j++)
{
// Put the jth randomly chosen sample into the items
// array.
items[j] = (*training_examples)[sample[j]];
}
// Now that the sample with replacement is ready, learn
// the next base model.
basemodels[i].trainbatch(items, numexamples);
// Now we need to adjust the weights.
// First determine which examples are being misclassified by
// the current base model and calculate lambda_wrong[i] (the sum
// of the weights of the incorrectly classified examples) and
// lambda_correct[i] (the sum of the weights of the correctly
// classified examples).
for (int j = first; j < last; j++)
{
// If the example is being classified correctly, then...
if (basemodels[i].test((*training_examples)[j]) ==
training_examples->TrueClass(j))
{
// it is classified correctly,...
correctp[j-first] = 1;
}
else
{
// else it is misclassified and its weight needs to be
// added to lambda_wrong.
correctp[j-first] = 0;
lambda_wrong[i] += weights[j-first];
}
}
// lambda_correct + lambda_wrong = numexamples. This is equivalent
// to epsilon + (1 - epsilon) = 1 from AdaBoost.
lambda_correct[i] = numexamples - lambda_wrong[i];
// The following condition is equivalent to epsilon > 1/2 in
// AdaBoost, i.e., under this condition we stop learning more
// base models.
if (lambda_wrong[i] >= numexamples / 2.0)
{
num_base_models = i; // Note that init_num_base_models (the
// number of base models allocated) is still correct.
return;
}
if (lambda_wrong[i] == 0.0)
{
// If this zero-error base model is the only one we have,
// then we should use it. Otherwise, we should not use it
// because it will get all the weight when classifying new
// examples.
if (i == 0)
{
num_base_models = 1;
return;
}
else
{
num_base_models = i;
}
}
// Now scale up the weights of misclassified examples and scale
// down the weights of correctly-classified examples. The method
// being used is equivalent to AdaBoost's method except that it
// avoids floating-point problems and does not require a separate
// normalization step, so it is more efficient.
for (int j = 0; j < numexamples; j++)
{
if (correctp[j])
{
weights[j] *= numexamples / (2.0 * lambda_correct[i]);
}
else
{
weights[j] *= numexamples / (2.0 * lambda_wrong[i]);
}
}
// This is the new weight distribution to be tried.
}
// We don't need the following data structures specific to the
// learning algorithm.
delete [] sample;
sample = NULL;
delete [] items;
items = NULL;
delete [] correctp;
correctp = NULL;
delete [] weights;
weights = NULL;
}
// Do batch training with examples 'first' up to 'last' (these
// are indices into the trainingfile)--with training file in online mode.
void onboostnn::trainonlinebatch(long first, long last)
{
long numexamples = last-first;
long* sampleindices = new long[numexamples]; // Indices into the original sample. We
// use these to create the actual training sample.
Description* origsample = new Description[numexamples]; // Original training set
Description* items = new Description[numexamples]; // Sample for current base model.
Boolean* correctp = new Boolean[numexamples];
double* weights = new double[numexamples];
// First create the original sample. We have to create it one-at-a-time because
// the training set's datafile is in online mode.
for (int j = 0; j < numexamples; j++)
{
origsample[j] = training_examples->next_example();
}
// Initialize weights.
for (int j = 0; j < numexamples; j++)
{
weights[j] = 1.0;
}
// For each base model,...
for (int i = 0; i < init_num_base_models; i++)
{
/* Create training sample according to the weights. The array
'sampleindices' contains indices into the training set given in
origsample. */
sampleindices = create_sample(sampleindices, weights, first, last);
for (int j = 0; j < numexamples; j++)
{
// Put the jth randomly chosen sample into the items
// array.
items[j] = origsample[sampleindices[j]];
}
// Now that the sample with replacement is ready, learn
// the next base model.
basemodels[i].trainbatch(items, numexamples);
// Now we need to adjust the weights.
// First determine which examples are being misclassified by
// the current base model and calculate lambda_wrong[i] (the sum
// of the weights of the incorrectly classified examples) and
// lambda_correct[i] (the sum of the weights of the correctly
// classified examples).
for (int j = first; j < last; j++)
{
// If the example is being classified correctly, then...
short numattributes = training_examples->return_num_attributes();
DiscrValue exampleclass = origsample[j][numattributes]._discr_val;
if (basemodels[i].test(origsample[j]) == exampleclass)
{
// it is classified correctly,...
correctp[j-first] = 1;
}
else
{
// else it is misclassified and its weight needs to be
// added to lambda_wrong.
correctp[j-first] = 0;
lambda_wrong[i] += weights[j-first];
}
}
// lambda_correct + lambda_wrong = numexamples. This is equivalent
// to epsilon + (1 - epsilon) = 1 from AdaBoost.
lambda_correct[i] = numexamples - lambda_wrong[i];
// The following ifdef-endif combination was set up by Nikunj Oza
// 8-2-01 to test when the first base model's performance is < 0.5.
// #ifdef NO
// The following condition is equivalent to epsilon > 1/2 in
// AdaBoost, i.e., under this condition we stop learning more
// base models.
if (lambda_wrong[i] >= numexamples / 2.0)
{
if (i == 0)
{
num_base_models = 1;
return;
}
else
{
num_base_models = i; // Note that init_num_base_models (the
// number of base models allocated) is still correct.
return;
}
}
// #endif
if (lambda_wrong[i] == 0.0)
{
// If this zero-error base model is the only one we have,
// then we should use it. Otherwise, we should not use it
// because it will get all the weight when classifying new
// examples.
if (i == 0)
{
num_base_models = 1;
return;
}
else
{
num_base_models = i;
}
}
// Now scale up the weights of misclassified examples and scale
// down the weights of correctly-classified examples. The method
// being used is equivalent to AdaBoost's method except that it
// avoids floating-point problems and does not require a separate
// normalization step, so it is more efficient.
for (int j = 0; j < numexamples; j++)
{
if (correctp[j])
{
weights[j] *= numexamples / (2.0 * lambda_correct[i]);
}
else
{
weights[j] *= numexamples / (2.0 * lambda_wrong[i]);
}
}
// This is the new weight distribution to be tried.
}
// We don't need the following data structures specific to the
// learning algorithm.
delete [] origsample;
origsample = NULL;
delete [] sampleindices;
sampleindices = NULL;
delete [] items;
items = NULL;
delete [] correctp;
correctp = NULL;
delete [] weights;
weights = NULL;
}
// Do online boosting learning with the supplied example
void onboostnn::train(Description example)
{
double lambda = 1.0;
for (int t = 0; t < num_base_models; t++)
{
// cout << " Updating base model: " << t << endl;
// Number of times example is to be included.
long k = poisson(lambda);
for (int n = 0; n < k; n++)
{
// The next line is used for weighted training of the base
// models.
// basemodels[t].train((*training_examples)[i], lambda);
basemodels[t].train(example);
}
// Check if example is classified correctly.
Boolean correctp = (basemodels[t].test(example) ==
training_examples->TrueClass(example));
// Now update the lambda_correct and lambda_wrong. Also update
// the weight of the current example.
if (correctp == 1)
{
lambda_correct[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_correct[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_correct[t]);
// Since the example has been correctly classified, its
// weight should be decreased, i.e., its multiplier should
// be less than 1.0
// lambda *= factor;
// The following ifdef-endif combination was set up by Nikunj Oza
// 8-2-01 to test when the first base model's performance is < 0.5.
// #ifdef NO
if (factor < 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * (1.0 - exp(-1.0)));
}
// #endif
}
else
{
lambda_wrong[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_wrong[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_wrong[t]);
// Since the example has been misclassified, its weight
// should be increased, i.e., its multiplier should be
// greater than 1.0.
// lambda *= factor;
// The following ifdef-endif combination was set up by Nikunj Oza
// 8-2-01 to test when the first base model's performance is < 0.5.
// #ifdef NO
if (factor > 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * exp(-1.0));
}
// #endif
}
}
}
// Do online boosting on the training set in the datafile
//'training_examples.'
void onboostnn::train()
{
train(0, training_examples->NumItems());
}
// Do online boosting on the training set in the datafile
// 'training_examples.' (from 'first' up to 'last,' but not including
// 'last.')
void onboostnn::train(long first, long last)
{
for (int i = first; i < last; i++)
{
// cout << "Learning example: " << i << endl;
// Set initial weight.
double lambda = 1.0;
for (int t = 0; t < num_base_models; t++)
{
// cout << " Updating base model: " << t << endl;
// Number of times example is to be included.
long k = poisson(lambda);
for (int n = 0; n < k; n++)
{
// The next line is used for weighted training of the base
// models.
// basemodels[t].train((*training_examples)[i], lambda);
basemodels[t].train((*training_examples)[i]);
}
// Check if example is classified correctly.
Boolean correctp = (basemodels[t].test((*training_examples)[i]) ==
training_examples->TrueClass(i));
// Now update the lambda_correct and lambda_wrong. Also update
// the weight of the current example.
if (correctp == 1)
{
lambda_correct[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_correct[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_correct[t]);
// Since the example has been correctly classified, its
// weight should be decreased, i.e., its multiplier should
// be less than 1.0
if (factor < 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * (1.0 - exp(-1.0)));
}
}
else
{
lambda_wrong[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_wrong[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_wrong[t]);
// Since the example has been misclassified, its weight
// should be increased, i.e., its multiplier should be
// greater than 1.0.
if (factor > 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * exp(-1.0));
}
}
}
}
}
/* This version of train calculates the errors of each online-updated base model on
all the training examples seen earlier and returns these in one file per base model. This
is to see how "stable" the base models are.
*/
void onboostnn::traintest(long first, long last)
{
std::vector< std::vector<double> > bmc(num_base_models, std::vector<double>(last-first, 0.0));
std::vector< std::vector<double> > oberror(num_base_models, std::vector<double>(last-first, 0.0));
std::vector< std::vector<double> > onlineerror(num_base_models, std::vector<double>(last-first, 0.0));
for (int i = first; i < last; i++)
{
// cout << "Learning example: " << i << endl;
// Set initial weight.
double lambda = 1.0;
for (int t = 0; t < num_base_models; t++)
{
// cout << " Updating base model: " << t << endl;
// Number of times example is to be included.
long k = poisson(lambda);
for (int n = 0; n < k; n++)
{
// The next line is used for weighted training of the base
// models.
// basemodels[t].train((*training_examples)[i], lambda);
basemodels[t].train((*training_examples)[i]);
}
// Check if example is classified correctly.
Boolean correctp = (basemodels[t].test((*training_examples)[i]) ==
training_examples->TrueClass(i));
// Now update the lambda_correct and lambda_wrong. Also update
// the weight of the current example.
if (correctp == 1)
{
lambda_correct[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_correct[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_correct[t]);
// Since the example has been correctly classified, its
// weight should be decreased, i.e., its multiplier should
// be less than 1.0
if (factor < 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * (1.0 - exp(-1.0)));
}
}
else
{
lambda_wrong[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_wrong[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_wrong[t]);
// Since the example has been misclassified, its weight
// should be increased, i.e., its multiplier should be
// greater than 1.0.
if (factor > 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * exp(-1.0));
}
}
// We will calculate the "online-batch" error (the error on all past training
// examples of the latest online base model.
// We will also update the bmc (base model classification error) here.
// Now, go through the previously-seen examples and test the base model
// on each of them.
for (int j = first; j <= i; j++)
{
Boolean correctp = (basemodels[t].test((*training_examples)[j]) ==
training_examples->TrueClass(j));
if (correctp == 0)
{
oberror[t][i] += 1.0;
}
else
{
bmc[t][j] += 1.0;
}
}
// Now divide by the number of examples seen earlier.
oberror[t][i] /= (i+1)-first;
// Calculate the online error.
onlineerror[t][i] = lambda_wrong[t] / (lambda_correct[t] + lambda_wrong[t]);
}
}
// Normalize bmc by dividing by the number of base models that have been evaluated
// on example j.
for (int t = 0; t < num_base_models; t++)
{
for (int j = first; j < last; j++)
{
bmc[t][j] /= (last-j);
}
}
// Open the file where the classification results are to be placed.
char basemodelnum[100];
for (int t = 0; t < num_base_models; t++)
{
sprintf(basemodelnum, "%d\0", t+1);
std::string baseclassesfilename = "classifications";
baseclassesfilename = baseclassesfilename + basemodelnum;
// Stupid additional code required for this to work under GCC.
// GCC has an obviously incorrect implementation of the string library.
// I.e., the function string::data() is supposed to return a char* version of
// the string, but it instead nondeterministically returns some corrupted version
// of the string. For this reason, we have to create the char* versions manually.
char* bcfchars = new char[baseclassesfilename.size()+1];
for (int m = 0; m < baseclassesfilename.size(); m++)
{
bcfchars[m] = baseclassesfilename[m];
}
bcfchars[baseclassesfilename.size()] = '\0';
// End of code needed to spoonfeed GNU C++.
std::ofstream baseclasses(bcfchars, ios::app);
//baseclasses.seekp(0,ios::end);
delete [] bcfchars;
for (int j = first; j < last; j++)
{
baseclasses << bmc[t][j] << " " << oberror[t][j] << " " << onlineerror[t][j] << "\n";
}
baseclasses.close();
}
}
// Do online boosting on the training set in the datafile
// 'training_examples.' drawn one-at-a-time (from 'first' up to 'last,'
// but not including 'last.')
void onboostnn::train2(long first, long last)
{
for (int i = first; i < last; i++)
{
Description Item = training_examples->next_example();
// cout << "Learning example: " << i << endl;
// Set initial weight.
double lambda = 1.0;
for (int t = 0; t < num_base_models; t++)
{
// cout << " Updating base model: " << t << endl;
// Number of times example is to be included.
long k = poisson(lambda);
for (int n = 0; n < k; n++)
{
// The next line is used for weighted training of the base
// models.
// basemodels[t].train((*training_examples)[i], lambda);
basemodels[t].train(Item);
}
// Check if example is classified correctly.
Boolean correctp = (basemodels[t].test(Item) ==
training_examples->TrueClass(Item));
// Now update the lambda_correct and lambda_wrong. Also update
// the weight of the current example.
if (correctp == 1)
{
lambda_correct[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_correct[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_correct[t]);
// Since the example has been correctly classified, its
// weight should be decreased, i.e., its multiplier should
// be less than 1.0
if (factor < 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * (1.0 - exp(-1.0)));
}
}
else
{
lambda_wrong[t] += lambda;
// double factor = ((i + 1.0) / (2.0 * lambda_wrong[t]));
double factor = (lambda_correct[t] + lambda_wrong[t]) /
(2.0 * lambda_wrong[t]);
// Since the example has been misclassified, its weight
// should be increased, i.e., its multiplier should be
// greater than 1.0.
if (factor > 1.0)
{
lambda *= factor;
}
else
{
lambda *= 1.0 / (2.0 * exp(-1.0));
}
}
}
}
}
// Test the example 'instance' using the learned boosted ensemble.
ClassNo onboostnn::test(Description instance)
{
return test(instance, num_base_models);
}
// Test the example 'instance' using the first 'use_base_models' number
// of base models from the learned boosted ensemble.
ClassNo onboostnn::test(Description instance, long use_base_models)
{
// Classify the instance using each base model.
// Recall that 'classifications' contains each base model's
// classification of the instance.
for (int t = 0; t < use_base_models; t++)
{
classifications[t] = basemodels[t].test(instance);
}
// Initialize the weighted votes for each class.
// votes contains, for each class, the sum of log(1/beta) values
// by the base models that voted for that class.
for (int i = 0; i < training_examples->NumClasses(); i++)
{
votes[i] = 0.0;
}
// Calculate the epsilons and then beta values needed to weight the
// votes of each base model.
for (int t = 0; t < use_base_models; t++)
{
epsilons[t] = lambda_wrong[t] / (lambda_wrong[t] + lambda_correct[t]);
if (epsilons[t] == 1.0)
{
betas[t] = FLT_MAX; // If error is maximized, then maximize beta,
// thereby giving this base model very low weight.
}
else
{
betas[t] = epsilons[t] / (1.0 - epsilons[t]);
}
}
// The trigger is set up so that if the mth base model has an error of
// more than 0.5, we don't use it or any subsequent base models to
// classify new examples.
int trigger = 0;
// Add up the log(1/beta) values for each class.
for (int t = 0; t < use_base_models; t++)
{
// if (!((betas[t] >= 1.0) || (betas[t] == 0.0)))
// {
// votes[classifications[t]] += log(1.0 / betas[t]);
// }
// The following ifdef-endif combination was set up by Nikunj Oza
// 8-2-01 to test when the first base model's performance is < 0.5.
// #ifdef NO
if ( !((betas[t] >= 1.0) || (betas[t] == 0.0) || (trigger == 1)))
{
votes[classifications[t]] += log(1.0 / betas[t]);
}
if (betas[t] >= 1.0)
{
trigger = 1;
}
// #endif
}
int answer = argmax(votes, training_examples->NumClasses());
return answer;
}
/* create_sample:
Inputs: Array of indices (to be overwritten) into the training set, the
weights of each example (THE WEIGHTS ARE POISSON PARAMETERS, i.e., a
'sampleweight' of 1.0 corresponds to an AdaBoost weight of 1.0/n where 'n'
is the number of training examples), and the indices of the first and last
examples to be considered for sampling.
Output: Array of indices into the training set. These indices correspond to
example sampled with replacement according to the supplied weights.
*/
long* onboostnn::create_sample(long* sample, double* sampleweights,
long first, long last)
{
// First we find the sum of the weights---we want to choose a random value
// from 0 to this sum and choose a training example accordingly.
double weightssum = sampleweights[0];
for (int j = 1; j < last-first; j++)
{
weightssum += sampleweights[j];
}
// For each training example, choose a random example out of the
// entire set of examples.
for (int i = 0; i < last-first; i++)
{
double randdouble = double(rand()) / RAND_MAX * weightssum;
int j = first; // Index to example.
double sumsofar = sampleweights[0];
while ((randdouble > sumsofar) && (j < last))
{
j++;
sumsofar += sampleweights[j-first];
}
// In case, due to rounding error, the weights do not quite
// add up to 1 and the random number chosen happens to be
// greater than the weight sum...
if (j >= last)
{
j = last - 1;
}
// Example j is the one to be included.
sample[i] = j;
}
return sample;
}
// The following function returns the beta value for a given base model.
double onboostnn::return_beta(int modelnum)
{
if (modelnum <= num_base_models)
{
return betas[modelnum-1];
}
else
{
std::cout << "Error in onboostnn::return_beta: The model number entered ("
<< modelnum << ") is out of range. The range is 1 to " << num_base_models
<< "\n";
exit(1);
}
}
long onboostnn::return_num_base_models()
{
return num_base_models;
}
nirav bhatt 0 Newbie Poster
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.