comparison pymf/nndsvd.py @ 0:26838b1f560f

initial commit of a segmenter project
author mi tian
date Thu, 02 Apr 2015 18:09:27 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26838b1f560f
1 #!/usr/bin/python
2 #
3 # Copyright (C) Christian Thurau, 2010.
4 # Licensed under the GNU General Public License (GPL).
5 # http://www.gnu.org/licenses/gpl.txt
6 #$Id$
7 """
8 PyMF Non-negative Double Singular Value Decompositions.
9
10 NNDSVD: Class for Non-negative Double Singular Value Decompositions [1]
11
12 [1] C. Boutsidis and E. Gallopoulos (2008), SVD based initialization: A head
13 start for nonnegative matrix factorization, Pattern Recognition, 41, 1350-1362
14 """
15
16
17 import numpy as np
18
19 from nmf import NMF
20 from svd import SVD
21
22 __all__ = ["NNDSVD"]
23
24 class NNDSVD(NMF):
25 """
26 NNDSVD(data, num_bases=4)
27
28
29 Non-negative Double Singular Value Decompositions. Factorize a data
30 matrix into two matrices s.t. F = | data - W*H | = | is minimal. H, and
31 W are restricted to non-negative data. NNDSVD is primarily used for
32 initializing NMF.
33
34 Parameters
35 ----------
36 data : array_like, shape (_data_dimension, _num_samples)
37 the input data
38 num_bases: int, optional
39 Number of bases to compute (column rank of W and row rank of H).
40 4 (default)
41
42 Attributes
43 ----------
44 W : "data_dimension x num_bases" matrix of basis vectors
45 H : "num bases x num_samples" matrix of coefficients
46 ferr : frobenius norm (after calling .factorize())
47
48 Example
49 -------
50 Applying NNDSVD to some rather stupid data set:
51
52 >>> import numpy as np
53 >>> data = np.array([[1.0, 0.0, 2.0], [0.0, 1.0, 1.0]])
54 >>> nndsvd_mdl = NNDSVD(data, num_bases=2)
55 >>> nndsvd_mdl.factorize()
56
57 The basis vectors are now stored in nndsvd_mdl.W, the coefficients in
58 nndsvd_mdl.H. To initialize NMF with nndsvd_mdl.W, nndsvd_mdl.H
59 simply copy W to nmf_mdl.W and H to nmf_mdl.H:
60
61 >>> data = np.array([[1.5], [1.2]])
62 >>> W = np.array([[1.0, 0.0], [0.0, 1.0]])
63 >>> nmf_mdl = NMF(data, num_bases=2)
64 >>> nmf_mdl.W = nndsvd_mdl.W
65 >>> nmf_mdl.H = nndsvd_mdl.H
66 >>> nmf_mdl.factorize(niter=20)
67
68 The result is a set of (more optimal) coefficients nmf_mdl.H, nmf_mdl.W.
69 """
70 def init_w(self):
71 self.W = np.zeros((self._data_dimension, self._num_bases))
72
73 def init_h(self):
74 self.H = np.zeros((self._num_bases, self._num_samples))
75
76 def update_h(self):
77 pass
78
79 def update_w(self):
80 svd_mdl = SVD(self.data)
81 svd_mdl.factorize()
82
83 U, S, V = svd_mdl.U, svd_mdl.S, svd_mdl.V
84
85 # The first left singular vector is nonnegative
86 # (abs is only used as values could be all negative)
87 self.W[:,0] = np.sqrt(S[0,0]) * np.abs(U[:,0])
88
89 #The first right singular vector is nonnegative
90 self.H[0,:] = np.sqrt(S[0,0]) * np.abs(V[0,:].T)
91
92 for i in range(1,self._num_bases):
93 # Form the rank one factor
94 Tmp = np.dot(U[:,i:i+1]*S[i,i], V[i:i+1,:])
95
96 # zero out the negative elements
97 Tmp = np.where(Tmp < 0, 0.0, Tmp)
98
99 # Apply 2nd SVD
100 svd_mdl_2 = SVD(Tmp)
101 svd_mdl_2.factorize()
102 u, s, v = svd_mdl_2.U, svd_mdl_2.S, svd_mdl_2.V
103
104 # The first left singular vector is nonnegative
105 self.W[:,i] = np.sqrt(s[0,0]) * np.abs(u[:,0])
106
107 #The first right singular vector is nonnegative
108 self.H[i,:] = np.sqrt(s[0,0]) * np.abs(v[0,:].T)
109
110 def factorize(self, niter=1, show_progress=False,
111 compute_w=True, compute_h=True, compute_err=True):
112
113 # enforce certain default values, otherwise it won't work
114 NMF.factorize(self, niter=1, show_progress=show_progress,
115 compute_w=True, compute_h=True, compute_err=compute_err)
116
117 if __name__ == "__main__":
118 import doctest
119 doctest.testmod()