1
$\begingroup$

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
$\endgroup$
  • 1
    $\begingroup$ I see your eigenvectors are normalized so the elements add up to 1. I don't know if that is OK, I suspect that portfolio_ret = np.dot(ret,eVec.T) does not give the right values in this case, the outputs may be scaled incorrectly. Don't the eigenvalues matter in this calculation? The scale of the eigenvectors is arbitrary, with many scalings possible. $\endgroup$ – noob2 Apr 21 at 12:20
  • 2
    $\begingroup$ Also, you normalise your eigenvectors by dividing by the sum. Shouldn't they be normalised by dividing by sum of squares? $\endgroup$ – Kermittfrog Apr 21 at 12:41
  • $\begingroup$ Put differently: The eigenvector normalisation is usually an output of your PCA. Finally, eigenvectors and eigenvalues must, of course, be able to recover your initial covariance / correlation matrix. $\endgroup$ – Kermittfrog Apr 21 at 12:52
  • 1
    $\begingroup$ I agree that there are two potential issues: 1. maybe weights are correctly evaluated, but statement in the question is just not true in general 2. scaling of the weights should be done differently. However I believe that since they are weights in portfolio that should sum up to 1. $\endgroup$ – mfolusiak Apr 21 at 20:39
  • $\begingroup$ I think if you added those weights (your terminology), then you'd arrive at a total of N * 100% investment, with N the number of eigen components, no? $\endgroup$ – Kermittfrog Apr 22 at 6:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.