2013-09-01 00:26:17 +08:00
|
|
|
"""
|
2015-03-31 04:17:39 +08:00
|
|
|
===============================================================
|
|
|
|
|
Model selection with Probabilistic PCA and Factor Analysis (FA)
|
|
|
|
|
===============================================================
|
2013-09-01 00:26:17 +08:00
|
|
|
|
|
|
|
|
Probabilistic PCA and Factor Analysis are probabilistic models.
|
|
|
|
|
The consequence is that the likelihood of new data can be used
|
2013-10-25 20:38:44 +08:00
|
|
|
for model selection and covariance estimation.
|
|
|
|
|
Here we compare PCA and FA with cross-validation on low rank data corrupted
|
|
|
|
|
with homoscedastic noise (noise variance
|
2013-09-01 00:26:17 +08:00
|
|
|
is the same for each feature) or heteroscedastic noise (noise variance
|
2013-10-25 20:38:44 +08:00
|
|
|
is the different for each feature). In a second step we compare the model
|
|
|
|
|
likelihood to the likelihoods obtained from shrinkage covariance estimators.
|
2013-09-01 00:26:17 +08:00
|
|
|
|
|
|
|
|
One can observe that with homoscedastic noise both FA and PCA succeed
|
|
|
|
|
in recovering the size of the low rank subspace. The likelihood with PCA
|
2013-09-01 21:08:46 +08:00
|
|
|
is higher than FA in this case. However PCA fails and overestimates
|
2013-10-25 20:38:44 +08:00
|
|
|
the rank when heteroscedastic noise is present. Under appropriate
|
2013-10-25 20:49:40 +08:00
|
|
|
circumstances the low rank models are more likely than shrinkage models.
|
2013-10-25 20:38:44 +08:00
|
|
|
|
|
|
|
|
The automatic estimation from
|
2013-09-01 00:26:17 +08:00
|
|
|
Automatic Choice of Dimensionality for PCA. NIPS 2000: 598-604
|
|
|
|
|
by Thomas P. Minka is also compared.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Authors: Alexandre Gramfort
|
2013-10-25 20:38:44 +08:00
|
|
|
# Denis A. Engemann
|
2013-09-01 00:26:17 +08:00
|
|
|
# License: BSD 3 clause
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
2014-05-15 04:31:03 +08:00
|
|
|
import matplotlib.pyplot as plt
|
2013-09-01 00:26:17 +08:00
|
|
|
from scipy import linalg
|
|
|
|
|
|
|
|
|
|
from sklearn.decomposition import PCA, FactorAnalysis
|
2013-10-25 20:38:44 +08:00
|
|
|
from sklearn.covariance import ShrunkCovariance, LedoitWolf
|
2015-09-11 02:26:39 +08:00
|
|
|
from sklearn.model_selection import cross_val_score
|
|
|
|
|
from sklearn.model_selection import GridSearchCV
|
2013-09-01 00:26:17 +08:00
|
|
|
|
2015-09-21 15:40:28 +08:00
|
|
|
print(__doc__)
|
|
|
|
|
|
2017-06-20 20:48:57 +08:00
|
|
|
# #############################################################################
|
2013-09-01 00:26:17 +08:00
|
|
|
# Create the data
|
|
|
|
|
|
|
|
|
|
n_samples, n_features, rank = 1000, 50, 10
|
|
|
|
|
sigma = 1.
|
|
|
|
|
rng = np.random.RandomState(42)
|
|
|
|
|
U, _, _ = linalg.svd(rng.randn(n_features, n_features))
|
|
|
|
|
X = np.dot(rng.randn(n_samples, rank), U[:, :rank].T)
|
|
|
|
|
|
|
|
|
|
# Adding homoscedastic noise
|
|
|
|
|
X_homo = X + sigma * rng.randn(n_samples, n_features)
|
|
|
|
|
|
|
|
|
|
# Adding heteroscedastic noise
|
|
|
|
|
sigmas = sigma * rng.rand(n_features) + sigma / 2.
|
|
|
|
|
X_hetero = X + rng.randn(n_samples, n_features) * sigmas
|
|
|
|
|
|
2017-06-20 20:48:57 +08:00
|
|
|
# #############################################################################
|
2013-09-01 00:26:17 +08:00
|
|
|
# Fit the models
|
|
|
|
|
|
|
|
|
|
n_components = np.arange(0, n_features, 5) # options for n_components
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def compute_scores(X):
|
2015-09-21 15:40:28 +08:00
|
|
|
pca = PCA(svd_solver='full')
|
2013-09-01 00:26:17 +08:00
|
|
|
fa = FactorAnalysis()
|
|
|
|
|
|
|
|
|
|
pca_scores, fa_scores = [], []
|
|
|
|
|
for n in n_components:
|
|
|
|
|
pca.n_components = n
|
|
|
|
|
fa.n_components = n
|
2018-08-21 03:22:42 +08:00
|
|
|
pca_scores.append(np.mean(cross_val_score(pca, X, cv=5)))
|
|
|
|
|
fa_scores.append(np.mean(cross_val_score(fa, X, cv=5)))
|
2013-09-01 00:26:17 +08:00
|
|
|
|
|
|
|
|
return pca_scores, fa_scores
|
2013-10-25 23:49:06 +08:00
|
|
|
|
|
|
|
|
|
2013-10-25 20:38:44 +08:00
|
|
|
def shrunk_cov_score(X):
|
2013-10-25 23:49:06 +08:00
|
|
|
shrinkages = np.logspace(-2, 0, 30)
|
2018-08-21 03:22:42 +08:00
|
|
|
cv = GridSearchCV(ShrunkCovariance(), {'shrinkage': shrinkages}, cv=5)
|
|
|
|
|
return np.mean(cross_val_score(cv.fit(X).best_estimator_, X, cv=5))
|
2013-10-25 20:38:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def lw_score(X):
|
2018-08-21 03:22:42 +08:00
|
|
|
return np.mean(cross_val_score(LedoitWolf(), X, cv=5))
|
2013-10-25 23:49:06 +08:00
|
|
|
|
|
|
|
|
|
2013-09-06 14:51:06 +08:00
|
|
|
for X, title in [(X_homo, 'Homoscedastic Noise'),
|
|
|
|
|
(X_hetero, 'Heteroscedastic Noise')]:
|
2013-09-01 00:26:17 +08:00
|
|
|
pca_scores, fa_scores = compute_scores(X)
|
|
|
|
|
n_components_pca = n_components[np.argmax(pca_scores)]
|
|
|
|
|
n_components_fa = n_components[np.argmax(fa_scores)]
|
|
|
|
|
|
2015-09-21 15:40:28 +08:00
|
|
|
pca = PCA(svd_solver='full', n_components='mle')
|
2013-09-01 00:26:17 +08:00
|
|
|
pca.fit(X)
|
|
|
|
|
n_components_pca_mle = pca.n_components_
|
2013-10-25 23:49:06 +08:00
|
|
|
|
2013-09-01 00:26:17 +08:00
|
|
|
print("best n_components by PCA CV = %d" % n_components_pca)
|
|
|
|
|
print("best n_components by FactorAnalysis CV = %d" % n_components_fa)
|
|
|
|
|
print("best n_components by PCA MLE = %d" % n_components_pca_mle)
|
|
|
|
|
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.figure()
|
|
|
|
|
plt.plot(n_components, pca_scores, 'b', label='PCA scores')
|
|
|
|
|
plt.plot(n_components, fa_scores, 'r', label='FA scores')
|
|
|
|
|
plt.axvline(rank, color='g', label='TRUTH: %d' % rank, linestyle='-')
|
|
|
|
|
plt.axvline(n_components_pca, color='b',
|
2014-05-15 10:35:13 +08:00
|
|
|
label='PCA CV: %d' % n_components_pca, linestyle='--')
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.axvline(n_components_fa, color='r',
|
2015-09-21 15:40:28 +08:00
|
|
|
label='FactorAnalysis CV: %d' % n_components_fa,
|
|
|
|
|
linestyle='--')
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.axvline(n_components_pca_mle, color='k',
|
2014-05-15 10:35:13 +08:00
|
|
|
label='PCA MLE: %d' % n_components_pca_mle, linestyle='--')
|
2013-10-25 20:38:44 +08:00
|
|
|
|
|
|
|
|
# compare with other covariance estimators
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.axhline(shrunk_cov_score(X), color='violet',
|
2014-05-15 10:35:13 +08:00
|
|
|
label='Shrunk Covariance MLE', linestyle='-.')
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.axhline(lw_score(X), color='orange',
|
2014-05-15 10:35:13 +08:00
|
|
|
label='LedoitWolf MLE' % n_components_pca_mle, linestyle='-.')
|
2013-10-25 23:49:06 +08:00
|
|
|
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.xlabel('nb of components')
|
|
|
|
|
plt.ylabel('CV scores')
|
|
|
|
|
plt.legend(loc='lower right')
|
|
|
|
|
plt.title(title)
|
2013-09-06 03:50:28 +08:00
|
|
|
|
2014-05-15 04:31:03 +08:00
|
|
|
plt.show()
|