File: NMFns-class.R

package info (click to toggle)
r-cran-nmf 0.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 3,344 kB
  • sloc: cpp: 680; ansic: 7; makefile: 2
file content (174 lines) | stat: -rw-r--r-- 6,049 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#' @include NMFstd-class.R
NULL

#' NMF Model - Nonsmooth Nonnegative Matrix Factorization
#' 
#' This class implements the \emph{Nonsmooth Nonnegative Matrix Factorization}
#' (nsNMF) model, required by the Nonsmooth NMF algorithm.
#' 
#' The Nonsmooth NMF algorithm is defined by \cite{Pascual-Montano2006} as a
#' modification of the standard divergence based NMF algorithm (see section
#' Details and references below).  It aims at obtaining sparser factor
#' matrices, by the introduction of a smoothing matrix.
#' 
#' @details
#' The Nonsmooth NMF algorithm is a modification of the standard divergence
#' based NMF algorithm (see \code{\linkS4class{NMF}}).  
#' Given a non-negative \eqn{n \times p}{n x p} matrix \eqn{V} and a 
#' factorization rank \eqn{r}, it fits the following model: 
#' 
#' \deqn{V \equiv W S(\theta) H,}{V ~ W S(theta) H,} 
#' where: 
#' \itemize{ 
#' 
#' \item \eqn{W} and \eqn{H} are such as in the standard model, i.e. 
#' non-negative matrices of dimension \eqn{n \times r}{n x r}
#' and \eqn{r \times p}{r x p} respectively; 
#' 
#' \item \eqn{S} is a \eqn{r \times r} square matrix whose entries depends on 
#' an extra parameter \eqn{0\leq \theta \leq 1} in the following way: 
#' \deqn{S = (1-\theta)I + \frac{\theta}{r} 11^T ,}
#' where \eqn{I} is the identity matrix and \eqn{1}
#' is a vector of ones.
#'  
#' }
#' 
#' The interpretation of S as a smoothing matrix can be explained as follows:
#' Let \eqn{X} be a positive, nonzero, vector. Consider the transformed vector
#' \eqn{Y = S X}. If \eqn{\theta = 0}, then \eqn{Y = X} and no smoothing on
#' \eqn{X} has occurred.  However, as \eqn{\theta \to 1}{theta tends to 1}, the
#' vector \eqn{Y} tends to the constant vector with all elements almost equal
#' to the average of the elements of \eqn{X}. This is the smoothest possible
#' vector in the sense of non-sparseness because all entries are equal to the
#' same nonzero value, instead of having some values close to zero and others
#' clearly nonzero.
#' 
#' @section Creating objects from the Class:
#' 
#' Object of class \code{NMFns} can be created using the standard way with
#' operator \code{\link{new}}
#' 
#' However, as for all NMF model classes -- that extend class 
#' \code{\linkS4class{NMF}}, objects of class \code{NMFns} should be
#' created using factory method \code{\link{nmfModel}} :
#' 
#' \code{new('NMFns')}
#' 
#' \code{nmfModel(model='NMFns')}
#' 
#' \code{nmfModel(model='NMFns', W=w, theta=0.3}
#' 
#' See \code{\link{nmfModel}} for more details on how to use the factory
#' method.
#' 
#' @section Algorithm:
#' 
#' The Nonsmooth NMF algorithm uses a modified version of the multiplicative
#' update equations in Lee & Seung's method for Kullback-Leibler divergence
#' minimization.  
#' The update equations are modified to take into account the --
#' constant -- smoothing matrix.  
#' The modification reduces to using matrix \eqn{W S} instead of matrix \eqn{W} 
#' in the update of matrix \eqn{H}, and similarly using matrix \eqn{S H} 
#' instead of matrix \eqn{H} in the update of matrix \eqn{W}.
#' 
#' After the matrix \eqn{W} has been updated, each of its columns is scaled so
#' that it sums up to 1.
#' 
#' @export
#' @family NMF-model
#' @examples
#' 
#' # create a completely empty NMFns object
#' new('NMFns')
#' 
#' # create a NMF object based on random (compatible) matrices
#' n <- 50; r <- 3; p <- 20
#' w <- rmatrix(n, r) 
#' h <- rmatrix(r, p)
#' nmfModel(model='NMFns', W=w, H=h)
#' 
#' # apply Nonsmooth NMF algorithm to a random target matrix
#' V <- rmatrix(n, p)
#' \dontrun{nmf(V, r, 'ns')}
#' 
#' # random nonsmooth NMF model  
#' rnmf(3, 10, 5, model='NMFns', theta=0.3)
#' 
setClass('NMFns'
	, representation(
				theta = 'numeric' # smoothing matrix
				)
	, contains = 'NMFstd'
  	, prototype = prototype(
				theta = 0.5
				)
	, validity = function(object){
		if( object@theta < 0 || object@theta > 1 ) 
			return(paste("Invalid value for theta (",object@theta,"): must be between 0 and 1", sep=''))
		TRUE
	}
)

#' Show method for objects of class \code{NMFns}
#' @export
setMethod('show', 'NMFns', 
		function(object)
		{			
			callNextMethod()
			cat("theta:", object@theta, "\n")
		}
)

#' Compute estimate for an NMFns object, according to the Nonsmooth NMF model 
#' (cf. \code{\link{NMFns-class}}).
#' 
#' Extra arguments in \code{...} are passed to method \code{smoothing}, and are 
#' typically used to pass a value for \code{theta}, which is used to compute 
#' the smoothing matrix instead of the one stored in \code{object}.
#' 
#' @param S smoothing matrix to use instead of \code{smoothing(object)}
#' It must be a square matrix compatible with the basis and coefficient matrices 
#' used in the computation.
#' @inline
#' 
setMethod('fitted', signature(object='NMFns'), 
	function(object, W, H, S, ...){
		if( missing(W) ) W <- object@W
		if( missing(H) ) H <- object@H
		if( missing(S) ) S <- smoothing(object, ...)
		W %*% (S %*% H)		
	}
)

#' Smoothing Matrix in Nonsmooth NMF Models
#' 
#' The function \code{smoothing} builds a smoothing matrix for using in Nonsmooth 
#' NMF models.
#'  
#' For a \eqn{r}-rank NMF, the smoothing matrix of parameter \eqn{\theta} is 
#' built as follows:
#' \deqn{S = (1-\theta)I + \frac{\theta}{r} 11^T ,}
#' where \eqn{I} is the identity matrix and \eqn{1} is a vector of ones 
#' (cf. \code{\link{NMFns-class}} for more details).
#' 
#' @param x a object of class \code{NMFns}.
#' @param theta the smoothing parameter (numeric) between 0 and 1.
#' @param ... extra arguments to allow extension (not used)   
#' 
#' @return if \code{x} estimates a \eqn{r}-rank NMF, 
#' then the result is a \eqn{r \times r} square matrix.
#' @export
#' 
#' @examples
#' x <- nmfModel(3, model='NMFns')
#' smoothing(x)
#' smoothing(x, 0.1)
#' 
smoothing <- function(x, theta=x@theta, ...){	
	# check validity of theta
	if( theta < 0 || theta > 1 ) 
		stop("Invalid smoothing parameter theta [",theta,"]: theta must be susch that 0 <= theta <=1")
	diag(1-theta, nbasis(x)) + theta / nbasis(x)		
}