From 4b75c0dc61fd5f2ea6b8a8323d0d1dd9b23f353d Mon Sep 17 00:00:00 2001 From: Parikshit Ram Date: Sat, 19 Jan 2008 22:33:20 +0000 Subject: [PATCH] The files have been commented and a README file has been included for assistance --- fastlib/u/pram/nbc/README.txt | 35 ++++++++++++ fastlib/u/pram/nbc/nbc_main.cc | 24 ++++++++ fastlib/u/pram/nbc/simple_nbc.h | 98 ++++++++++++++++++++++++++++----- 3 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 fastlib/u/pram/nbc/README.txt diff --git a/fastlib/u/pram/nbc/README.txt b/fastlib/u/pram/nbc/README.txt new file mode 100644 index 0000000000..9c5ca90f5b --- /dev/null +++ b/fastlib/u/pram/nbc/README.txt @@ -0,0 +1,35 @@ +The files are the following: +1. nbc_main.cc - this is the main which creates an object of the class SimpleNaiveBayesClassifier, trains it, tests it and outputs the results. The executable formed is called "simple_nbc_main". + - the parameters taken in by the main are the following: + --training_data : the file that contains the training data, the last column being the class of the data point + --number_of_classes : the number of classes the data provided has been classified into + --testing_data : this file contains the testing data, this still contains its actual labels on the last column, but it is not used. + --output_filename : the file into which you want the output to be written into, defaults to "output.csv" (but it does not output in .csv format, it outputs in the "pretty-print" format) + +2. simple_nbc.h - this is the file that contains the definition of the class SimpleNaiveBayesClassifier. The rest of the details are present in the file itself. + +3. phi.h - this contains the function that calculates the value of the univariate Gaussian pdf + +4. math_functions.h - this file contains functions like returning the highest element and its index in an array/vector. + +5. test_simple_nbc_main.cc - this file contains the class which tests the class SimpleNaiveBayesClassifier. The executable formed is "test_simple_nbc_main". + - the parameters taken in by this are the following: + --training_set : the training set, defaults to the file "trainSet.arff" + --training_results : the training results, defaults to the file "trainRes.arff" + --testing_set : the testing set, defaults to the file "testSet.arff" + --testing_results : the testing results, defaults to the file "testRes.arff" + --num_classes : the number of classes in the data, defaults to "2", which in the number of classes of the data present in the default files + +6. the .arff files, whose use has been described above. + +7. build.py - you might want to take a look at them for the purpose of seeing what all files are used where. + +-> An example run would the following: +fl-build simple_nbc_main +./simple_nbc_main --training_data=trainSet.arff --number_of_classes=2 --testing_data=testSet.arff --output_filename=output_example.csv + +-> An example run of the testing class would be the following: +fl-build test_simple_nbc_main +./test_simple_nbc_main + +Note: you don't need to give any parameters for testing because it will use the defaults. In case you want to give your own training and test sets, you know how to do it. diff --git a/fastlib/u/pram/nbc/nbc_main.cc b/fastlib/u/pram/nbc/nbc_main.cc index f2ad0cd375..7cbfd10b2f 100644 --- a/fastlib/u/pram/nbc/nbc_main.cc +++ b/fastlib/u/pram/nbc/nbc_main.cc @@ -3,6 +3,26 @@ * * This program test drives the Simple Naive Bayes Classifier * + * This classifier does parametric naive bayes classification + * assuming that the features are sampled from a Gaussian + * distribution. + * + * PARAMETERS TO BE INPUT: + * + * --training_data + * This is the file that contains the training data + * + * --number_of_classes + * This is the number of classes present in the training data + * + * --testing_data + * This file contains the data points which the trained + * classifier would classify + * + * --output_filename + * This file will contain the classes to which the corresponding + * data points in the testing data + * */ #include "simple_nbc.h" @@ -23,6 +43,7 @@ int main(int argc, char* argv[]) { ////// SIMPLE NAIVE BAYES CLASSIFICATION ASSUMING THE DATA TO BE UNIFORMLY DISTRIBUTED ////// + ////// Declaration of an object of the class SimpleNaiveBayesClassifier SimpleNaiveBayesClassifier nbc; struct datanode* nbc_module = fx_submodule(NULL, "simple_nbc", "simple_nbc_module"); @@ -31,15 +52,18 @@ int main(int argc, char* argv[]) { ////// Timing the training of the Naive Bayes Classifier ////// fx_timer_start(nbc_module, "training_classifier"); + ////// Calling the function that trains the classifier nbc.InitTrain(training_data, number_of_classes); fx_timer_stop(nbc_module, "training_classifier"); ////// Timing the testing of the Naive Bayes Classifier ////// + ////// The variable that contains the result of the classification Vector results; fx_timer_start(nbc_module, "testing_classifier"); + ////// Calling the function that classifies the test data nbc.Classify(testing_data, &results); fx_timer_stop(nbc_module, "testing_classifier"); diff --git a/fastlib/u/pram/nbc/simple_nbc.h b/fastlib/u/pram/nbc/simple_nbc.h index ddee0234a7..bca572f4cc 100644 --- a/fastlib/u/pram/nbc/simple_nbc.h +++ b/fastlib/u/pram/nbc/simple_nbc.h @@ -1,23 +1,67 @@ /** * @file simple_nbc.h * - * A Simple Naive Bayes Classifier assuming that the data - * is generated from a gaussian distribution + * A Naive Bayes Classifier which parametrically + * estimates the distribution of the features. + * It is assumed that the features have been + * sampled from a Gaussian PDF * */ +#ifndef NBC_H +#define NBC_H #include "fastlib/fastlib.h" #include "phi.h" #include "math_functions.h" +/** + * A classification class. The class labels are assumed + * to be positive integers - 0,1,2,.... + * + * This class trains on the data by calculating the + * sample mean and variance of the features with + * respect to each of the labels, and also the class + * probabilities. + * + * Mathematically, it computes P(X_i = x_i | Y = y_j) + * for each feature X_i for each of the labels y_j. + * Alongwith this, it also computes the classs probabilities + * P( Y = y_j) + * + * For classifying a data point (x_1, x_2, ..., x_n), + * it computes the following: + * arg max_y(P(Y = y)*P(X_1 = x_1 | Y = y) * ... * P(X_n = x_n | Y = y)) + * + * Example use: + * + * @code + * SimpleNaiveBayesClassifier nbc; + * Vector results; + * + * nbc.InitTrain(training_data, number_of_classes); + * nbc.Classify(testing_data, &results); + * @endcode + */ class SimpleNaiveBayesClassifier { + + // The class for testing this class is made a friend class friend class TestClassSimpleNBC; + private: + + // The variables containing the sample mean and variance + // for each of the features with respect to each class Matrix means_, variances_; + + // The variable containing the class probabilities ArrayList class_probabilities_; + + // The variable keeping the information about the + // number of classes present index_t number_of_classes_; public: + SimpleNaiveBayesClassifier(){ means_.Init(0, 0); variances_.Init(0, 0); @@ -32,13 +76,16 @@ class SimpleNaiveBayesClassifier { } - + // The function that initializes the classifier as per the input + // and then trains it by calculating the sample mean and variances void InitTrain(const Matrix& data, int number_of_classes) { + ArrayList feature_sum, feature_sum_squared; - /** the last row are the classes */ - index_t number_examples = data.n_cols(); // number of examples in the dataset - index_t number_features = data.n_rows() - 1; // number of features in each example - /** the classes are of the form 0,1,2...,n_classes - 1 */ + index_t number_examples = data.n_cols(); + index_t number_features = data.n_rows() - 1; + + // updating the variables, private and local, according to + // the number of features and classes present in the data number_of_classes_ = number_of_classes; class_probabilities_.Resize(number_of_classes_); means_.Destruct(); @@ -51,8 +98,12 @@ class SimpleNaiveBayesClassifier { feature_sum[k] = 0; feature_sum_squared[k] = 0; } - printf("%"LI"d examples with %"LI"d features each\n",number_examples, number_features); - // calculating the probablity of occurrence of the individual classes + printf("%"LI"d examples with %"LI"d features each\n", + number_examples, number_features); + + // calculating the class probabilities as well as the + // sample mean and variance for each of the features + // with respect to each of the labels for(index_t i = 0; i < number_of_classes_; i++ ) { index_t number_of_occurrences = 0; for (index_t j = 0; j < number_examples; j++) { @@ -66,18 +117,28 @@ class SimpleNaiveBayesClassifier { } } } - class_probabilities_[i] = (double)number_of_occurrences / (double)number_examples ; + class_probabilities_[i] = (double)number_of_occurrences + / (double)number_examples ; for(index_t k = 0; k < number_features; k++) { means_.set(k, i, (feature_sum[k] / number_of_occurrences)); - variances_.set(k, i, (feature_sum_squared[k] - (feature_sum[k] * feature_sum[k] / number_of_occurrences)) / (number_of_occurrences - 1)); + variances_.set(k, i, (feature_sum_squared[k] + - (feature_sum[k] * feature_sum[k] + / number_of_occurrences) + )/(number_of_occurrences - 1)); feature_sum[k] = 0; feature_sum_squared[k] = 0; } } } + // Given a bunch of data points, this function evaluates the class + // of each of those data points, and puts it in the vector 'results' void Classify(const Matrix& test_data, Vector *results){ + + // Checking that the number of features in the test data is same + // as in the training data DEBUG_ASSERT(test_data.n_rows() - 1 == means_.n_rows()); + ArrayList tmp_vals; double *evaluated_result; index_t number_features = test_data.n_rows() - 1; @@ -85,19 +146,30 @@ class SimpleNaiveBayesClassifier { evaluated_result = (double*)malloc(test_data.n_cols() * sizeof(double)); tmp_vals.Init(number_of_classes_); - printf("%"LI"d test cases with %"LI"d features each\n", test_data.n_cols(), number_features); + printf("%"LI"d test cases with %"LI"d features each\n", + test_data.n_cols(), number_features); + // Calculating the joint probability for each of the data points + // for each of the classes for (index_t n = 0; n < test_data.n_cols(); n++) { for (index_t i = 0; i < number_of_classes_; i++) { + // Using the log values to prevent floating point underflow tmp_vals[i] = log(class_probabilities_[i]); for (index_t j = 0; j < number_features; j++) { - tmp_vals[i] += log(phi(test_data.get(j, n), means_.get(j, i), variances_.get(j, i))); + tmp_vals[i] += log(phi(test_data.get(j, n), + means_.get(j, i), + variances_.get(j, i)) + ); } } + // Calling a function 'max_element_index' from the file 'math_functions.h + // to obtain the index of the maximum element in an array evaluated_result[n] = (double) max_element_index(tmp_vals); } + // The result is being put in a vector (*results).Copy(evaluated_result, test_data.n_cols()); return; } }; +#endif