[mlpack-svn] r16053 - mlpack/trunk/src/mlpack/methods/logistic_regression

fastlab-svn at coffeetalk-1.cc.gatech.edu fastlab-svn at coffeetalk-1.cc.gatech.edu
Thu Nov 21 10:40:40 EST 2013


Author: rcurtin
Date: Thu Nov 21 10:40:40 2013
New Revision: 16053

Log:
Refactor LogisticRegression class.  LearnModel() can be private, and we can
const-ize a lot of the parameters and functions.  Also restore functionality to
Predict(), ComputeError(), and ComputeAccuracy().  This does not ever make a
copy of the predictors matrix and doesn't add a column for the intercept, which
is faster.


Modified:
   mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression.hpp
   mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp

Modified: mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression.hpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression.hpp	(original)
+++ mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression.hpp	Thu Nov 21 10:40:40 2013
@@ -62,18 +62,49 @@
   //! Modify the lambda value for L2-regularization.
   double& Lambda() { return errorFunction().Lambda(); }
 
-  double LearnModel();
-
-  //predict functions
-  void Predict(arma::mat& predictors,
+  /**
+   * Predict the responses to a given set of predictors.  The responses will be
+   * either 0 or 1.  Optionally, specify the decision boundary; logistic
+   * regression returns a value between 0 and 1.  If the value is greater than
+   * the decision boundary, the response is taken to be 1; otherwise, it is 0.
+   * By default the decision boundary is 0.5.
+   *
+   * @param predictors Input predictors.
+   * @param responses Vector to put output predictions of responses into.
+   * @param decisionBoundary Decision boundary (default 0.5).
+   */
+  void Predict(const arma::mat& predictors,
                arma::vec& responses,
-               const double decisionBoundary = 0.5);
+               const double decisionBoundary = 0.5) const;
 
-  double ComputeAccuracy(arma::mat& predictors,
+  /**
+   * Compute the accuracy of the model on the given predictors and responses,
+   * optionally using the given decision boundary.  The responses should be
+   * either 0 or 1.  Logistic regression returns a value between 0 and 1.  If
+   * the value is greater than the decision boundary, the response is taken to
+   * be 1; otherwise, it is 0.  By default, the decision boundary is 0.5.
+   *
+   * The accuracy is returned as a percentage, between 0 and 100.
+   *
+   * @param predictors Input predictors.
+   * @param responses Vector of responses.
+   * @param decisionBoundary Decision boundary (default 0.5).
+   * @return Percentage of responses that are predicted correctly.
+   */
+  double ComputeAccuracy(const arma::mat& predictors,
                          const arma::vec& responses,
-                         const double decisionBoundary = 0.5);
+                         const double decisionBoundary = 0.5) const;
 
-  double ComputeError(arma::mat& predictors, const arma::vec& responses);
+  /**
+   * Compute the error of the model.  This returns the negative objective
+   * function of the logistic regression log-likelihood function.  For the model
+   * to be optimal, the negative log-likelihood function should be minimized.
+   *
+   * @param predictors Input predictors.
+   * @param responses Vector of responses.
+   */
+  double ComputeError(const arma::mat& predictors,
+                      const arma::vec& responses) const;
 
  private:
   //! Matrix of predictor points (X).
@@ -87,6 +118,12 @@
   LogisticRegressionFunction errorFunction;
   //! Instantiated optimizer.
   OptimizerType<LogisticRegressionFunction> optimizer;
+
+  /**
+   * Learn the model by optimizing the logistic regression objective function.
+   * Returns the objective function evaluated when the parameters are optimized.
+   */
+  double LearnModel();
 };
 
 }; // namespace regression

Modified: mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp	(original)
+++ mlpack/trunk/src/mlpack/methods/logistic_regression/logistic_regression_impl.hpp	Thu Nov 21 10:40:40 2013
@@ -21,10 +21,12 @@
     const double lambda) :
     predictors(predictors),
     responses(responses),
+    parameters(arma::zeros<arma::vec>(predictors.n_rows + 1)),
     errorFunction(LogisticRegressionFunction(predictors, responses, lambda)),
     optimizer(OptimizerType<LogisticRegressionFunction>(errorFunction))
 {
-  parameters.zeros(predictors.n_rows + 1);
+  // Train the model.
+  LearnModel();
 }
 
 template<template<typename> class OptimizerType>
@@ -35,74 +37,66 @@
     const double lambda) :
     predictors(predictors),
     responses(responses),
+    parameters(arma::zeros<arma::vec>(predictors.n_rows + 1)),
     errorFunction(LogisticRegressionFunction(predictors, responses)),
     optimizer(OptimizerType<LogisticRegressionFunction>(errorFunction))
 {
-  parameters.zeros(predictors.n_rows + 1);
+  // Train the model.
+  LearnModel();
 }
 
 template <template<typename> class OptimizerType>
-double LogisticRegression<OptimizerType>::LearnModel()
-{
-  Timer::Start("logistic_regression_optimization");
-  const double out = optimizer.Optimize(parameters);
-  Timer::Stop("logistic_regression_optimization");
-
-  return out;
+void LogisticRegression<OptimizerType>::Predict(const arma::mat& predictors,
+                                                arma::vec& responses,
+                                                const double decisionBoundary)
+    const
+{
+  // Calculate sigmoid function for each point.  The (1.0 - decisionBoundary)
+  // term correctly sets an offset so that floor() returns 0 or 1 correctly.
+  responses = arma::floor((1.0 / (1.0 + arma::exp(-parameters(0)
+      - predictors.t() * parameters.subvec(1, parameters.n_elem - 1))))
+      + (1.0 - decisionBoundary));
 }
 
 template <template<typename> class OptimizerType>
 double LogisticRegression<OptimizerType>::ComputeError(
-    arma::mat& predictors,
-    const arma::vec& responses)
+    const arma::mat& predictors,
+    const arma::vec& responses) const
 {
-  // Here we add the row of ones to the predictors.
-  arma::rowvec ones;
-  ones.ones(predictors.n_cols);
-  predictors.insert_rows(0, ones);
-
-//  double out = errorFunction.Evaluate(predictors, responses, parameters);
+  // Construct a new error function.
+  LogisticRegressionFunction newErrorFunction(predictors, responses,
+      errorFunction.Lambda());
 
-  predictors.shed_row(0);
-
-//  return out;
-  return 0.0;
+  return newErrorFunction.Evaluate(parameters);
 }
 
 template <template<typename> class OptimizerType>
 double LogisticRegression<OptimizerType>::ComputeAccuracy(
-    arma::mat& predictors,
+    const arma::mat& predictors,
     const arma::vec& responses,
-    const double decisionBoundary)
+    const double decisionBoundary) const
 {
+  // Predict responses using the current model.
   arma::vec tempResponses;
   Predict(predictors, tempResponses, decisionBoundary);
-  int count = 0;
-  for (size_t i = 0; i < responses.n_rows; i++)
-    if (responses(i, 0) == tempResponses(i, 0))
+
+  // Count the number of responses that were correct.
+  size_t count = 0;
+  for (size_t i = 0; i < responses.n_elem; i++)
+    if (responses(i) == tempResponses(i))
       count++;
 
   return (double) (count * 100) / responses.n_rows;
 }
 
 template <template<typename> class OptimizerType>
-void LogisticRegression<OptimizerType>::Predict(
-    arma::mat& predictors,
-    arma::vec& responses,
-    const double decisionBoundary)
-{
-  //add rows of ones to predictors
-  arma::rowvec ones;
-  ones.ones(predictors.n_cols);
-  predictors.insert_rows(0, ones);
-
-//  responses = arma::floor(
-//      errorFunction.getSigmoid(arma::trans(predictors) * parameters) -
-//      decisionBoundary * arma::ones<arma::vec>(predictors.n_cols, 1)) +
-//      arma::ones<arma::vec>(predictors.n_cols);
+double LogisticRegression<OptimizerType>::LearnModel()
+{
+  Timer::Start("logistic_regression_optimization");
+  const double out = optimizer.Optimize(parameters);
+  Timer::Stop("logistic_regression_optimization");
 
-  //shed the added rows
-  predictors.shed_row(0);
+  return out;
 }
 
 }; // namespace regression



More information about the mlpack-svn mailing list