| 10 | |
| 11 | |
| 12 | class PCA(BaseEstimator): |
| 13 | y_required = False |
| 14 | |
| 15 | def __init__(self, n_components, solver="svd"): |
| 16 | """Principal component analysis (PCA) implementation. |
| 17 | |
| 18 | Transforms a dataset of possibly correlated values into n linearly |
| 19 | uncorrelated components. The components are ordered such that the first |
| 20 | has the largest possible variance and each following component as the |
| 21 | largest possible variance given the previous components. This causes |
| 22 | the early components to contain most of the variability in the dataset. |
| 23 | |
| 24 | Parameters |
| 25 | ---------- |
| 26 | n_components : int |
| 27 | solver : str, default 'svd' |
| 28 | {'svd', 'eigen'} |
| 29 | """ |
| 30 | self.solver = solver |
| 31 | self.n_components = n_components |
| 32 | self.components = None |
| 33 | self.mean = None |
| 34 | |
| 35 | def fit(self, X, y=None): |
| 36 | self.mean = np.mean(X, axis=0) |
| 37 | self._decompose(X) |
| 38 | |
| 39 | def _decompose(self, X): |
| 40 | # Mean centering |
| 41 | X = X.copy() |
| 42 | X -= self.mean |
| 43 | |
| 44 | if self.solver == "svd": |
| 45 | _, s, Vh = svd(X, full_matrices=True) |
| 46 | elif self.solver == "eigen": |
| 47 | s, Vh = np.linalg.eig(np.cov(X.T)) |
| 48 | Vh = Vh.T |
| 49 | |
| 50 | s_squared = s**2 |
| 51 | variance_ratio = s_squared / s_squared.sum() |
| 52 | logging.info( |
| 53 | "Explained variance ratio: %s" % (variance_ratio[0 : self.n_components]) |
| 54 | ) |
| 55 | self.components = Vh[0 : self.n_components] |
| 56 | |
| 57 | def transform(self, X): |
| 58 | X = X.copy() |
| 59 | X -= self.mean |
| 60 | return np.dot(X, self.components.T) |
| 61 | |
| 62 | def _predict(self, X=None): |
| 63 | return self.transform(X) |