Principal component analysis trades exact reconstruction for a smaller set of orthogonal features. scikit-learn can select the minimum number of components that reaches a retained-variance target, so the reduced width follows an explicit information rule instead of an arbitrary column count.
The digits dataset contains 1,797 samples with 64 pixel features whose active standard deviations span different scales. PCA centers input values but does not scale each feature, so StandardScaler gives active features unit variance before the decomposition.
A 90% retained-variance rule selects 31 components for the scaled digits matrix and retains about 90.05% of its variance. Applying inverse_transform() exposes the tradeoff as reconstruction error in standardized feature units; a downstream supervised model still needs scaling and PCA fitted only on training rows.
import numpy as np from sklearn.datasets import load_digits from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler X, _ = load_digits(return_X_y=True) active_std = X.std(axis=0) active_std = active_std[active_std > 0] print(f"original shape: {X.shape}") print( "raw active-feature std range: " f"{active_std.min():.4f} to {active_std.max():.4f}" )
Constant pixel columns are excluded only from the spread calculation; they remain in X so the PCA input keeps its original 64-column shape.
$ python3 reduce_dimensions_pca.py original shape: (1797, 64) raw active-feature std range: 0.0236 to 6.5361
scaler = StandardScaler() X_scaled = scaler.fit_transform(X)
scaled_active_std = X_scaled.std(axis=0) scaled_active_std = scaled_active_std[scaled_active_std > 0]
target_variance = 0.90 pca = PCA(n_components=target_variance, svd_solver="full")
With svd_solver=“full”, a float between 0 and 1 makes PCA select the smallest component count whose cumulative explained variance exceeds that value.
X_reduced = pca.fit_transform(X_scaled)
X_reconstructed = pca.inverse_transform(X_reduced)
retained_variance = pca.explained_variance_ratio_.sum()
reconstruction_rmse = np.sqrt(np.mean((X_scaled - X_reconstructed) ** 2))
if X_reduced.shape[0] != X.shape[0]: raise RuntimeError("PCA changed the sample count") if X_reduced.shape[1] >= X.shape[1]: raise RuntimeError("PCA did not reduce the feature count") if retained_variance < target_variance: raise RuntimeError("PCA missed the retained-variance target") if not np.isfinite(reconstruction_rmse): raise RuntimeError("PCA reconstruction error is not finite")
print( "scaled active-feature std range: " f"{scaled_active_std.min():.4f} to {scaled_active_std.max():.4f}" ) print(f"variance target: {target_variance:.4f}") print(f"selected components: {pca.n_components_}") print(f"retained variance: {retained_variance:.4f}") print(f"reduced shape: {X_reduced.shape}") print(f"reconstruction RMSE: {reconstruction_rmse:.4f}")
$ python3 reduce_dimensions_pca.py original shape: (1797, 64) raw active-feature std range: 0.0236 to 6.5361 scaled active-feature std range: 1.0000 to 1.0000 variance target: 0.9000 selected components: 31 retained variance: 0.9005 reduced shape: (1797, 31) reconstruction RMSE: 0.3080
The fitted model retained 0.9005, so 31 components satisfy the selected rule while reducing the original 64-feature width.
A smaller reconstruction error means the retained components reproduce the scaled matrix more closely. Reconstruction error does not measure classification accuracy; a downstream estimator needs its own evaluation.