CHAPTER 05/ 45
: Linear Algebra, Portfolio Objects and Risk
Spine: matrices let you calculate across assets; shape, orientation and sample meaning give those calculations their financial interpretation. Prerequisites: Chapter 2's arrays and indexing, and elementary algebra. Chapter 6 develops probability and covariance formally; its current Chinese edition remains the reference until a later English batch. Here we begin with a supplied covariance matrix. Principal component analysis (PCA) follows Chapter 3's information-time contract.
1. Learning Objectives
Write holdings as vectors and multi-asset returns as matrices, explaining each axis before computing. Read matrix multiplication, transpose, rank, basis and orthogonality, and recognize singular or ill-conditioned systems.
For risk, derive portfolio variance from a two-asset expansion and assess whether a candidate matrix can be a covariance matrix. For dimension reduction, read singular value decomposition (SVD) and PCA: training centering, directions, scores, explained variance and the exclusion of future rows from fitting.
You need not master every abstract vector-space theorem yet. Check dimensions, calculate small examples and understand the conditions before verifying them in code. Chapter 8 develops regression; Chapters 9 and 20 use these objects in portfolio problems. Chapter 20's English edition is already available; other later chapters remain Chinese pending translation.
2. Why Quantitative Research Needs Linear Algebra
With one stock you can calculate each number. With 500 stocks, a date has 500 returns, 500 weights, many exposure coordinates and a 500-by-500 risk matrix. Explicit shapes make the calculations manageable and expose missing terms or incorrect axis order.
A solver does not know that monthly covariance was mixed with annual expected returns, or that column 17 now represents another security. Arrays retain positions after labels are removed. Data engineering establishes identities and available times; linear algebra then computes under those contracts.
We use a return panel, a weight vector and a covariance matrix throughout. Chapter 2 introduced broadcasting; here matrix products explain the resulting portfolio returns. Chapter 21 later addresses estimation error and investment constraints.
3. Intuition
A weight vector is a recipe; a contemporaneous return vector records how each ingredient changes over one holding interval. Their inner product multiplies paired entries and adds them.
A matrix can map weights to returns by date, or holdings to industry and style exposures. A return panel and a risk matrix are both two-dimensional but have different axes.
Two volatile assets can move imperfectly together. Risk depends on both individual movement and joint movement. An eigenvector keeps its direction under a matrix transformation; an eigenvalue measures the scaling in that direction. For a risk matrix, these directions carry particular variances.
PCA rotates coordinates toward the greatest sample variation, then the greatest remaining orthogonal variation. Historical variance concentration alone does not identify a useful forecast or investment direction.
4. Mathematical Foundations
4.1 Vectors, Length and Transpose
Use column vectors:
Weights and same-interval simple returns are dimensionless; each vector is
is a scalar. Interpreting it as realized portfolio return also requires actual weights held at the interval's start.
For
Length is not gross exposure. Gross exposure uses the L1 norm
At start-of-interval weights
This is .8%, a scalar. Choosing those weights after seeing the interval's returns would introduce future information.
4.2 Return Panels and Matrix Multiplication
Let
This is a specified-weight mapping, not an automatic rebalancing backtest. Drifting positions need the actual interval weights; Chapter 29 later develops the ledger.
For
The shared axis
A fixed matrix maps
The first column is the image of
Calculate every output cell:
Each entry is a row of the left matrix dotted with a column of the right. In
The elementwise, or Hadamard, product has @ multiplies matrices and * multiplies elements. Both can return plausible values; the operation's purpose and axes distinguish them.
4.3 Linear Combinations, Span, Basis and Rank
A linear combination of
A basis is independent and spans the chosen space. The standard plane basis
For
Rank equals both column-space and row-space dimension. A hundred stored factors can offer far fewer independent directions if many are linear combinations. The null space is
4.4 Orthogonality and Projection
Nonzero vectors with
Project
For unit
For
4.5 Linear Systems, Inverses and Conditioning
In
Numerically prefer solve(A,b) over constructing the entire inverse for one right-hand side. Check the residual
Invertibility does not imply stability. The Euclidean condition number is
where the norm is induced by Euclidean vector length and the
5. Definitions
5.1 Symmetry and Definiteness
5.2 Covariance Matrices
Begin with a supplied risk table ordered A, B on both axes:
Diagonal entries are individual variances, off-diagonals describe joint movement. You can compute with the table before deriving probability theory.
For a same-interval return vector
Volatility
5.3 Eigenvalues and Spectral Decomposition
A nonzero
Columns of eigh returns column eigenvectors and uses one triangle, so check symmetry independently.
5.4 SVD and PCA
Every real
For the reduced computational form,
PCA finds orthogonal directions of maximum projected training variance after centering. Directions are columns of
Center by subtracting each training column mean:
Standardization also divides by training standard deviations, removing original volatility magnitudes. For correlation-PCA, justify equal scaling and fit both means and scales only on training rows.
With components is (X-center) @ components.T.
For
If trained with standardization, apply the frozen training scales too. Retain cutoff, feature order, center, scales and directions. Future rows enter the transform, never the past fit.
6. Derivations
6.1 Portfolio Variance from a Two-Asset Expansion
For fixed start-of-interval weights,
Linearity gives
Squaring the scalar and moving deterministic weights outside expectation,
The shape is
Expand the four matrix cells to see both cross terms:
Symmetry combines the middle terms. Omitting them omits joint risk.
6.2 Why Covariance Is PSD
For every
An expected square cannot be negative. If a nonzero combination is always zero, the covariance need not be PD. If B always returns twice A,
For
The denominator is the sample-covariance convention. This Gram-matrix proof requires every entry to come from the same
Centered columns sum to zero, so the sum of the
6.3 Variance Along Risk Axes
Write
Each
6.4 Why PCA Takes the Largest Eigenvalue Direction
For unit
Write
SVD gives
Explained variance ratio (EVR) is dimensionless; eigenvalues retain squared-return units. Scores
All nonzero directions reconstruct the centered data. Fewer directions discard variation. For that same centered matrix, truncated SVD minimizes squared reconstruction error at the chosen rank; the error equals the sum of discarded squared singular values. This optimization has no labels, fills or future net returns in its objective.
7. Financial Interpretation
7.1 Diversification and Joint Movement
At asset volatilities 20%, 30% and correlation
7.2 Small Eigenvalues Can Amplify Errors
Solving
Stable algorithms do not remove economic estimation error. Shrinkage, regularization and position limits can reduce sensitivity, while introducing bias and model choices that need out-of-sample checks. Chapters 8 and 21 develop these methods.
7.3 Appropriate Roles for PCA
PCA can summarize joint asset movement, diagnose near-duplicate columns and supply a candidate feature transform. Directions need separate units, budgets, shorting conventions, costs and signs before they define tradable positions.
PCA is unsupervised and uses no target labels. A high-variance direction may be common noise for a prediction task; a low-variance direction may contain target information. Covering 95% of training variance alone cannot establish trading value. Chapter 41 continues dimension reduction and model selection.
8. Numerical Examples
8.1 Two Assets: Each Risk Contribution
These supplied annual parameters are teaching constructions, not daily estimates or current market parameters:
Use annual simple expected returns, the same annual covariance interval, weights held at its start, no fees and no within-interval trades.
- Expected return:
, or 6.2%. - The row
is . - Its dot product with weights is
. - The four original-cell contributions are .0144, .0024, .0024 and .0144, summing to .0336.
- Volatility is
, about 18.33%.
Calling .0336 a 3.36% volatility confuses variance with standard deviation. Omitting cross terms gives .0288. With unchanged asset volatilities and perfect positive correlation, covariance is .06 and portfolio volatility 24%. At zero correlation, variance is .0288 and volatility about 16.97%. These changes come from specified joint-movement assumptions, not measured allocation effects.
8.2 Rank-Deficient Systems
For
both rows and columns are dependent and rank is 1. The sole independent equation is
Changing
8.3 Eigenvalues, Invertibility and the Budget
For the Section 8.1 covariance,
For a two-by-two matrix, the determinant is
Both are positive, and the condition number is about 2.41438775. This supplied small matrix is not nearly singular; real estimation quality is a separate question.
As a linear-system exercise,
Multiply back: the upper-left entry is
8.4 Three Rows: PCA and Reconstruction by Hand
9. Python Implementation
Default Entry in the Accepted Reader Package
Follow the reader installation instructions and run from its root:
.venv/bin/python run_notebook.py notebooks/ch05_linear_algebra.ipynb
The default Notebook uses packaged shared logic without absent French inputs or downloads. New runs and figures use unique runs directories; the reader CLI uses universally unique identifiers (UUIDs) and rejects overwrites. Historical tests absent from the reader are original production-check references. Use the Notebook assertions. Optional French inputs require the data contract; this batch did not rerun them.
The shared PCA implementation takes only a training matrix and returns its mean, row-stored directions, explained variances, ratios and training scores. Require at least two rows and one column of finite real values. It neither fills NaN nor standardizes; zero total variance raises an error. The separate original-course route uses the script, Notebook and project environment:
.venv/bin/python tools/run_a2.py --chapter 5
Each following snippet is self-contained. A NumPy one-dimensional vector is not literally a two-dimensional column; @ defines its contractions. Use reshape(-1,1) when an explicit column is needed.
import numpy as np
asset_returns = np.array([[0.02, -0.01], [-0.03, 0.04]])
weights = np.array([0.6, 0.4])
portfolio_returns = asset_returns @ weights
assert asset_returns.shape == (2, 2)
assert weights.shape == (2,)
assert portfolio_returns.shape == (2,)
assert np.allclose(portfolio_returns, [0.008, -0.002])
assert np.allclose(portfolio_returns, (asset_returns * weights).sum(axis=1))
print(portfolio_returns)
The rows are two supplied holding intervals, with decimal returns and A/B column order matched to weights. There is no signal or execution design, so the code checks multiplication rather than a backtest.
The second snippet verifies algebra, symmetry, spectrum and constraints. eigh returns ascending eigenvalues; PCA generally selects descending variance. The official interface documentation records that ordering and triangle convention; its previously read source scope is retained.
import numpy as np
covariance = np.array([[0.04, 0.01], [0.01, 0.09]])
expected_returns = np.array([0.05, 0.08])
weights = np.array([0.6, 0.4])
assert np.allclose(covariance, covariance.T)
eigenvalues, directions = np.linalg.eigh(covariance)
assert eigenvalues.min() > 0.0
assert np.allclose(directions.T @ directions, np.eye(2))
assert np.allclose(covariance @ directions, directions * eigenvalues)
variance = float(weights @ covariance @ weights)
assert np.isclose(variance, 0.0336)
assert np.isclose(weights @ expected_returns, 0.062)
solution = np.linalg.solve(covariance, expected_returns)
assert np.linalg.norm(covariance @ solution - expected_returns) < 1e-12
assert not np.isclose(solution.sum(), 1.0)
print(variance, np.sqrt(variance), eigenvalues, solution)
The third constructs covariance from one finite matrix and checks SVD against the spectrum. Its geometric rows have no timestamps or trade interpretation.
import numpy as np
from quant_course.math_tools import pca_fit_transform
samples = np.array([[1.0, 2.0], [2.0, 4.0], [3.0, 6.0]])
result = pca_fit_transform(samples, n_components=1)
centered = samples - result.center
sample_covariance = centered.T @ centered / (len(samples) - 1)
assert np.allclose(sample_covariance, [[1.0, 2.0], [2.0, 4.0]])
assert np.isclose(result.explained_variance[0], 5.0)
assert np.isclose(result.explained_variance_ratio[0], 1.0)
assert np.allclose(result.projection @ result.components + result.center, samples)
print(result.center, result.explained_variance, result.explained_variance_ratio)
The larger script constructs 252 daily rows for four fictitious assets with seed 20261005. Dates are timezone-aware Coordinated Universal Time (UTC) business-day labels without an exchange holiday calendar. Fit the first 180 rows, 2024-01-02 through 2024-09-09, and hold out 72. The inherited variance shares are about 56.96%, 20.19%, 14.36% and 8.49%. It creates no signal, fills or strategy-return result. Read actual outputs rather than changing the sample to obtain appealing percentages.
Later rows use (X_later-center) @ components.T with fitted parameters. Joining them to training before SVD changes the past fit. Missing-data policies belong in the training process; the shared implementation rejects missing values rather than silently zero-filling them.
10. Visualization

The Section 8.1 annual matrix supplies this geometry. Axes show A/B annual return deviations in percentage points. Contours have

The left axes are first/second component scores in decimal-return units. Each point is a training observation, colored by row order from early to late. The first axis has larger variance because PCA selects it that way; this is not independent investment evidence, a price series or a wealth chart.
The right panel shows component index against training variance share. The first two explain about 77.15%, leaving about 22.85% of training variation discarded by a two-direction truncation. Held-out shares can differ. The plot uses centering and SVD, without per-feature standardization or whitening. Whitening would rescale component variance and is discussed later in Chapter 41.
11. A Recorded Market-Snapshot Example
Chapter 2 already read the Kenneth R. French ten-industry monthly portfolio-return cache. Arranging it as months by industries lets you inspect common-sample covariance and PCA. These are published portfolio-return directions, not individual-stock risk models or executable industry strategies. A return-month label does not establish data availability at that month's closing auction.
The code uses complete common months from January 2010 through December 2019. The inherited executed first-three EVRs are 71.6043%, 7.5198% and 7.1064%; see the run record. They describe this recorded snapshot, fixed window and unstandardized convention. No 2020-or-later rows entered that fit. Nonetheless, the downloaded version may contain historical revisions and is insufficient to establish historical point-in-time (PIT) availability. Chapter 3 explains that version-time distinction.
from pathlib import Path
import numpy as np
import pandas as pd
from quant_course.math_tools import pca_fit_transform
path = Path("data/processed/french_10_industries_monthly.csv")
raw = pd.read_csv(path, dtype={"month": "string"})
monthly = raw.set_axis(pd.PeriodIndex(raw.pop("month"), freq="M"), axis="index")
train = monthly.loc["2010-01":"2019-12"].dropna(axis=0, how="any")
assert train.index.is_monotonic_increasing and train.index.is_unique
assert len(train) == 120
fit = pca_fit_transform(train.to_numpy(), n_components=3)
covariance = np.cov(train.to_numpy(), rowvar=False, ddof=1)
assert np.linalg.eigvalsh(covariance).min() >= -1e-12
assert np.isclose(fit.explained_variance.sum(), np.linalg.eigvalsh(covariance)[-3:].sum())
print("French snapshot: monthly published portfolio returns; not PIT prices")
print("training rows:", len(train), "features:", list(train.columns))
print("first three training EVR:", fit.explained_variance_ratio)
Common-sample dropna removes a whole month when any industry is missing. Research should report removed months and reasons, not only the final count. Here the fixed 120-row assertion prevents silently substituting another sample while keeping the same claims. PCA on uncentered price levels is not automatically a return-risk factor model.
12. Common Mistakes
12.1 Valid Dimensions with the Wrong Security Order
A two-entry dot product runs after swapping identities, but its meaning changes:
import numpy as np
import pandas as pd
returns = pd.Series({"A": 0.02, "B": -0.01})
weights = pd.Series({"B": 0.4, "A": 0.6})
wrong = float(returns.to_numpy() @ weights.to_numpy())
correct = float(returns @ weights.reindex(returns.index))
assert np.isclose(wrong, 0.002)
assert np.isclose(correct, 0.008)
print("positional mistake:", wrong, "aligned labels:", correct)
Freeze the column list before array operations. Training, risk, holdings and execution need the same security mapping. Permanent identifiers from Chapter 3 do not automatically enforce column order.
12.2 Pairwise Plausibility without Joint Consistency
12.3 Calling a Successful Solve a Valid Portfolio
A small linear-system residual says little about budgets, leverage, sectors, shorting or costs. Section 8.3 is not a maximum-Sharpe portfolio: no risk-free return, budget normalization or feasible set has yet been specified.
12.4 Fitting PCA before a Time Split
A full-sample fit makes past features depend on future means and covariance. Unsupervised processing can still leak future information. Fit each training window and only transform its successor. Section 18 changes an extreme future row to test the frozen past mean.
12.5 Mixing Scales and Risk Units
Columns combining prices, dollar turnover, percentages and bp can have high variance simply because of their units. Standardization may help compare features but also removes original risk magnitudes. Choose covariance- or correlation-PCA for the question; do not rescale arbitrarily and keep interpreting the result in original return units.
12.6 Comparing Every Eigenvector Sign Literally
A direction and its negative are equivalent. Nearly equal eigenvalues can make individual vectors sensitive to perturbations while their span is more stable. Check subspaces, orthogonality, reconstruction and spectrum; identical loading signs are not the sole criterion.
13. Research Application
For a risk-panel study, specify currency, frequency, holding intervals and securities; use versions available by the training cutoff and a shared missing-data rule. Estimate covariance on the same complete sample. Check symmetry, units, minimum eigenvalue, rank and conditioning before evaluating weights.
For PCA, fit means/directions in training and project the next window with those past parameters. Save feature order, cutoff, versions, center, directions and random configuration. Compare principal subspaces across windows as well as signs. Chapters 19 and 41 later address changing structure.
Predeclare at least two ways the proposal can fail: large direction changes under tiny sample perturbations, or no improvement in out-of-sample risk prediction/downstream loss despite high training EVR. Compare equal weights, a single common-risk direction or existing economic factors rather than only complex models against one another.
This chapter hands off numerical diagnostics and risk structure, not investment performance. A backtest still needs signal, execution, holdings, costs and label timing as developed in Chapter 29.
14. Chapter Summary
Vectors, matrices and transposes encode multi-asset mappings with explicit shapes. Rank counts independent directions; invertibility determines unique square-system solutions; conditioning diagnoses error amplification. Orthogonality, projection and changes of basis explain risk and regression geometry.
Fixed-weight variance is
Next, the current Chinese Chapter 6 develops probability, Chapter 8 applies projection to regression, and Chapters 9, 20 and 21 address estimated, constrained portfolio choices. Knowing the matrix objects prepares these problems without pretending to solve them already.
15. Exercises
5-E01. A panel has 120 months and ten industries. Give shapes of
5-E02. Calculate the dot product of weights
5-E03. Distinguish rank 1 from one stored column. For
5-E04. Give a PSD but non-PD covariance, identify a nonzero zero-variance direction and explain why PSD does not imply independence of all assets.
5-E05. Use the annual covariance in Section 8.1 with equal weights. Calculate expected return, variance, volatility and correlation, including units.
5-E06. For centered rows
5-E07. Section 8.4 retains 100% of sample variance with one component. Reverse its sign: what happens to scores, reconstruction and EVR? Does this prove future prediction?
5-N01: Identify Shapes. For
5-N02: Calculate Every Cell. Multiply
5-N03: Diagnose the Axis. What does this runnable code output? Change it to returns by date and assert the hand results.
import numpy as np
returns = np.array([[0.02, -0.01], [-0.03, 0.04]])
weights = np.array([0.6, 0.4])
wrong = (returns * weights).sum(axis=0)
print(wrong)
5-N04: Assess the Research Claim. A researcher stacks ten assets' full-period price levels, centers with the full-period mean and does PCA. They name the first direction a market-return factor, trade it and use high EVR as proof of strategy success. Identify at least three object/scale/timing errors, define a train/holdout process and state the evidence needed for trading claims.
16. Programming Exercises
5-P01. Diagnose a supplied real square matrix: shape, finite values, symmetry, eigenvalues and a scale-relative PSD check, rank and condition number. Test
5-P02. Center one complete training matrix and compute covariance. Use shared pca_fit_transform to verify full-component reconstruction, orthogonality and score variances. Retain one direction and compare squared reconstruction error with discarded squared singular values.
5-P03. Fit four training rows and transform one future row. Replace the future row by an extreme value: verify unchanged fit parameters, while showing that a leaky combined fit changes the mean. Record feature order and reject mismatched future column counts. Define all inputs locally.
17. Challenge Problems
5-C01. For near-duplicate assets with covariance solve is insufficient.
5-C02. French monthly industry PCA gives high first-component EVR. A colleague claims it is the market factor and retaining it must improve Sharpe. Plan checks of economic naming, versions/timing, out-of-sample results, scales, risk and costs, and specify findings that would reject the claim.
18. Complete Solutions
18.1 Concepts and Hand Calculations
5-E01.
5-E02. The correct return is
5-E03. Stored columns and independent directions differ. The second column is twice the first, giving rank 1.
5-E04. Take
5-E05. Annual expected return is .065, or 6.5%; variance is
5-E06. Centered rank is at most 19, leaving at least eleven zero-eigenvalue directions in a 30-asset covariance. Pairwise samples generally cannot be represented by one
5-E07.
18.2 Programming Reference Implementations
5-P01. Tie the tolerance to spectral scale and report both it and the minimum eigenvalue. Diagnosis is separate from invertibility; valid PSD can be singular. The function refuses materially invalid directions rather than deleting them.
import numpy as np
def diagnose_symmetric_matrix(matrix, relative_tolerance: float = 1e-10) -> dict:
raw = np.asarray(matrix)
if raw.ndim != 2 or raw.shape[0] != raw.shape[1] or raw.shape[0] == 0:
raise ValueError("require a non-empty square matrix")
if not np.issubdtype(raw.dtype, np.number) or np.iscomplexobj(raw):
raise TypeError("require real numeric values")
values = raw.astype(float)
if not np.isfinite(values).all():
raise ValueError("require finite values")
if not np.isfinite(relative_tolerance) or relative_tolerance <= 0:
raise ValueError("tolerance must be positive and finite")
scale = max(float(np.linalg.norm(values, ord=2)), np.finfo(float).tiny)
if not np.allclose(values, values.T, rtol=relative_tolerance,
atol=relative_tolerance * scale):
raise ValueError("input is not symmetric; do not silently symmetrize")
eigenvalues = np.linalg.eigvalsh(values)
tolerance = relative_tolerance * scale
return {"eigenvalues": eigenvalues, "tolerance": tolerance,
"psd_numerical": bool(eigenvalues.min() >= -tolerance),
"pd_numerical": bool(eigenvalues.min() > tolerance),
"rank": int(np.linalg.matrix_rank(values)),
"condition_2": float(np.linalg.cond(values))}
covariance = np.array([[0.04, 0.01], [0.01, 0.09]])
singular = np.array([[1.0, 2.0], [2.0, 4.0]])
invalid = np.array([[1.0, 0.9, 0.9], [0.9, 1.0, -0.9], [0.9, -0.9, 1.0]])
assert diagnose_symmetric_matrix(covariance)["pd_numerical"]
assert diagnose_symmetric_matrix(singular)["psd_numerical"]
assert not diagnose_symmetric_matrix(singular)["pd_numerical"]
assert not diagnose_symmetric_matrix(invalid)["psd_numerical"]
assert np.isclose(diagnose_symmetric_matrix(invalid)["eigenvalues"][0], -0.8)
print(diagnose_symmetric_matrix(covariance))
Numerical PD depends on the tolerance and does not replace the exact definition. Even small asymmetry needs investigation and an explicit treatment rule; this teaching checker rejects it.
5-P02. Full components check reconstruction and variance conventions; a single component checks truncation error. The squared Frobenius norm
import numpy as np
from quant_course.math_tools import pca_fit_transform
samples = np.array([[1.0, 2.0, 0.0], [2.0, 0.0, 1.0],
[4.0, 3.0, 2.0], [3.0, 5.0, 1.0]])
full = pca_fit_transform(samples, n_components=3)
centered = samples - full.center
covariance = centered.T @ centered / (len(samples) - 1)
assert np.allclose(full.projection @ full.components + full.center, samples)
assert np.allclose(full.components @ full.components.T, np.eye(3))
assert np.allclose(np.var(full.projection, axis=0, ddof=1), full.explained_variance)
assert np.isclose(full.explained_variance.sum(), np.trace(covariance))
short = pca_fit_transform(samples, n_components=1)
reconstructed = short.projection @ short.components + short.center
squared_error = float(np.square(samples - reconstructed).sum())
singular_values = np.linalg.svd(centered, compute_uv=False)
assert np.isclose(squared_error, np.square(singular_values[1:]).sum())
print("discarded reconstruction error:", squared_error)
Large-unit columns dominate unscaled squared reconstruction error. The objective remains computable, but its research meaning requires a scale decision.
5-P03. Transform with frozen centers/directions, without refitting. Column counts can be checked, while security names/order must be saved and checked by the caller as model metadata.
import numpy as np
from quant_course.math_tools import pca_fit_transform
training = np.array([[0.01, -0.02], [0.02, 0.01],
[-0.01, 0.03], [0.0, -0.01]])
future = np.array([[0.03, 0.02]])
fit = pca_fit_transform(training, n_components=2)
saved_center = fit.center.copy()
saved_components = fit.components.copy()
def transform_past_fit(values, center, components):
array = np.asarray(values, dtype=float)
if array.ndim != 2 or array.shape[1] != len(center):
raise ValueError("feature count differs from training")
if not np.isfinite(array).all():
raise ValueError("non-finite future features")
return (array - center) @ components.T
scores = transform_past_fit(future, fit.center, fit.components)
changed_future = np.array([[100.0, -100.0]])
changed_scores = transform_past_fit(changed_future, fit.center, fit.components)
assert not np.allclose(scores, changed_scores)
assert np.array_equal(fit.center, saved_center)
assert np.array_equal(fit.components, saved_components)
leaky_fit = pca_fit_transform(np.vstack([training, changed_future]), n_components=2)
assert not np.allclose(leaky_fit.center, saved_center)
try:
transform_past_fit(np.zeros((1, 3)), fit.center, fit.components)
except ValueError:
pass
else:
raise AssertionError("mismatched feature count accepted")
print("past center:", fit.center, "leaky center:", leaky_fit.center)
The assertions show this extreme future input did not change this fit. They do not prove every caller uses only past rows; callers still implement the time split and persist cutoff/version.
18.3 Challenge Reasoning and Scoring
5-C01. The common direction
import numpy as np
covariance = 0.04 * np.array([[1.0, 0.999], [0.999, 1.0]])
first = np.linalg.solve(covariance, np.array([0.05, 0.05]))
second = np.linalg.solve(covariance, np.array([0.051, 0.049]))
assert np.isclose(np.linalg.cond(covariance), 1999.0)
assert np.allclose(second - first, [25.0, -25.0])
print(first, second)
At the data level, check duplicates, synchronous returns and common-sample length. At the estimation level, assess mean shrinkage and covariance regularization, recording bias. At the decision level, impose budgets, leverage, asset limits and turnover costs. Stable decomposition and residual checks support these steps without replacing them. Ten points: directions/eigenvalues 3, solutions/amplification 3, three-level remedies 3, rejection of automatic arbitrage claims 1.
5-C02. Compare component scores with independently defined market excess returns using matched currency, frequency and model. High correlation alone does not establish identity. Record snapshot version and return month; distinguish retrospective analysis from actual PIT trading, which a current revised snapshot cannot reproduce by itself.
Fit preprocessing only inside each training window. Compare covariance-PCA, correlation-PCA and simple economic baselines under predeclared downstream prediction or risk loss. In the next window, assess subspace stability, risk forecast error and target prediction rather than reusing training EVR. A strategy also needs executable asset mapping, budgets, delays, costs and net returns. Only in-sample gains, strong scale dependence, a few years driving the result or no improvement after costs cannot support the strong claim.
Ten points: 2 for economic naming and comparison, 2 for versions and timing, 2 for training and later-window checks, 2 for scales and stability, and 2 for investment constraints, costs and falsification. “PCA reduces dimensions, so the model is better” earns no method credit.
18.4 Complete Answers to the Existing N-Series
5-N01.
5-N02.
Reversing the operation requires rechecking shapes and meaning. Both happen to be square, so
5-N03. Axis zero sums dates, yielding weighted totals by asset
import numpy as np
returns = np.array([[0.02, -0.01], [-0.03, 0.04]])
weights = np.array([0.6, 0.4])
by_date = (returns * weights).sum(axis=1)
via_matrix = returns @ weights
assert by_date.shape == (2,)
assert np.allclose(by_date, [0.008, -0.002])
assert np.allclose(via_matrix, by_date)
assert np.allclose((returns * weights).sum(axis=0), [-0.006, 0.012])
Axis one preserves rows/dates. The assertions check shape, hand results, matrix-product equivalence and the wrong-axis output.
5-N04. Price levels are not returns. A direction describes variation in its actual inputs and cannot automatically be named a return factor. Full-period centering leaks holdout observations into fitting; differing price scales also affect covariance-PCA directions. EVR does not measure forecasting, execution or net profit.
Specify objects/order, derive matching-frequency returns from information-available prices, and split training/holdout by time. Fit center and any justified standard deviations only on training data. Freeze directions, center, columns and cutoff, then transform held-out returns. Predeclare a risk or trading task, compare simple benchmarks in later windows and check stability. A trading claim additionally needs executable mapping, timing, fees and net results. Training EVR without these results cannot support it.
19. Further Reading
- Must know: MIT 18.06 syllabus for systems, spaces, projections, eigenvalues and positive matrices before the final SVD topic.
- Should know: NumPy SVD, solve and eigh: output shapes, direction storage and order.
- Should know: scikit-learn PCA: centering without automatic feature scaling, component/variance attributes and solver conditions.
- Advanced: Current Chinese Chapters 21 and 41 for shrinkage, constraints and dimension reduction, pending their English batches.
20. References and Reading Boundaries
The exposition and small examples are original teaching material, not a page-by-page textbook rewrite. Historical source verification is dated 2026-10-05; the Chinese source audit record states actual reading and limits. No new external reading, market download or market execution was performed for this translation.
MIT_LA and MIT_LA_SYLL support course-topic mapping, without claiming every video/lecture was read. NP_SVD supports decomposition, reduced shapes, ordering and reconstruction; NP_EIGH supports real-symmetric input, column directions, ascending eigenvalues and the triangle convention. NP_SOLVE and NP_COND support full-rank square systems, errors and the two-norm condition number. SK_PCA supports centering/scaling and component/variance attributes; the project uses explicit shared SVD and does not claim equivalence to every online library default. The exact official URLs are retained in the source audit record and the reading links above.