Principal component analysis in Python takes three lines with scikit-learn: scale your features, create PCA(n_components=2), and call fit_transform(). You get a smaller set of new columns that keep most of the information:
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
X_2d = PCA(n_components=2).fit_transform(StandardScaler().fit_transform(X))
I tested this on Python 3.12.5 with scikit-learn 1.9.1, using the wine and iris datasets that ship with scikit-learn, so you won’t need to download anything.
We’ll run a basic PCA, see why scaling matters, pick the number of components, plot the result, read the loadings, and use PCA inside a model pipeline.
How to do PCA in Python with scikit-learn
The wine dataset has 178 wines measured on 13 chemical features. PCA squeezes those 13 columns into 2 new ones, called principal components:
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
X, y = load_wine(return_X_y=True)
print("original shape:", X.shape)
X_scaled = StandardScaler().fit_transform(X)
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X_scaled)
print("reduced shape: ", X_2d.shape)
print("variance kept by each component:", pca.explained_variance_ratio_.round(3))
print(f"total kept: {pca.explained_variance_ratio_.sum():.1%}")
print("first wine as 2 numbers:", X_2d[0].round(3))
Output:
original shape: (178, 13)
reduced shape: (178, 2)
variance kept by each component: [0.362 0.192]
total kept: 55.4%
first wine as 2 numbers: [3.317 1.443]

Each component is a weighted mix of the original features. The first one points in the direction where the data varies most, and the second captures the most of what’s left.
If scikit-learn isn’t installed yet, run python -m pip install scikit-learn first; it brings NumPy and SciPy with it.
Why you should scale data before PCA
PCA chases variance, so a feature measured in big numbers drowns out the rest. In the wine data, proline goes past 1,600 while hue stays under 2:
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
X, _ = load_wine(return_X_y=True)
raw = PCA(n_components=2).fit(X)
scaled = PCA(n_components=2).fit(StandardScaler().fit_transform(X))
print("without scaling:", raw.explained_variance_ratio_.round(3))
print("with scaling: ", scaled.explained_variance_ratio_.round(3))
print("feature ranges: proline up to", X[:, 12].max(), "| hue up to", X[:, 10].max())
Output:
without scaling: [0.998 0.002]
with scaling: [0.362 0.192]
feature ranges: proline up to 1680.0 | hue up to 1.71

StandardScaler gives every feature a mean of 0 and a standard deviation of 1. Scikit-learn’s PCA centers the data, but it doesn’t scale it for you.
How many principal components should you keep?
Look at the cumulative explained variance and stop when it’s high enough for your job. Or pass a fraction like 0.95 and let scikit-learn count for you:
import numpy as np
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
X_scaled = StandardScaler().fit_transform(load_wine().data)
full = PCA().fit(X_scaled)
cumulative = np.cumsum(full.explained_variance_ratio_)
for k, share in enumerate(cumulative[:8], start=1):
print(f"{k} components -> {share:.1%}")
pca95 = PCA(n_components=0.95).fit(X_scaled)
print("components needed for 95%:", pca95.n_components_)
Output:
1 components -> 36.2%
2 components -> 55.4%
3 components -> 66.5%
4 components -> 73.6%
5 components -> 80.2%
6 components -> 85.1%
7 components -> 89.3%
8 components -> 92.0%
components needed for 95%: 10

For charts, 2 or 3 components is the norm. For speeding up a model, 90% to 95% of the variance is a common target.
Plotting PCA results in Python
Reducing to two components means you can draw data that had four or more dimensions. Here are the iris flowers, colored by species:
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
iris = load_iris()
X_2d = PCA(n_components=2).fit_transform(StandardScaler().fit_transform(iris.data))
fig, ax = plt.subplots(figsize=(7, 5))
for label, name in enumerate(iris.target_names):
pts = X_2d[iris.target == label]
ax.scatter(pts[:, 0], pts[:, 1], label=name, alpha=0.8)
ax.set_xlabel("Principal component 1")
ax.set_ylabel("Principal component 2")
ax.set_title("Iris flowers after PCA (4 features -> 2)")
ax.legend()
plt.tight_layout()
plt.show()

If you’re new to matplotlib, the for loop here just draws one species at a time so each gets its own color and legend entry.
Reading PCA loadings
pca.components_ holds the weight of each original feature in each component. Putting it in a pandas DataFrame makes it readable:
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
iris = load_iris()
pca = PCA(n_components=2).fit(StandardScaler().fit_transform(iris.data))
loadings = pd.DataFrame(pca.components_.T, index=iris.feature_names, columns=["PC1", "PC2"])
print(loadings.round(3))
Output:
PC1 PC2
sepal length (cm) 0.521 0.377
sepal width (cm) -0.269 0.923
petal length (cm) 0.580 0.024
petal width (cm) 0.565 0.067
Petal length, petal width and sepal length all load heavily on PC1, so it’s roughly a “flower size” axis. PC2 is mostly sepal width.
Using PCA in a scikit-learn pipeline
PCA is often a preprocessing step before a model. A pipeline keeps scaling and PCA inside cross-validation, so test data never leaks into the fit:
from sklearn.datasets import load_wine
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = load_wine(return_X_y=True)
for k in (2, 5, 13):
model = make_pipeline(StandardScaler(), PCA(n_components=k), LogisticRegression(max_iter=1000))
scores = cross_val_score(model, X, y, cv=5)
print(f"{k:>2} components: accuracy {scores.mean():.3f}")
Output:
2 components: accuracy 0.955
5 components: accuracy 0.978
13 components: accuracy 0.983

On wide datasets with hundreds of features, this is where PCA really pays off: faster training with little or no loss in accuracy.
PCA in Python: key attributes
| Attribute or argument | What it gives you |
|---|---|
n_components=2 | Keep exactly 2 components |
n_components=0.95 | Keep enough components for 95% of the variance |
explained_variance_ratio_ | Share of variance per component |
components_ | Loadings: feature weights per component |
inverse_transform() | Map reduced data back to the original features (approximately) |
More machine learning in Python to explore next:
- Python libraries for machine learning
- Best Python libraries for data science
- R vs Python for data science
- List of lists in Python
Frequently asked questions
How do I do principal component analysis in Python?
Scale the data with StandardScaler, then use PCA(n_components=k).fit_transform(X_scaled) from scikit-learn.
Do I need to standardize data before PCA?
Usually, yes. Without scaling, features with large units dominate the components.
What does explained_variance_ratio_ mean?
It’s the share of the total variance each component captures. Add them up to see how much information you kept.
How do I choose n_components?
Plot the cumulative explained variance, or pass a fraction such as 0.95 to keep 95% of it.
Can I use PCA without scikit-learn?
Yes. NumPy’s np.linalg.svd on centered data gives the same components, but scikit-learn is easier.
Where is the full PCA reference?
Every parameter is listed in the scikit-learn PCA documentation.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn