public class NMFactorization
extends java.lang.Object
m X n matrix V:
V ~= W H, W >= 0, H >= 0where
W is m X k and H is k X n, with
k (the number of factors) typically much smaller than either
m or n. The factorization minimizes the Frobenius norm of
the residual V - W H, optionally with an L2 (Tikhonov)
regularization on W and H.
A common application is the extraction of muscle synergies from
muscle excitation data, in which case the columns of V contain the
excitations for each of m muscles at each of n time samples,
the columns of W contain the k synergy vectors, and the rows
of H contain the time-varying activation coefficient for each
synergy.
Two update methods are available, selected by setUpdate(maspack.solvers.NMFactorization.Update):
NMFactorization.Update.ANLS (the default) performs alternating
non-negative least squares: with W fixed, each column of H
is the solution to a non-negative least squares (NNLS) problem, and with
H fixed, each row of W is likewise. Each NNLS problem is
solved exactly, as a k X k linear complementarity problem
(LCP), using DantzigLCPSolver. This is exact block coordinate
descent: the residual decreases monotonically, and since k is
usually small the k X k solves are very fast.
NMFactorization.Update.MULTIPLICATIVE uses the multiplicative update rules of
Lee and Seung. These are simpler but converge more slowly, and because a
factor entry which reaches zero can never become positive again, they can
stall at a non-stationary point. Provided mainly for comparison. Because the NMF problem is not convex, the result depends on the initial
values of W and H, which are set according to setInitialization(maspack.solvers.NMFactorization.Init). The default is NMFactorization.Init.NNDSVD, the non-negative
double singular value decomposition of Boutsidis and Gallopoulos, which is
deterministic and generally converges faster than a random start.
Alternatively, NMFactorization.Init.RANDOM may be used together with setNumRestarts(int), in which case the factorization is repeated and the result
with the lowest residual is retained.
The factorization is not unique: for any positive diagonal D,
W H = (W D)(inv(D) H). The factors are therefore ordered by
decreasing contribution and then normalized, as specified by setNormalization(maspack.solvers.NMFactorization.Normalization), so that results are comparable between runs. The default
scales each column of W so that its largest entry is 1.
Sample usage:
NMFactorization nmf = new NMFactorization();
nmf.factor (V, 4);
MatrixNd W = nmf.getW(); // synergy vectors
MatrixNd H = nmf.getH(); // activation coefficients
double vaf = nmf.getVAF();
References:
D. D. Lee and H. S. Seung, "Algorithms for non-negative matrix factorization", NIPS 13, 2001.
C. Boutsidis and E. Gallopoulos, "SVD based initialization: A head start for nonnegative matrix factorization", Pattern Recognition 41(4), 2008.
H. Kim and H. Park, "Nonnegative matrix factorization based on alternating nonnegativity constrained least squares", SIAM J. Matrix Analysis and Applications 30(2), 2008.
| Modifier and Type | Class and Description |
|---|---|
static class |
NMFactorization.Init
Method used to initialize the factors.
|
static class |
NMFactorization.Normalization
Normalization applied to the factors once the factorization is complete.
|
static class |
NMFactorization.Update
Method used to update the factors at each iteration.
|
| Modifier and Type | Field and Description |
|---|---|
static int |
DEFAULT_MAX_ITERATIONS
Default value for the maximum number of iterations.
|
static double |
DEFAULT_TOLERANCE
Default value for the convergence tolerance.
|
| Constructor and Description |
|---|
NMFactorization()
Creates a new, uninitialized NMFactorization.
|
NMFactorization(Matrix V,
int numFactors)
Creates a new NMFactorization and uses it to factor the matrix
V
into numFactors factors. |
| Modifier and Type | Method and Description |
|---|---|
double[] |
computeVAFs(Matrix V,
int minFactors,
int maxFactors)
Convenience method that factors
V for each number of factors from
minFactors to maxFactors and returns the resulting VAF
values, as described for getVAF(). |
void |
factor(Matrix V,
int numFactors)
Factors the non-negative
m X n matrix V into the product
of an m X k matrix W and a k X n matrix H, both non-negative, where k is given by numFactors. |
MatrixNd |
getH()
Returns the
k X n factor H. |
NMFactorization.Init |
getInitialization()
Queries the initialization method used by this factorization.
|
int |
getIterationCount()
Returns the number of iterations used by this factorization.
|
int |
getMaxIterations()
Queries the maximum number of iterations for this factorization.
|
NMFactorization.Normalization |
getNormalization()
Queries the normalization applied to the factors.
|
int |
getNumFactors()
Returns the number of factors
k for this factorization. |
int |
getNumRestarts()
Queries the number of restarts used by this factorization.
|
java.util.Random |
getRandomGenerator()
Queries the random generator used for random initialization.
|
MatrixNd |
getReconstruction()
Returns the reconstruction
W H of the matrix which was factored. |
double |
getRegularization()
Queries the regularization term for this factorization.
|
double |
getResidual()
Returns the relative residual
||V - W H||/||V|| of this
factorization, where the norms are Frobenius norms. |
double |
getTolerance()
Queries the convergence tolerance for this factorization.
|
NMFactorization.Update |
getUpdate()
Queries the update method used by this factorization.
|
double |
getVAF()
Returns the variance accounted for (VAF) by this factorization, defined
by
|
MatrixNd |
getW()
Returns the
m X k factor W. |
void |
setInitialization(NMFactorization.Init init)
Sets the initialization method used by this factorization.
|
void |
setMaxIterations(int maxi)
Sets the maximum number of iterations for this factorization.
|
void |
setNormalization(NMFactorization.Normalization normalization)
Sets the normalization applied to the factors once the factorization is
complete.
|
void |
setNumRestarts(int nrestarts)
Sets the number of times the factorization should be restarted, with the
result having the lowest residual being retained.
|
void |
setRandomGenerator(java.util.Random generator)
Sets the random generator used for random initialization.
|
void |
setRegularization(double lambda)
Sets an L2 regularization term
lambda for this factorization, so
that the quantity being minimized becomes |
void |
setTolerance(double tol)
Sets the convergence tolerance for this factorization.
|
void |
setUpdate(NMFactorization.Update update)
Sets the update method used by this factorization.
|
public static final double DEFAULT_TOLERANCE
public static final int DEFAULT_MAX_ITERATIONS
public NMFactorization()
public NMFactorization(Matrix V, int numFactors)
V
into numFactors factors.V - matrix to be factored. Must be non-negative.numFactors - number of factorspublic double getTolerance()
setTolerance(double)public void setTolerance(double tol)
getResidual()) between successive iterations falls below this value. The
default value is DEFAULT_TOLERANCE.tol - convergence tolerancepublic int getMaxIterations()
setMaxIterations(int)public void setMaxIterations(int maxi)
DEFAULT_MAX_ITERATIONS.maxi - maximum number of iterationspublic double getRegularization()
setRegularization(double)public void setRegularization(double lambda)
lambda for this factorization, so
that the quantity being minimized becomes
||V - W H||^2 + lambda (||W||^2 + ||H||^2)where all norms are Frobenius norms. This is used only by the
NMFactorization.Update.ANLS update. Regularization can improve conditioning when factors
are nearly collinear, at the cost of a slightly larger residual. The
default value is 0.lambda - regularization term. Must not be negative.public NMFactorization.Update getUpdate()
setUpdate(maspack.solvers.NMFactorization.Update)public void setUpdate(NMFactorization.Update update)
NMFactorization.Update.ANLS.update - update methodpublic NMFactorization.Init getInitialization()
setInitialization(maspack.solvers.NMFactorization.Init)public void setInitialization(NMFactorization.Init init)
NMFactorization.Init.NNDSVD.init - initialization methodpublic NMFactorization.Normalization getNormalization()
setNormalization(maspack.solvers.NMFactorization.Normalization)public void setNormalization(NMFactorization.Normalization normalization)
NMFactorization.Normalization.UNITY_MAX.normalization - factor normalizationpublic int getNumRestarts()
setNumRestarts(int)public void setNumRestarts(int nrestarts)
setInitialization(maspack.solvers.NMFactorization.Init)), since repeating a deterministic
initialization would simply repeat the same result. The default value is
1.nrestarts - number of restarts. Must be at least 1.public java.util.Random getRandomGenerator()
null if the default generator
of RandomGenerator is being usedsetRandomGenerator(java.util.Random)public void setRandomGenerator(java.util.Random generator)
null (the default), the generator supplied by RandomGenerator is used. Setting an explicitly seeded generator makes
randomly initialized factorizations repeatable.generator - random generator to use, or nullpublic void factor(Matrix V, int numFactors)
m X n matrix V into the product
of an m X k matrix W and a k X n matrix H, both non-negative, where k is given by numFactors.V - matrix to be factored. All entries must be non-negative.numFactors - number k of factors. Must be at least 1 and no
greater than min(m,n).public MatrixNd getW()
m X k factor W. The returned matrix is
internal to this factorization and should not be modified.Wpublic MatrixNd getH()
k X n factor H. The returned matrix is
internal to this factorization and should not be modified.Hpublic int getNumFactors()
k for this factorization.public double getResidual()
||V - W H||/||V|| of this
factorization, where the norms are Frobenius norms.public double getVAF()
VAF = 1 - ||V - W H||^2/||V||^2This is the measure conventionally used to select the number of factors when extracting muscle synergies.
public int getIterationCount()
public MatrixNd getReconstruction()
W H of the matrix which was factored.public double[] computeVAFs(Matrix V, int minFactors, int maxFactors)
V for each number of factors from
minFactors to maxFactors and returns the resulting VAF
values, as described for getVAF(). The number of synergies to use
is conventionally taken as the smallest for which the VAF exceeds some
threshold (typically 0.9 to 0.95).V - matrix to be factored. Must be non-negative.minFactors - minimum number of factors. Must be at least 1 and no
greater than maxFactors.maxFactors - maximum number of factorsk factors stored at
location k-minFactors