Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions sklearn/decomposition/fastica_.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ def _cube(x, fun_args):

def fastica(X, n_components=None, algorithm="parallel", whiten=True,
fun="logcosh", fun_args=None, max_iter=200, tol=1e-04, w_init=None,
random_state=None, return_X_mean=False, compute_sources=True,
return_n_iter=False):
svd_solver='svd', random_state=None, return_X_mean=False,
compute_sources=True, return_n_iter=False):
"""Perform Fast Independent Component Analysis.

Read more in the :ref:`User Guide <ICA>`.
Expand Down Expand Up @@ -203,6 +203,11 @@ def my_g(x):
Initial un-mixing array of dimension (n.comp,n.comp).
If None (default) then an array of normal r.v.'s is used.

svd_solver : str, optional
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this whitening_solver

The solver to use for whitening. Can either be 'svd' or 'eigh'.
'svd' is more stable numerically if the problem is degenerate.
'eigh' is generally faster.

random_state : int, RandomState instance or None, optional (default=None)
If int, random_state is the seed used by the random number generator;
If RandomState instance, random_state is the random number generator;
Expand Down Expand Up @@ -309,9 +314,19 @@ def g(x, fun_args):
X -= X_mean[:, np.newaxis]

# Whitening and preprocessing by PCA
u, d, _ = linalg.svd(X, full_matrices=False)

del _
if svd_solver == 'eigh' and n < p:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with n < p you change the behavior of existing code. Does it affect any test?

D, u = linalg.eigh(X.dot(X.T)) # Faster when n < p
eps = np.finfo(np.double).eps
degenerate_idx = D < eps
if np.any(degenerate_idx):
warnings.warn('There are some small singular values, using '
'svd_solver = \'svd\' might lead to more '
'accurate results.')
D[degenerate_idx] = eps # For numerical issues
d = np.sqrt(D)
del D
else:
u, d, _ = linalg.svd(X, full_matrices=False)
K = (u / d).T[:n_components] # see (6.33) p.140
del u, d
X1 = np.dot(K, X)
Expand Down Expand Up @@ -423,6 +438,11 @@ def my_g(x):
w_init : None of an (n_components, n_components) ndarray
The mixing matrix to be used to initialize the algorithm.

svd_solver : str, optional
The solver to use for whitening. Can either be 'svd' or 'eigh'.
'svd' is more stable numerically if the problem is degenerate.
'eigh' is generally faster.

random_state : int, RandomState instance or None, optional (default=None)
If int, random_state is the seed used by the random number generator;
If RandomState instance, random_state is the random number generator;
Expand Down Expand Up @@ -452,7 +472,7 @@ def my_g(x):
"""
def __init__(self, n_components=None, algorithm='parallel', whiten=True,
fun='logcosh', fun_args=None, max_iter=200, tol=1e-4,
w_init=None, random_state=None):
w_init=None, svd_solver='svd', random_state=None):
super(FastICA, self).__init__()
self.n_components = n_components
self.algorithm = algorithm
Expand All @@ -463,6 +483,7 @@ def __init__(self, n_components=None, algorithm='parallel', whiten=True,
self.tol = tol
self.w_init = w_init
self.random_state = random_state
self.svd_solver = svd_solver

def _fit(self, X, compute_sources=False):
"""Fit the model
Expand All @@ -487,7 +508,8 @@ def _fit(self, X, compute_sources=False):
whiten=self.whiten, fun=self.fun, fun_args=fun_args,
max_iter=self.max_iter, tol=self.tol, w_init=self.w_init,
random_state=self.random_state, return_X_mean=True,
compute_sources=compute_sources, return_n_iter=True)
compute_sources=compute_sources, return_n_iter=True,
svd_solver=self.svd_solver)

if self.whiten:
self.components_ = np.dot(unmixing, whitening)
Expand Down
6 changes: 4 additions & 2 deletions sklearn/decomposition/tests/test_fastica.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ def g_test(x):
assert_almost_equal(np.dot(s2_, s2) / n_samples, 1, decimal=1)

# Test FastICA class
_, _, sources_fun = fastica(m.T, fun=nl, algorithm=algo, random_state=0)
ica = FastICA(fun=nl, algorithm=algo, random_state=0)
_, _, sources_fun = fastica(m.T, fun=nl, algorithm=algo, random_state=0,
svd_solver='eigh')
ica = FastICA(fun=nl, algorithm=algo, random_state=0,
svd_solver='eigh')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the svd method still tested?

you should loop over solver options

sources = ica.fit_transform(m.T)
assert_equal(ica.components_.shape, (2, 2))
assert_equal(sources.shape, (1000, 2))
Expand Down