-
Notifications
You must be signed in to change notification settings - Fork 0
/
pca.py
87 lines (75 loc) · 2.91 KB
/
pca.py
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
import numpy as np
import processFrames
from scipy.optimize import minimize
class PCAL1:
"""
PCA model using L1 objective function rather than traditional L2 objective
function to identify outliers.
Given:
k number of components, number of iteration (optional)
and eps (optional) for multi-quardic approximation for L1 approximation
Return:
new X composed by PCA by calling fitTransform()
"""
def __init__( self, k, iteration=20, eps=0.0001 ):
self.k = k
self.iteration = iteration
self.eps = eps
def _fit( self, X, imgDim ):
n,d = X.shape
k = self.k
self.mu = np.mean( X, 0 )
X = X - self.mu
# Randomly initial Z, W
z = np.random.randn( n * k )
w = np.random.randn( k * d )
with processFrames.createFigureWrapper() as fig:
for i in range( self.iteration ):
zResult = minimize( self.zObjFunc, z, args=( w, X, k ),
method="CG", jac=True, options={'maxiter':10} )
z, fz = zResult.x, zResult.fun
wResult = minimize( self.wObjFunc, w, args=( z, X, k ),
method="CG", jac=True, options={'maxiter':10} )
w, fw = wResult.x, wResult.fun
print('Iteration %d, loss = %.1f, %.1f' % (i, fz, fw))
processFrames.plotSeparatedImage( X[ 0 ] + self.mu,
( z.reshape( n, k ) @ w.reshape(k,d) + self.mu )[ 0 ],
0.1, fig, imgDim )
self.W = w.reshape(k,d)
def _compress( self, X ):
n,d = X.shape
k = self.k
X = X - self.mu
# W may not be orthogonal so we need to solve for Z one last time...
z = np.zeros( n * k )
zResult = minimize( self.zObjFunc, z, args=( self.W.flatten(), X, k ),
method="CG", jac=True, options={'maxiter':100} )
z, fz = zResult.x, zResult.fun
Z = z.reshape( n, k )
return Z
def _expand( self, Z ):
X = Z @ self.W + self.mu
return X
def fitTransform( self, X, imgDim ):
self._fit( X, imgDim )
return self._expand( self._compress( X ) )
def zObjFunc( self, z, w, X, k ):
n,d = X.shape
Z = z.reshape(n,k)
W = w.reshape(k,d)
R = np.dot(Z,W) - X
f = np.sum( abs( R ) )
R[:] /= np.sqrt( R[:]**2 + self.eps )
g = np.dot( R, W.transpose() )
#print( "loss (fixed w): ", f )
return f, g.flatten()
def wObjFunc( self, w, z, X, k ):
n,d = X.shape
Z = z.reshape(n,k)
W = w.reshape(k,d)
R = np.dot(Z,W) - X
f = np.sum( abs( R ) )
R[:] /= np.sqrt( R[:]**2 + self.eps )
g = np.dot( Z.transpose(), R )
#print( "loss (fixed z): ", f )
return f, g.flatten()