Principal Component Analysis and Factor Extraction › PCA Applied to Equity Returns

Michael BrenndoerferDecember 12, 20256 min read
Quantitative FinanceAll chapters
Part 8 of 15Econometrics and Statistical Modeling
Chapter 44Principal Component Analysis and Factor Extraction › PCA Applied to Equity Returns
Reading section 6 of 13 · PCA Applied to Equity Returns · 6 minSection 6 of 13 · 6 min

Book contents

Section 6 of 13 · 6 min read

Principal Component Analysis and Factor Extraction › PCA Applied to Equity ReturnsOne section · Sections in this chapter6 / 13 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Equity returns present a more challenging application of PCA. Unlike yield curves, where maturities have a natural ordering and the factor structure is highly regular, equity returns exhibit a messier factor structure with lower variance concentration in the leading components.

Analyzing Sector Returns

Let's apply PCA to a set of simulated sector returns:

In[22]:
Code
import numpy as np
import pandas as pd

np.random.seed(456)

# Define sectors
sectors = [
    "Technology",
    "Healthcare",
    "Financials",
    "Consumer",
    "Industrials",
    "Energy",
    "Materials",
    "Utilities",
    "Real Estate",
    "Communications",
]
n_sectors = len(sectors)
n_days = 500

# Simulate factor structure:
# Factor 1: Market factor (affects all sectors)
# Factor 2: Growth vs Value (Tech/Healthcare vs Financials/Energy)
# Factor 3: Interest rate sensitivity (Utilities/Real Estate vs others)

market_factor = np.random.randn(n_days)
growth_value_factor = np.random.randn(n_days)
rate_sensitivity_factor = np.random.randn(n_days)

# Define factor exposures (betas) for each sector
market_betas = np.array([1.2, 0.9, 1.1, 1.0, 1.05, 1.3, 1.1, 0.5, 0.8, 1.15])
gv_betas = np.array([0.8, 0.5, -0.6, 0.2, 0.0, -0.7, -0.3, -0.2, 0.1, 0.4])
rate_betas = np.array([-0.2, 0.1, 0.4, 0.0, 0.1, 0.2, 0.1, 0.7, 0.6, -0.1])

# Generate returns
returns = np.zeros((n_days, n_sectors))
for i in range(n_sectors):
    returns[:, i] = (
        market_betas[i] * market_factor * 0.01
        + gv_betas[i] * growth_value_factor * 0.005
        + rate_betas[i] * rate_sensitivity_factor * 0.004
        + np.random.randn(n_days) * 0.008
    )  # Idiosyncratic

returns_df = pd.DataFrame(returns, columns=sectors)
In[23]:
Code
# Apply PCA to sector returns
returns_centered = returns - returns.mean(axis=0)
cov_returns = np.cov(returns_centered, rowvar=False)

eigenvalues_ret, eigenvectors_ret = np.linalg.eigh(cov_returns)
sort_idx = np.argsort(eigenvalues_ret)[::-1]
eigenvalues_ret = eigenvalues_ret[sort_idx]
eigenvectors_ret = eigenvectors_ret[:, sort_idx]

# Calculate variance metrics
total_var_ret = eigenvalues_ret.sum()
explained_pct_ret = 100 * eigenvalues_ret / total_var_ret
cumulative_pct_ret = np.cumsum(explained_pct_ret)
Out[24]:
Console
Variance Explained by Principal Components (Sector Returns):
-------------------------------------------------------
PC1:  64.47%  (Cumulative:  64.47%)
PC2:   6.36%  (Cumulative:  70.83%)
PC3:   4.14%  (Cumulative:  74.97%)
PC4:   4.08%  (Cumulative:  79.05%)
PC5:   3.85%  (Cumulative:  82.90%)

Unlike yield curves, equity returns require more components to achieve high variance explanation. The first component (the market factor) explains a smaller fraction of total variance because idiosyncratic risk is more significant for individual stocks and sectors.

Out[25]:
Visualization
Grouped bar chart comparing individual variance explained for yield curves and equity sectors across six principal components.
Individual component variance for yield curves versus equity sectors. Yield curves show extreme concentration in the first component, while equity sectors distribute variance more evenly across components.
Line plot comparing cumulative variance explained for yield curves versus equity sectors, showing faster convergence for yield curves.
Cumulative variance explained for yield curves versus equity sectors. Yield curves reach high cumulative thresholds in far fewer components than equity returns, which reflects the stronger common factor structure in interest rates.
Out[26]:
Visualization
Horizontal bar chart of PC1 loadings for ten sectors, all bars pointing in the same positive direction.
PC1 loadings for sector returns. All sectors have positive loadings of similar magnitude, identifying this component as the broad market factor.
Horizontal bar chart of PC2 loadings for ten sectors, with mixed positive and negative bars separating growth and value sectors.
PC2 loadings for sector returns. The alternating positive and negative values separate sectors along a growth versus value dimension, with Technology and Healthcare on one side and Financials and Energy on the other.
Horizontal bar chart of PC3 loadings for ten sectors, which shows high loadings for Utilities and Real Estate.
PC3 loadings for sector returns. High loadings on Utilities and Real Estate relative to cyclical sectors suggest this component captures interest rate sensitivity.

The loading patterns reveal the underlying factor structure:

  • PC1: All positive loadings indicate a common market factor. The relative magnitudes reflect each sector's market beta.
  • PC2: The pattern of positive and negative loadings separates sectors along a dimension that might correspond to growth versus value characteristics.
  • PC3: Further differentiation, potentially capturing interest rate sensitivity given the high loadings on Utilities and Real Estate.