# [mlpack-svn] r14889 - mlpack/trunk/src/mlpack/core/dists

fastlab-svn at coffeetalk-1.cc.gatech.edu fastlab-svn at coffeetalk-1.cc.gatech.edu
Wed Apr 10 17:09:46 EDT 2013

```Author: rcurtin
Date: 2013-04-10 17:09:46 -0400 (Wed, 10 Apr 2013)
New Revision: 14889

Modified:
mlpack/trunk/src/mlpack/core/dists/gaussian_distribution.cpp
Log:
Put in checks for non-invertible covariances after training; add perturbation to
avoid them where necessary.  Also avoid dividing by zero.

Modified: mlpack/trunk/src/mlpack/core/dists/gaussian_distribution.cpp
===================================================================
--- mlpack/trunk/src/mlpack/core/dists/gaussian_distribution.cpp	2013-04-10 19:41:43 UTC (rev 14888)
+++ mlpack/trunk/src/mlpack/core/dists/gaussian_distribution.cpp	2013-04-10 21:09:46 UTC (rev 14889)
@@ -22,8 +22,6 @@
*/
void GaussianDistribution::Estimate(const arma::mat& observations)
{
-  // Calculate the mean and covariance with each point.  Because this is a
-  // std::vector and not a matrix, this is a little more difficult.
if (observations.n_cols > 0)
{
mean.zeros(observations.n_rows);
@@ -33,6 +31,7 @@
{
mean.zeros(0);
covariance.zeros(0);
+    return;
}

// Calculate the mean.
@@ -52,6 +51,17 @@
// Finish estimating the covariance by normalizing, with the (1 / (n - 1)) so
// that it is the unbiased estimator.
covariance /= (observations.n_cols - 1);
+
+  // Ensure that there are no zeros on the diagonal.
+  for (size_t d = 0; d < covariance.n_rows; ++d)
+  {
+    if (covariance(d, d) == 0.0)
+    {
+      Log::Debug << "GaussianDistribution::Estimate(): covariance diagonal "
+          << "element " << d << " is 0; adding perturbation." << std::endl;
+      covariance(d, d) = 1e-50;
+    }
+  }
}

/**
@@ -71,6 +81,7 @@
{
mean.zeros(0);
covariance.zeros(0);
+    return;
}

double sumProb = 0;
@@ -83,6 +94,14 @@
sumProb += probabilities[i];
}

+  if (sumProb == 0)
+  {
+    // Nothing in this Gaussian!  At least set the covariance so that it's
+    // invertible.
+    covariance.diag() += 1e-50;
+    return;
+  }
+
// Normalize.
mean /= sumProb;

@@ -96,6 +115,16 @@
// This is probably biased, but I don't know how to unbias it.
covariance /= sumProb;

+  // Ensure that there are no zeros on the diagonal.
+  for (size_t d = 0; d < covariance.n_rows; ++d)
+  {
+    if (covariance(d, d) == 0.0)
+    {
+      Log::Debug << "GaussianDistribution::Estimate(): covariance diagonal "
+          << "element " << d << " is 0; adding perturbation." << std::endl;
+      covariance(d, d) = 1e-50;
+    }
+  }
}

/**

```