def Solve(self, K): #GET EIGENVALUES AND EIGENVECTOR THE CENTER KERNEL self.lambdas_, self.vectors_ = linalg.eigh( K, eigvals=(K.shape[0] - self.n_components, K.shape[0] - 1)) # make sure that the eigenvalues are ok and fix numerical issues self.lambdas_ = _check_psd_eigenvalues(self.lambdas_, enable_warnings=False) # flip eigenvectors' sign to enforce deterministic output self.vectors_, _ = svd_flip(self.vectors_, np.empty_like(self.vectors_).T) # sort eigenvectors in descending order indices = self.lambdas_.argsort()[::-1] self.lambdas_ = self.lambdas_[indices] self.vectors_ = self.vectors_[:, indices] # remove eigenvectors with a zero eigenvalue (null space) if required if self.remove_zero_eig: self.vectors_ = self.vectors_[:, self.lambdas_ > 0] self.lambdas_ = self.lambdas_[self.lambdas_ > 0] return K
def test_kernel_conditioning(): """ Test that ``_check_psd_eigenvalues`` is correctly called Non-regression test for issue #12140 (PR #12145)""" # create a pathological X leading to small non-zero eigenvalue X = [[5, 1], [5 + 1e-8, 1e-8], [5 + 1e-8, 0]] kpca = KernelPCA(kernel="linear", n_components=2, fit_inverse_transform=True) kpca.fit(X) # check that the small non-zero eigenvalue was correctly set to zero assert kpca.lambdas_.min() == 0 assert np.all(kpca.lambdas_ == _check_psd_eigenvalues(kpca.lambdas_))
def test_check_psd_eigenvalues_valid(lambdas, expected_lambdas, w_type, w_msg, enable_warnings): # Test that ``_check_psd_eigenvalues`` returns the right output for valid # input, possibly raising the right warning if not enable_warnings: w_type = None w_msg = "" with pytest.warns(w_type, match=w_msg) as w: assert_array_equal( _check_psd_eigenvalues(lambdas, enable_warnings=enable_warnings), expected_lambdas) if w_type is None: assert not w
def Solve(self, K): # SELECT THE BEST METHOD TO CALCULATE THE EIGENVALUES if self.eigen_solver == 'auto': if K.shape[0] > 200 and self.n_components < 10: eigen_solver = 'arpack' else: eigen_solver = 'dense' else: eigen_solver = self.eigen_solver #GET EIGENVALUES AND EIGENVECTOR THE CENTER KERNEL if eigen_solver == 'dense': self.lambdas_, self.vectors_ = linalg.eigh( K, eigvals=(K.shape[0] - self.n_components, K.shape[0] - 1)) elif eigen_solver == 'arpack': random_state = check_random_state(self.random_state) # initialize with [-1,1] as in ARPACK v0 = random_state.uniform(-1, 1, K.shape[0]) self.lambdas_, self.vectors_ = eigsh(K, self.n_components, which="LA", tol=self.tol, maxiter=self.max_iter, v0=v0) # make sure that the eigenvalues are ok and fix numerical issues self.lambdas_ = _check_psd_eigenvalues(self.lambdas_, enable_warnings=False) # flip eigenvectors' sign to enforce deterministic output self.vectors_, _ = svd_flip(self.vectors_, np.empty_like(self.vectors_).T) # sort eigenvectors in descending order indices = self.lambdas_.argsort()[::-1] self.lambdas_ = self.lambdas_[indices] self.vectors_ = self.vectors_[:, indices] # remove eigenvectors with a zero eigenvalue (null space) if required if self.remove_zero_eig: self.vectors_ = self.vectors_[:, self.lambdas_ > 0] self.lambdas_ = self.lambdas_[self.lambdas_ > 0] return K
def _fit_transform(self, K): """ Fit's using kernel K""" # center kernel K = self._centerer.fit_transform(K) self.lambdas_, self.alphas_ = linalg.eigh( K, eigvals=(K.shape[0] - self.n_components, K.shape[0] - 1)) # make sure that the eigenvalues are ok and fix numerical issues self.lambdas_ = _check_psd_eigenvalues(self.lambdas_, enable_warnings=False) # flip eigenvectors' sign to enforce deterministic output self.alphas_, _ = svd_flip(self.alphas_, np.empty_like(self.alphas_).T) # sort eigenvectors in descending order indices = self.lambdas_.argsort()[::-1] self.lambdas_ = self.lambdas_[indices] self.alphas_ = self.alphas_[:, indices] # remove eigenvectors with a zero eigenvalue (null space) if required self.alphas_ = self.alphas_[:, self.lambdas_ > 0] self.lambdas_ = self.lambdas_[self.lambdas_ > 0] # Maintenance note on Eigenvectors normalization # ---------------------------------------------- # there is a link between # the eigenvectors of K=Phi(X)'Phi(X) and the ones of Phi(X)Phi(X)' # if v is an eigenvector of K # then Phi(X)v is an eigenvector of Phi(X)Phi(X)' # if u is an eigenvector of Phi(X)Phi(X)' # then Phi(X)'u is an eigenvector of Phi(X)Phi(X)' # # At this stage our self.alphas_ (the v) have norm 1, we need to scale # them so that eigenvectors in kernel feature space (the u) have norm=1 # instead # # We COULD scale them here: # self.alphas_ = self.alphas_ / np.sqrt(self.lambdas_) # # But choose to perform that LATER when needed, in `fit()` and in # `transform()`. return K
def test_check_psd_eigenvalues_invalid(lambdas, err_type, err_msg): # Test that ``_check_psd_eigenvalues`` raises the right error for invalid # input with pytest.raises(err_type, match=err_msg): _check_psd_eigenvalues(lambdas)
def _fit_transform(self, K): """ Fit's using kernel K""" # center kernel K = self._centerer.fit_transform(K) if self.n_components is None: n_components = K.shape[0] else: n_components = min(K.shape[0], self.n_components) # compute eigenvectors if self.eigen_solver == 'auto': if K.shape[0] > 200 and n_components < 10: eigen_solver = 'arpack' else: eigen_solver = 'dense' else: eigen_solver = self.eigen_solver if eigen_solver == 'dense': self.lambdas_, self.alphas_ = linalg.eigh( K, eigvals=(K.shape[0] - n_components, K.shape[0] - 1)) elif eigen_solver == 'arpack': random_state = check_random_state(self.random_state) # initialize with [-1,1] as in ARPACK v0 = random_state.uniform(-1, 1, K.shape[0]) self.lambdas_, self.alphas_ = eigsh(K, n_components, which="LA", tol=self.tol, maxiter=self.max_iter, v0=v0) # make sure that the eigenvalues are ok and fix numerical issues self.lambdas_ = _check_psd_eigenvalues(self.lambdas_, enable_warnings=False) # flip eigenvectors' sign to enforce deterministic output self.alphas_, _ = svd_flip(self.alphas_, np.empty_like(self.alphas_).T) # sort eigenvectors in descending order indices = self.lambdas_.argsort()[::-1] self.lambdas_ = self.lambdas_[indices] self.alphas_ = self.alphas_[:, indices] # remove eigenvectors with a zero eigenvalue (null space) if required if self.remove_zero_eig or self.n_components is None: self.alphas_ = self.alphas_[:, self.lambdas_ > 0] self.lambdas_ = self.lambdas_[self.lambdas_ > 0] # Maintenance note on Eigenvectors normalization # ---------------------------------------------- # there is a link between # the eigenvectors of K=Phi(X)'Phi(X) and the ones of Phi(X)Phi(X)' # if v is an eigenvector of K # then Phi(X)v is an eigenvector of Phi(X)Phi(X)' # if u is an eigenvector of Phi(X)Phi(X)' # then Phi(X)'u is an eigenvector of Phi(X)Phi(X)' # # At this stage our self.alphas_ (the v) have norm 1, we need to scale # them so that eigenvectors in kernel feature space (the u) have norm=1 # instead # # We COULD scale them here: # self.alphas_ = self.alphas_ / np.sqrt(self.lambdas_) # # But choose to perform that LATER when needed, in `fit()` and in # `transform()`. return K