Why PCA Components Do Not Directly Rank Portfolio Volatility
Summary
The document presents a question about interpreting principal components as portfolios of securities. The questioner applies PCA to a matrix of stock returns, rescales each component’s weights so they sum to one, and then compares the resulting portfolio return standard deviations with PCA’s explained variances. The reported component portfolio volatilities do not follow the eigenvalue ordering, prompting confusion about whether the first component maximizes portfolio risk.
The example exposes a mismatch between PCA’s mathematical components and the portfolios created by the author’s weight adjustment. PCA orders orthogonal directions by variance under its fitted data representation; modifying component weights to force them to sum to one changes those directions and their variance properties. The document includes code and sample output but no reply resolving the issue, so it does not establish a complete implementation procedure or address other portfolio constraints.
Key ideas
- PCA ranks its fitted directions by explained variance.
- The example rescales component weights to sum to one before calculating portfolio returns.
- Rescaling eigenvectors changes their variance properties and can break the original PCA ordering.
- The document provides a numerical example but no answer or validated portfolio construction method.
Tags
Full text
# Why doesn't the first principal component maximize the standard deviation of returns
# Why doesn't the first principal component maximize the standard deviation of returns
I am trying to apply PCA to portfolio of securities. My understanding is that the first principal component can be used to evaluate weights for portfolio of maximum variance and each next principal portfolio would have lower variance of returns. I implemented the following Python code:
```
import pandas_datareader as web
import sklearn.decomposition
import pandas as pd
import numpy as np
start="1/1/2016"
end="1/1/2020"
engine = 'stooq'
MSFT = web.DataReader('MSFT.US',engine,start=start,end=end)[::-1]
AAPL = web.DataReader('AAPL.US',engine,start=start,end=end)[::-1]
AMZN = web.DataReader('AMZN.US',engine,start=start,end=end)[::-1]
GOOG = web.DataReader('QQQ.US',engine,start=start,end=end)[::-1]
stocks = [MSFT,AAPL,AMZN,GOOG]
snames = ['MSFT','AAPL','AMZN','QQQ']
# build returns
for sname, stock in zip(snames, stocks):
stock['ret']=stock.Close/stock.Close.shift(1)-1
stock.dropna(inplace=True)
ret = pd.DataFrame()
ret = pd.concat([stock.iloc[:,-1] for stock in stocks],axis=1)
ret.columns = snames
# PCA decomposition
sklearn_pca = sklearn.decomposition.PCA()
sklearn_pca.fit_transform(ret)
eVec = pd.DataFrame(sklearn_pca.components_)
for i in range(eVec.shape[0]):
eVec.iloc[i,:] /= eVec.iloc[i,:].sum()
# Print
print("Eigenvectors: ")
print (eVec)
print
portfolio_ret = np.dot(ret,eVec.T)
print("Explained variance: ",sklearn_pca.explained_variance_)
print("std dev comparison:")
for i in range(eVec.shape[0]):
print("std in principal portfolio: "+str(i)+" ",portfolio_ret[:,i].std())
```
I get the following output from my code:
```
Eigenvectors:
0 1 2 3
0 0.261228 0.257406 0.268283 0.213082
1 1.498299 12.356333 -15.088625 2.233993
2 34.957326 -23.782872 -15.253020 5.078566
3 -2.170364 -1.577372 -0.700586 5.448321
Explained variance: [9.10267304e-04 1.57918603e-04 8.46751096e-05 1.54724748e-05]
std dev comparison:
std in principal portfolio: 0 0.015135846955727339
std in principal portfolio: 1 0.24730052498285351
std in principal portfolio: 2 0.41607045895649003
std in principal portfolio: 3 0.024037508433806268
```
From the above output `Explained variance` indicates that eigenvectors are listed in descending order of variance. The PCA analysis seems to be correct.
Above I calculated returns for principal portfolios corresponding to eigenvectors. What I don't understand is why standard deviations of returns are the lowest for the principal portfolio corresponding to the first (0th in Python's convention) eigenvector (`0.015` < `0.024` < `0.247` < `0.416`).
I would expect it to be the highest as this should be portfolio maximizing the std, variance and thus the risk.
EDIT: It was suggested in comments that the PCA part could be split into atomic operations for better understanding. Here is the equivalent code for evaluation of eigenvalues and eigenvectors before scaling:
```
ret_dm = ret - ret.mean(axis=0) # de-mean
cov = np.cov(ret_dm.T) # compute the covariance matrix
eVal, eVec = np.linalg.eig(cov)
# sort vectors and values by descending eigenvalue
indices = eVal.argsort()[::-1] # sort args descending
eVal, eVec = eVal[indices], eVec[:,indices]
# transform to row eigenvectors
eVec = eVec.T
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.