Skip to content

Instantly share code, notes, and snippets.

@nicklatin
Last active November 12, 2022 15:45
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nicklatin/f60268d64ab9e4e5a87ec16127d53467 to your computer and use it in GitHub Desktop.
Save nicklatin/f60268d64ab9e4e5a87ec16127d53467 to your computer and use it in GitHub Desktop.
Klein and Chow (2013) propose an optimal simultaneous orthogonal transformation of factors, following the so-called symmetric procedure of Schweinler and Wigner (1970) and Löwdin (1970): https://www.sciencedirect.com/science/article/abs/pii/S1062976913000185. The data transformation allows the identification of the underlying uncorrelated compon…
# orthogonalization of correlated factors in a multifactor model
def orthogonalize_factors(factors_df, output_format='df'):
"""
As described by Klein and Chow (2013) in Orthogonalized Factors and Systematic Risk Decompositions:
https://www.sciencedirect.com/science/article/abs/pii/S1062976913000185
They propose an optimal simultaneous orthogonal transformation of factors, following the so-called symmetric procedure
of Schweinler and Wigner (1970) and Löwdin (1970). The data transformation allows the identification of the underlying uncorrelated
components of common factors without changing their correlation with the original factors. It also facilitates the systematic risk
decomposition by disentangling the coefficient of determination (R²) based on factors' volatilities, which makes it easier to distinguish
the marginal risk contribution of each common risk factor to asset returns.
Parameters
----------
factors_df: DataFrame
DataFrame with DatetimeIndex and facotrs to orthogonalize
output_format: str,{'array', 'df'}, defaul 'df'
Select the output format, numpy.array or DataFrame.
Returns
-------
F_orth: numpy.array or DataFrame
numpy.array of orthogonalized factors or DataFrame with DatetimeIndex and orthogonalized factors.
"""
# before orthogonalization, factors should be normalized
# if factors are in a DataFrame, convert to numpy for speed and ease of computation
if isinstance(factors_df, pd.DataFrame):
F = factors_df.to_numpy()
# compute cov matrix
M = np.cov(F.T, bias=False)
# factorize cov matrix M
u, s, vh = np.linalg.svd(M)
# solve for symmetric matrix
S = u @ np.diag(s**(-0.5)) @ vh
# rescale symmetric matrix to original variances
S_rs = S @ (np.diag(np.sqrt(M)) * np.eye(S.shape[0], S.shape[1]))
# convert to orthogonalized matrix
F_orth = F @ S_rs
# if selected, convert output format back to dataframe
if output_format == 'df':
F_orth = pd.DataFrame(F_orth, index=factors_df.index, columns=factors_df.columns)
return F_orth
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment