This repository was archived by the owner on Sep 22, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfastica.py
131 lines (119 loc) · 3.92 KB
/
fastica.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
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
__all__ = ["FastICA","fastica"]
import sys,os,random,math,numpy,pylab,scipy,scipy.linalg
from numpy import *
from scipy.linalg import norm
from pylab import imshow,show,clf,gray
verbose = 0
def project_perp(data,vs):
"Project on the space perpendicular to the space spanned by the vs."
if len(vs.shape)==1: vs = vs.reshape(1,len(vs))
for v in vs:
v = v/norm(v)
for i in range(len(data)):
data[i] -= dot(v,data[i]) * v
def fraction(evals,frac):
"Find a quantile (fractile)."
p = evals/sum(evals)
p.sort()
p = cumsum(p)
k = searchsorted(p,frac,side="left")
return k
def pca(data,k=None,frac=0.99,whiten=1):
"""Compute the PCA and whitening of the input data.
Returns the transformed data, the mean, the eigenvalues,
and the eigenvectors."""
n,d = data.shape
mean = average(data,axis=0).reshape(1,d)
data = data - mean.reshape(1,d)
cov = dot(data.T,data)/n
evals,evecs = linalg.eig(cov)
if k is None: k = fraction(evals,frac)
top = argsort(-evals)
evals = evals[top[:k]]
evecs = evecs.T[top[:k]]
assert evecs.shape==(k,d)
ys = dot(evecs,data.T)
assert ys.shape==(k,n)
if whiten: ys = dot(diag(sqrt(1.0/evals)),ys)
return (ys.T,mean,evals,evecs)
def g(x):
"Nonlinear function for fastica."
return x**3
def gp(x):
"Derivative of nonlinear function for fastica."
return 3*x**2
def fastica1(data,maxiter=1000,g=g,gp=gp,eps=1e-3):
"""Perform fast-ICA for one component using the given g function;
gp must be the derivative of g."""
n,d = data.shape
iter = 0
index = argmax([norm(x) for x in data])
w = data[index]
w /= norm(w)
while iter<maxiter:
iter += 1
w1 = zeros(d)
for i in range(len(data)):
x = data[i]
dp = dot(w,x)
v = g(dp)*x - gp(dp)*w
w1 += v
w1 /= norm(w1)
if average(w1)<0: w1 = -w1
delta = 1.0 - abs(dot(w,w1))
if verbose: print iter,delta
if delta<eps: return w1
w = w1
return None
def fastica(data,ncomp,maxiter=1000,g=g,gp=gp,eps=1e-2):
"""Perform fast-ICA for ncomp components using the given
g and g' functions."""
result = []
for comp in range(ncomp):
w = fastica1(data,maxiter=maxiter,g=g,gp=gp,eps=eps)
result.append(w)
project_perp(data,w)
if verbose: print comp,amin(data),amax(data)
return array(result)
class FastICA:
"""Compute an ICA data transformation using the given
training data. Also performs PCA and whitening of the
data prior to invoking FastICA."""
w = None
def train(self,data,k=None,pca_k=None,frac=0.99,g=g,gp=gp):
"""Train using the given data set."""
assert self.w is None
n,d = data.shape
ys,mean,evals,evecs = pca(data,k=pca_k,frac=frac)
assert "ys",ys.shape==(n,len(evals))
if verbose: print "#pca",len(evals),"#ica",k
if not k: k = len(evals)
comps = fastica(ys,ncomp=k)
self.mean = mean
self.w = dot(comps,evecs)
def transform(self,data):
"""Transform data using the PCA and ICA transformations."""
n,d = data.shape
assert d==self.w.shape[1]
assert self.w is not None
k,d = self.w.shape
return dot(data-self.mean.reshape(1,d),self.w.T)
def reconstruct(self,data):
"""Perform the inverse transformation given the components."""
k,d = self.w.shape
return dot(data,self.w)+self.mean.reshape(1,d)
def save(self,stream):
"""Save the transformer."""
self.mean.dump(stream)
self.w.dump(stream)
def load(self,stream):
"""Load the transformer."""
self.mean = load(stream)
self.w = load(stream)
import unittest
from test_transformer import *
class TestFastICA(TestBatchTransformer):
params = {"k":3,"pca_k":5}
factory = FastICA
if __name__ == "__main__":
unittest.main()