Skip to content

Commit 9657bd6

Browse files
committed
Merge pull request scikit-learn#2396 from dengemann/insert_fast_dot
ENH: put fast dot to PCA, ICA and FA
2 parents baa8ba4 + ffbead9 commit 9657bd6

File tree

4 files changed

+19
-17
lines changed

4 files changed

+19
-17
lines changed

doc/developers/performance.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ replacement for `numpy.dot`. example::
9898

9999
>>> X = np.random.random_sample([2, 10])
100100

101-
>>> (np.dot(X, X.T) == fast_dot(X, X.T)).all()
101+
>>> np.allclose(np.dot(X, X.T), fast_dot(X, X.T))
102102
True
103103

104104
However this requires data to be exactly 2 dimensional and of the same type,

sklearn/decomposition/factor_analysis.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from ..base import BaseEstimator, TransformerMixin
2020
from ..externals.six.moves import xrange
2121
from ..utils import array2d, check_arrays
22-
from ..utils.extmath import fast_logdet
22+
from ..utils.extmath import fast_logdet, fast_dot
2323

2424

2525
class FactorAnalysis(BaseEstimator, TransformerMixin):
@@ -193,8 +193,8 @@ def transform(self, X):
193193

194194
Wpsi = self.components_ / self.noise_variance_
195195
cov_z = linalg.inv(Ih + np.dot(Wpsi, self.components_.T))
196-
tmp = np.dot(X_transformed, Wpsi.T)
197-
X_transformed = np.dot(tmp, cov_z)
196+
tmp = fast_dot(X_transformed, Wpsi.T)
197+
X_transformed = fast_dot(tmp, cov_z)
198198

199199
return X_transformed
200200

sklearn/decomposition/fastica_.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from ..externals import six
1717
from ..externals.six import moves
1818
from ..utils import array2d, as_float_array, check_random_state, deprecated
19+
from ..utils.extmath import fast_dot
1920

2021
__all__ = ['fastica', 'FastICA']
2122

@@ -66,7 +67,7 @@ def _ica_def(X, tol, g, fun_args, max_iter, w_init):
6667
w /= np.sqrt((w ** 2).sum())
6768

6869
for _ in moves.xrange(max_iter):
69-
gwtx, g_wtx = g(np.dot(w.T, X), fun_args)
70+
gwtx, g_wtx = g(fast_dot(w.T, X), fun_args)
7071

7172
w1 = (X * gwtx).mean(axis=1) - g_wtx.mean() * w
7273

@@ -94,12 +95,12 @@ def _ica_par(X, tol, g, fun_args, max_iter, w_init):
9495
del w_init
9596
p_ = float(X.shape[1])
9697
for ii in moves.xrange(max_iter):
97-
gwtx, g_wtx = g(np.dot(W, X), fun_args)
98-
W1 = _sym_decorrelation(np.dot(gwtx, X.T) / p_
98+
gwtx, g_wtx = g(fast_dot(W, X), fun_args)
99+
W1 = _sym_decorrelation(fast_dot(gwtx, X.T) / p_
99100
- g_wtx[:, np.newaxis] * W)
100101
del gwtx, g_wtx
101102
# builtin max, abs are faster than numpy counter parts.
102-
lim = max(abs(abs(np.diag(np.dot(W1, W.T))) - 1))
103+
lim = max(abs(abs(np.diag(fast_dot(W1, W.T))) - 1))
103104
W = W1
104105
if lim < tol:
105106
break
@@ -322,7 +323,7 @@ def g(x, fun_args):
322323

323324
if whiten:
324325
if compute_sources:
325-
S = np.dot(np.dot(W, K), X).T
326+
S = fast_dot(fast_dot(W, K), X).T
326327
else:
327328
S = None
328329
if return_X_mean:
@@ -331,7 +332,7 @@ def g(x, fun_args):
331332
return K, W, S
332333
else:
333334
if compute_sources:
334-
S = np.dot(W, X).T
335+
S = fast_dot(W, X).T
335336
else:
336337
S = None
337338
if return_X_mean:
@@ -508,7 +509,7 @@ def transform(self, X, y=None, copy=True):
508509
if self.whiten:
509510
X -= self.mean_
510511

511-
return np.dot(X, self.components_.T)
512+
return fast_dot(X, self.components_.T)
512513

513514
@deprecated('To be removed in 0.16. Use the `mixing_` attribute.')
514515
def get_mixing_matrix(self):
@@ -543,7 +544,7 @@ def inverse_transform(self, X, copy=True):
543544
"""
544545
if copy:
545546
X = X.copy()
546-
X = np.dot(X, self.mixing_.T)
547+
X = fast_dot(X, self.mixing_.T)
547548
if self.whiten:
548549
X += self.mean_
549550

sklearn/decomposition/pca.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# Author: Alexandre Gramfort <[email protected]>
55
# Olivier Grisel <[email protected]>
66
# Mathieu Blondel <[email protected]>
7+
# Denis A. Engemann <[email protected]>
8+
#
79
# License: BSD 3 clause
810

911
from math import log, sqrt
@@ -16,9 +18,8 @@
1618
from ..base import BaseEstimator, TransformerMixin
1719
from ..utils import array2d, check_random_state, as_float_array
1820
from ..utils import atleast2d_or_csr
19-
from ..utils.extmath import fast_logdet
20-
from ..utils.extmath import safe_sparse_dot
21-
from ..utils.extmath import randomized_svd
21+
from ..utils.extmath import fast_logdet, safe_sparse_dot, randomized_svd, \
22+
fast_dot
2223

2324

2425
def _assess_dimension_(spectrum, rank, n_samples, n_features):
@@ -303,7 +304,7 @@ def transform(self, X):
303304
X = array2d(X)
304305
if self.mean_ is not None:
305306
X = X - self.mean_
306-
X_transformed = np.dot(X, self.components_.T)
307+
X_transformed = fast_dot(X, self.components_.T)
307308
return X_transformed
308309

309310
def inverse_transform(self, X):
@@ -325,7 +326,7 @@ def inverse_transform(self, X):
325326
If whitening is enabled, inverse_transform does not compute the
326327
exact inverse operation as transform.
327328
"""
328-
return np.dot(X, self.components_) + self.mean_
329+
return fast_dot(X, self.components_) + self.mean_
329330

330331

331332
class ProbabilisticPCA(PCA):

0 commit comments

Comments
 (0)