05 Linear Models

90-Minute Main Lesson: Loss → Regularization → Probability Decision

  • Objectives: Explain regression from its loss; compare Ridge and Lasso; map a linear score to probability; handle imbalance without leakage.

  • learning path:

    • prerequisite and regression 20 min → regularization 20 min → Sigmoid predict–reveal 15 min → Fuyao Glass main case 25 min → checks and synthesis 10 min.

    • SVM, multiclass methods, and SMOTE are extensions.

  • Answer first: If a residual grows from 2 to 4, by what factor does its squared-loss contribution grow?

  • Feedback: It grows from \(2^2=4\) to \(4^2=16\), a factor of four; MSE therefore emphasizes large residuals.

Welcome to Chapter 5: Linear Models

  • The intersection of machine learning and econometrics.
  • The art and science of finding linear relationships in data.
  • An indispensable foundation for building more complex models.

Goal 1: Build Powerful Predictive Capabilities

Linear models are the workhorses of economic forecasting.

  • Macroeconomics: Predicting GDP growth, inflation, and unemployment rates.
  • Financial Markets: Forecasting stock returns and asset price volatility.
  • Micro-level Behavior: Predicting consumer purchasing habits and corporate sales.

Mastering them means you possess the fundamental tools to quantitatively forecast the future.

Goal 2: Separate Predictive Association from Causal Effects

Linear regression first describes a conditional-mean association; it does not automatically answer ‘why’. Causal analysis must define the treatment, outcome, estimand, and a defensible identification design.

  • Identification checklist: establish timing and an assignment/exogeneity source; require consistency/SUTVA; measure treatment and key confounders; check overlap/positivity when relevant; choose in advance the estimand and specification.
  • Design before regression: tax, education, and pricing effects need a randomized or credible quasi-experimental design—not merely a broad ‘no omitted variables’ phrase.
  • Without identification: report a predictive association, not a policy or pricing effect.

This chapter trains prediction; its causal examples mark the boundary and do not turn an ordinary regression into an identified effect.

Goal 3: Establish the Foundation for Advanced Models

Nearly all modern, advanced machine learning models incorporate linear transformations at their core.

  • Neural Networks: Each neuron performs a weighted sum (a linear transformation) followed by a non-linear activation function.
  • Factor Models: In finance, asset returns are modeled as linear exposures to various risk factors.
  • Generalized Linear Models (GLMs): Extend the linear predictor to data with various distributions via a link function.

A solid understanding of linear models is the gateway to the broader world of machine learning.

This Chapter’s Learning Roadmap

We will follow a path from simple to complex to comprehensively master the ‘family’ of linear models.

Core Topic Key Models Core Problem Solved
Basic Linear Models Linear Regression Predicting continuous values (e.g., prices)
Logistic Regression Predicting probabilities/binary classes
Regularization/Sparsity Ridge & Lasso Regression Preventing overfitting, feature selection
Maximum-Margin Idea Support Vector Machine (SVM) Finding the most robust decision boundary
Handling Complexity Multiclass & Class Imbalance Tackling more complex real-world tasks

The Core Idea: What is a Linear Model?

The central assumption of a linear model is that the target variable can be expressed as a weighted sum of the input features.

For a sample \(\mathbf{x} = (x_1, x_2, \ldots, x_d)\) with d features, the prediction function is:

\[ \large{f(\mathbf{x}; \mathbf{w}, b) = w_1x_1 + w_2x_2 + \ldots + w_dx_d + b} \]

Using vector notation, this can be written concisely as:

\[ \large{f(\mathbf{x}; \mathbf{w}, b) = \mathbf{w}^T\mathbf{x} + b} \]

  • \(\mathbf{w} = (w_1, \ldots, w_d)\): The weight vector, which determines the importance of each feature.
  • \(b\): The bias or intercept term, which acts as the model’s baseline.

Anatomy of a Linear Model

This diagram illustrates how a linear model combines input features to produce a single predictive value.

Anatomy of a Linear Model A flowchart showing input features x1 to xd being multiplied by weights w1 to wd, then summed with a bias term b to produce the output f(x). Inputs (x) x₁ x₂ ... x_d Weights (w) w₁ w₂ w_d Σ Weighted Sum b Bias Term f(x) = wᵀx + b Model Output

The Geometry: It Defines a Decision Hyperplane

The model’s equation, \(\mathbf{w}^T\mathbf{x} + b = 0\), geometrically defines a hyperplane.

  • In 2D space (d=2): This is a straight line (\(w_1x_1 + w_2x_2 + b = 0\)).
  • In 3D space (d=3): This is a flat plane (\(w_1x_1 + w_2x_2 + w_3x_3 + b = 0\)).

This hyperplane divides the feature space into two halves, forming the decision boundary for all linear classifiers.

Hyperplanes Take Different Forms in Different Dimensions

Hyperplanes in 1D, 2D, and 3D space Three panels illustrating that a hyperplane is a point in 1D, a line in 2D, and a plane in 3D. 1D Space x₁ Hyperplane (a point) 2D Space x₁ x₂ 2D hyperplane: line 3D Space Hyperplane (a plane)

Example: A Linear Classifier in 2D Space

  • Suppose we predict if the economy is in an ‘expansion’ (blue circles) or ‘recession’ (red diamonds) based on two indicators: \(x_1\) (GDP growth) and \(x_2\) (inflation).

  • A linear classifier finds a line to separate these two classes.

Linear Classifier Decision Boundary A 2D plot showing a linear decision boundary separating two classes of data, with the orthogonal weight vector 'w' indicated. Classifier Decision Boundary x₁ (GDP Growth) x₂ (Inflation) w Expansion (Blue Circles) Recession (Red Diamonds)

The Weight Vector w Determines the Hyperplane’s Orientation

The weight vector \(\mathbf{w}\) is not just for weighting features; geometrically, it is always perpendicular to the decision hyperplane.

  • The direction of \(\mathbf{w}\) points in the direction of the fastest increase in the function \(f(\mathbf{x})\).
  • Orthogonality argument:
    • For two hyperplane points, \(\mathbf{w}^T(\mathbf{x}_A - \mathbf{x}_B) = 0\).

    • Therefore \(\mathbf{w}\) is orthogonal to every direction lying within the hyperplane.

In the previous slide, the vector \(\mathbf{w}\) (teal arrow) is perpendicular to the decision boundary (grey line).

From Geometry to Prediction: The Decision Rule

Once we have the hyperplane \(\mathbf{w}^T\mathbf{x} + b = 0\), classification is straightforward.

For a new data point \(\mathbf{x}\), we compute the value of \(f(\mathbf{x}) = \mathbf{w}^T\mathbf{x} + b\):

  • If \(f(\mathbf{x}) > 0\), the point lies on the side of the hyperplane pointed to by \(\mathbf{w}\). We predict it as the positive class (e.g., label +1).
  • If \(f(\mathbf{x}) < 0\), the point lies on the other side. We predict it as the negative class (e.g., label -1).

This decision function is often written as: \(\hat{y} = \text{sign}(\mathbf{w}^T\mathbf{x} + b)\).

Key Math: Distance from a Point to the Hyperplane

What is the distance from a sample point \(\mathbf{x}\) to the decision boundary \(\mathbf{w}^T\mathbf{x} + b = 0\)? This concept is crucial for Support Vector Machines (SVMs).

From analytic geometry, the distance \(r\) is given by:

\[ \large{r = \frac{|\mathbf{w}^T\mathbf{x} + b|}{\|\mathbf{w}\|}} \]

Where \(\|\mathbf{w}\|\) is the L2 norm (Euclidean length) of the weight vector, \(\|\mathbf{w}\| = \sqrt{w_1^2 + w_2^2 + \ldots + w_d^2}\).

Within one fixed model, \(|f(\mathbf{x})|\) is proportional to geometric distance; across models, use \(|f(\mathbf{x})|/\|\mathbf{w}\|\). A geometric margin is not a calibrated class probability.

5.1 From Classification to Regression: Linear Regression

If our goal is not to predict a discrete class (like ‘Expansion/Recession’) but a continuous value (like house prices, stock prices), the linear model becomes Linear Regression.

We directly use the model’s output as the predicted value:

\[ \large{\hat{y} = f(\mathbf{x}; \mathbf{w}, b) = \mathbf{w}^T\mathbf{x} + b} \]

The objective now becomes: Find the best \(\mathbf{w}\) and \(b\) such that the predicted value \(\hat{y}\) is as close as possible to the true observed value \(y\).

Measuring ‘Closeness’: Mean Squared Error (MSE)

We use a Loss Function to quantify the ‘error’ of our predictions. For linear regression, the most common loss function is the Mean Squared Error (MSE).

For a dataset of \(N\) samples \(\{(\mathbf{x}_n, y_n)\}_{n=1}^N\), the MSE is defined as:

\[ \large{J(\mathbf{w}, b) = \frac{1}{N} \sum_{n=1}^N (y_n - \hat{y}_n)^2 = \frac{1}{N} \sum_{n=1}^N (y_n - (\mathbf{w}^T\mathbf{x}_n + b))^2} \]

Our goal is to find the \(\mathbf{w}\) and \(b\) that minimize this \(J(\mathbf{w}, b)\). This is the famous Least Squares Method.

Geometric Intuition of the MSE Loss Function

Least squares finds the line that minimizes the sum of squared vertical residuals.

Ordinary Least Squares Intuition An illustration of the OLS method, showing data points, a regression line, and the vertical residuals whose squared sum is minimized. Ordinary Least Squares x y εᵢ Goal: minimize SSE min Σ (εᵢ)²

Solution 1: The Normal Equation Provides a Direct Formula

  • After absorbing the intercept into a constant feature, minimize \(J(\mathbf{w})=N^{-1}\|\mathbf y-\mathbf X\mathbf w\|_2^2\).

  • Setting its gradient to zero gives \(\mathbf X^{\mathsf T}\mathbf X\mathbf w=\mathbf X^{\mathsf T}\mathbf y\); with full column rank:

\[ \large{\mathbf{w}^* = (\mathbf{X}^T\mathbf{X})^{-1}\mathbf{X}^T\mathbf{y}} \]

  • Shapes: \(\mathbf X\) is \(N\times(d+1)\) and \(\mathbf y\) is \(N\times1\).
  • Rank-safe computation: \(\mathbf w^*=\mathbf X^+\mathbf y\) is the minimum-norm solution; use QR/SVD or lstsq, not an explicit inverse.

The Normal Equation Has Pros and Cons

Pros

  • Convex Problem: Stable QR/SVD solvers directly recover a global least-squares solution.
  • No Hyperparameters: No learning rate to tune.

Cons

  • Computational Cost: Direct factorizations become expensive as feature count grows; large sparse problems often use iterative solvers.
  • Rank Deficiency: With multicollinearity or \(d>N\), coefficients may be non-unique, but QR/SVD/pseudoinverse still solves least squares; report rank and conditioning.

Solution 2: The Core Idea of Gradient Descent

When the number of features is large, we typically use an iterative method called Gradient Descent.

The Core Idea

  • Imagine a blindfolded person trying to walk to the bottom of a valley.

  • At each step, they feel for the steepest path downhill (the opposite direction of the gradient) and take a small step.

  • They repeat this until they reach the valley floor (the minimum of the loss function).

Gradient Descent: the Optimization Path

Gradient Descent Visualization A contour plot showing the optimization path of gradient descent, moving opposite to the gradient vectors at each step towards the global minimum. Gradient descent: contour and update path Global minimum Steepest ascent Update: −gradient
  1. Randomly initialize \(\mathbf{w}\) and \(b\).

  2. Compute the gradient of the loss function with respect to \(\mathbf{w}\) and \(b\).

  3. Update the parameters in the opposite direction of the gradient: \(\mathbf{w} \leftarrow \mathbf{w} - \eta \nabla_{\mathbf{w}}J\); \(b \leftarrow b - \eta \nabla_{b}J\)

  4. Repeat steps 2 and 3 until convergence. (\(\eta\) is the learning rate).

Problem: What if Features are Numerous or Correlated?

Standard linear regression (OLS) runs into trouble in certain situations:

  1. Overfitting:
  • When the number of features \(d\) is close to or exceeds the number of samples \(N\), the model can become overly complex.

  • It may fit the training data perfectly but perform poorly on new data.

  1. Multicollinearity:
    • Pattern: features are highly correlated, such as house area and number of rooms.
    • Mechanism: \(\mathbf{X}^T\mathbf{X}\) becomes nearly singular.
    • Consequence: weight estimates \(\mathbf{w}\) become unstable and unreliable.

A Visual Example of Overfitting

Model Fit Comparison: Good Fit vs. Overfitting A comparative illustration showing a well-fitted model that captures the data's trend versus an overfitted model that memorizes the data's noise. Model Fit Comparison (Good Fit vs. Overfitting) Good Fit Captures the trend Overfitting Learns the noise

An overfit model learns the ‘noise’ in the training data, not just the underlying ‘signal’.

The Core Trade-off: Bias vs. Variance

  • Bias: The systematic difference between a model’s predictions and the true values. High bias means the model is too simple (underfitting).
  • Variance: The variability of a model’s predictions across different training sets. High variance means the model is too sensitive to the training data (overfitting).

Our goal is to find a model that achieves a good balance between bias and variance.

Bias–Variance Trade-off: Visual Summary

Bias-Variance Tradeoff A graph illustrating the Bias-Variance Tradeoff, showing the optimal point at the minimum of the total error curve. Error Model Complexity High bias High variance Total error Optimal balance

The Solution: Regularization Penalizes Complexity

The core idea of regularization is to penalize model complexity while minimizing training error.

We achieve this by adding a Penalty Term to the loss function, which is related to the magnitude of the weights \(\mathbf{w}\).

\[ \large{J_{\text{reg}}(\mathbf{w}, b) = \text{Training Error (e.g., MSE)} + \lambda \cdot \text{Complexity Penalty}} \]

  • \(\lambda \ge 0\) is the regularization parameter, a hyperparameter we set. It controls the strength of the penalty.
  • \(\lambda = 0\): No penalty; this reverts to standard linear regression.
  • \(\lambda \to \infty\): The penalty is extreme, forcing all weights toward zero.

5.2 L2 Regularization: Ridge Regression

Ridge Regression uses the squared L2 norm of the weight vector, \(\|\mathbf{w}\|_2^2 = \sum_{j=1}^d w_j^2\), as its penalty term.

The objective function is:

\[ \large{J_{\text{Ridge}}(\mathbf{w}, b) = \text{MSE}(\mathbf{w},b) + \lambda \sum_{j=1}^d w_j^2} \]

Effect:

  • It causes shrinkage of the coefficients, pulling them towards zero but rarely making them exactly zero.
  • By penalizing large weights, it makes the model smoother and reduces variance.
  • It effectively handles multicollinearity, making the model more stable.

L1 Regularization: Lasso Regression

Lasso (Least Absolute Shrinkage and Selection Operator) Regression uses the L1 norm of the weight vector, \(\|\mathbf{w}\|_1 = \sum_{j=1}^d |w_j|\), as its penalty.

The objective function is:

\[ \large{J_{\text{Lasso}}(\mathbf{w}, b) = \text{MSE}(\mathbf{w},b) + \lambda \sum_{j=1}^d |w_j|} \]

Effect:

  • Lasso not only shrinks coefficients but can force the coefficients of some unimportant features to be exactly zero.
  • Therefore, Lasso performs automatic Feature Selection, producing a sparser, more interpretable model, which is highly valuable in economic analysis.

Geometric View: Why Lasso Produces Sparse Solutions

The difference between Lasso and Ridge can be seen in the constraints they place on the weights.

  • Ridge: The constraint \(\|\mathbf{w}\|_2^2 \le \alpha\) is a circle (or sphere).

  • Lasso: The constraint \(\|\mathbf{w}\|_1 \le \alpha\) is a diamond (or high-dimensional polyhedron).

  • Contact geometry: loss contours expand until they meet the constraint region.

  • Why zeros appear: the Lasso diamond has sharp corners on the axes, so contact is more likely where some \(w_j=0\).

Geometric Evidence: Diamond Corners Favor Exact Zeros

Code
import numpy as np  # Create grids for regularization constraints and loss contours
import matplotlib.pyplot as plt  # Plot the L1-versus-L2 geometry
input_feature_values = np.linspace(-1.5, 1.5, 100)  # Fixed Horizontal Axis Weight Range
target_values = np.linspace(-1.5, 1.5, 100)  # Fixed Vertical Axis Weight Range
input_feature_matrix, target_grid_values = np.meshgrid(input_feature_values, target_values)  # Generate 2D Weight Combination
l1_norm = np.abs(input_feature_matrix) + np.abs(target_grid_values)  # Calculate L1 diamond constraint value
l2_norm_sq = input_feature_matrix**2 + target_grid_values**2  # Calculate L2 circular constraint value
w1_opt, w2_opt = 0.8, 1.0  # Fixed Unconstrained Loss Center
loss_contour = (input_feature_matrix - w1_opt)**2 + 1.5 * (target_grid_values - w2_opt)**2  # Pre-Calculated Elliptic Loss Contour
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
fig.suptitle('Geometric Interpretation of Regularization', fontsize=20)
ax1.contour(input_feature_matrix, target_grid_values, loss_contour, levels=np.logspace(-1, 1, 10), colors='gray', linestyles='--')
ax1.contour(input_feature_matrix, target_grid_values, l1_norm, levels=[1.2], colors='red', linewidths=2.5)
ax1.plot(0, 1.2, 'bo', markersize=10, label='Optimal Solution')
ax1.scatter(w1_opt, w2_opt, marker='x', color='blue', s=100, label='OLS Solution')
ax1.set_title('Lasso (L1 Constraint)', fontsize=20)
ax1.set_xlabel('$w_1$'); ax1.set_ylabel('$w_2$')
ax1.axhline(0, color='black', lw=0.5); ax1.axvline(0, color='black', lw=0.5)
ax1.set_aspect('equal', adjustable='box'); ax1.legend()
ax2.contour(input_feature_matrix, target_grid_values, loss_contour, levels=np.logspace(-1, 1, 10), colors='gray', linestyles='--')
ax2.contour(input_feature_matrix, target_grid_values, l2_norm_sq, levels=[1.1**2], colors='red', linewidths=2.5)
ax2.plot(0.6, 0.92, 'bo', markersize=10, label='Optimal Solution')
ax2.scatter(w1_opt, w2_opt, marker='x', color='blue', s=100, label='OLS Solution')
ax2.set_title('Ridge (L2 Constraint)', fontsize=20)
ax2.set_xlabel('$w_1$'); ax2.set_ylabel('$w_2$')
ax2.axhline(0, color='black', lw=0.5); ax2.axvline(0, color='black', lw=0.5)
ax2.set_aspect('equal', adjustable='box'); ax2.legend()
plt.tight_layout(rect=[0, 0.03, 1, 0.95])  # 展示当前步骤的结果。
plt.show()  # 展示当前步骤的结果。
Geometric Interpretation of Lasso (left) vs. Ridge (right)
Figure 1: Geometric Interpretation of Lasso (left) vs. Ridge (right)

5.3 Logistic Regression

Let’s return to classification. What are the problems with using the raw output of a linear model, \(\mathbf{w}^T\mathbf{x}+b\), directly for classification?

  1. Mismatched Output Range: The output is \((-\infty, +\infty)\), whereas the Sigmoid maps every finite input strictly into \((0, 1)\).
  2. Sensitivity to Outliers: A single outlier far from the decision boundary can drastically shift the regression line, thereby altering the classification outcome.

Logistic regression solves these issues with a clever ‘squashing’ function.

The Sigmoid Function Maps Real Numbers to Probabilities

Logistic regression models the Bernoulli conditional mean as a Sigmoid (Logistic) transform of the linear score and estimates parameters by likelihood/cross-entropy.

\[ \large{\sigma(z) = \frac{1}{1 + e^{-z}}} \]

where \(z = \mathbf{w}^T\mathbf{x} + b\).

Code
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(linear_predictor_values):  # 定义当前教学案例所需的函数。
    # Returns the current function results for subsequent evaluation or display.
    return 1 / (1 + np.exp(-linear_predictor_values))  # 返回当前步骤的计算结果供后续使用。
linear_predictor_values = np.linspace(-8, 8, 200)
probability_value = sigmoid(linear_predictor_values)
plt.style.use('seaborn-v0_8-whitegrid')  # 展示当前步骤的结果。
plt.figure(figsize=(8, 3.2))  # 展示当前步骤的结果。
plt.plot(linear_predictor_values, probability_value, color='crimson', linewidth=2.5)  # 展示当前步骤的结果。
plt.axhline(y=0.5, color='grey', linestyle='--'); plt.axvline(x=0, color='grey', linestyle='--')  # 展示当前步骤的结果。
plt.title('The Sigmoid Function', fontsize=50)  # 放大图题以满足投影阅读距离。
plt.xlabel('Linear score z', fontsize=50); plt.ylabel('Probability σ(z)', fontsize=50)  # 放大坐标轴标题以满足投影阅读距离。
plt.tick_params(axis='both', labelsize=50)  # 放大刻度文字以满足投影阅读距离。
plt.yticks([0, 0.5, 1.0])  # 展示当前步骤的结果。
plt.show()  # 展示当前步骤的结果。
The Sigmoid Function Curve
Figure 2: The Sigmoid Function Curve

Sigmoid Properties

  1. The output lies in \((0,1)\) and can therefore parameterize a Bernoulli probability; bounded output alone does not guarantee calibration, which must be checked on validation data.
  2. When \(z=0\), \(\sigma(z)=0.5\); as \(z \to +\infty\), \(\sigma(z) \to 1\); as \(z \to -\infty\), \(\sigma(z) \to 0\).

Sigmoid Predict–Reveal: Probability and Sensitivity

Without a calculator, first rank the probabilities for \(z\in\{-2,0,2\}\); then decide where \(\sigma'(z)=\sigma(z)[1-\sigma(z)]\) is largest.

Step-by-step check:

  • \(\sigma(-2)=1/(1+e^2)\approx0.119\); \(\sigma(0)=0.500\); \(\sigma(2)\approx0.881\).
  • \(\sigma'(0)=0.25\), while \(\sigma'(\pm2)\approx0.105\).
  • The model is most sensitive to score changes near the boundary \(z=0\) and saturates toward both tails; for finite \(z\), the probability remains strictly inside \((0,1)\).

Probabilistic Interpretation of Logistic Regression

The logistic regression model assumes the probability of a sample belonging to the positive class (y=1) is:

\[ \large{P(y=1 | \mathbf{x}; \mathbf{w}, b) = \sigma(\mathbf{w}^T\mathbf{x} + b)} \]

Therefore, the probability of it belonging to the negative class (y=0) is:

\[ \large{P(y=0 | \mathbf{x}; \mathbf{w}, b) = 1 - P(y=1 | \mathbf{x}; \mathbf{w}, b)} \]

A decision threshold of 0.5 is typically used: if \(P(y=1 | \mathbf{x}) > 0.5\) (which means \(\mathbf{w}^T\mathbf{x} + b > 0\)), we predict 1; otherwise, we predict 0.

The Loss Function for Logistic Regression is Cross-Entropy

Logistic regression isn’t optimized using Mean Squared Error. Instead, it uses an idea derived from Maximum Likelihood Estimation (MLE).

  • For the entire dataset, we want to maximize the joint probability of observing the given labels.

  • Taking the logarithm and negating it gives us the loss function to minimize, known as Log Loss or Binary Cross-Entropy:

\[ \large{J(\mathbf{w}, b) = -\frac{1}{N} \sum_{n=1}^N \left[ y_n \log(\hat{p}_n) + (1-y_n) \log(1 - \hat{p}_n) \right]} \]

where \(\hat{p}_n = \sigma(\mathbf{w}^T\mathbf{x}_n + b)\). This loss function is convex and can be efficiently solved using methods like gradient descent.

Intuition Behind the Cross-Entropy Loss

Intuitive View of Cross-Entropy Loss Two plots showing the log loss curve for true labels y=1 and y=0, illustrating how the loss penalizes incorrect predictions. When True Label y=1 Loss = -log(p̂) Loss p̂ (Predicted Prob.) 0 1 As p̂ → 1, loss → 0 When True Label y=0 Loss = -log(1-p̂) Loss p̂ (Predicted Prob.) 0 1 As p̂ → 0, loss → 0

Main lesson: Skip SVM and Multiclass Methods

Main lesson: SVM and multiclass methods are Extension; continue from logistic loss directly to class imbalance.

5.4 Support Vector Machines (SVM)

Logistic regression finds a boundary that separates the data, but is it the best boundary?

  • As seen below, multiple lines can perfectly separate the two classes.

  • The core idea of SVM is: Don’t just separate the classes, separate them with the largest possible ‘margin’.

  • The most robust boundary is the one that is as far as possible from the nearest points of both classes.

Visual: Maximum Margin Selects a More Robust Boundary

Code
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
input_feature_matrix, target_values = make_blobs(n_samples=40, centers=2, random_state=8, cluster_std=0.8)
plt.style.use('seaborn-v0_8-whitegrid')  # 展示当前步骤的结果。
plt.figure(figsize=(8, 6))  # 展示当前步骤的结果。
plt.scatter(input_feature_matrix[:, 0], input_feature_matrix[:, 1], c=target_values, s=50, cmap='winter', edgecolors='k')  # 展示当前步骤的结果。
x_fit = np.linspace(plt.xlim()[0], plt.xlim()[1], 100)
plt.plot(x_fit, -1 * x_fit + 7, '-k', label='Boundary A (Optimal)')  # 展示当前步骤的结果。
plt.plot(x_fit, -0.6 * x_fit + 8.5, '--k', label='Boundary B (Too close to blue)')  # 展示当前步骤的结果。
plt.plot(x_fit, -1.5 * x_fit + 3.5, ':k', label='Boundary C (Too close to green)')  # 展示当前步骤的结果。
plt.title('SVM Motivation: The Optimal Boundary', fontsize=24)  # 放大图题以满足投影阅读距离。
plt.xlabel('Feature 1', fontsize=22); plt.ylabel('Feature 2', fontsize=22)  # 放大坐标轴标题以满足投影阅读距离。
plt.legend(fontsize=20)  # 放大图例以满足投影阅读距离。
plt.tick_params(axis='both', labelsize=20)
plt.show()  # 展示当前步骤的结果。
Which separating line is the best?
Figure 3: Which separating line is the best?

SVM Core Concepts: Margin and Support Vectors

Optional topic: Core proceeds from logistic loss to class imbalance, then the main case. Return to SVM and multiclass methods after Core.

  • Decision Boundary: The hyperplane \(\mathbf{w}^T\mathbf{x} + b = 0\).
  • Margin: The “empty” region between the decision boundary and the data points on either side. SVM aims to maximize the width of this region.
  • Support vectors:
    • in the linearly separable hard-margin case, they lie exactly on the margin boundaries.

    • In a soft-margin SVM, they have active/nonzero dual coefficients and may lie on the boundary, inside the margin, or violate it.

    • Moving a non-support point leaves the current solution unchanged only while that point remains inactive.

Mechanism Appendix: SVM Margin and Support Vectors

Code
import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVC
from sklearn.datasets import make_blobs
input_feature_matrix, target_values = make_blobs(n_samples=50, centers=2, random_state=0, cluster_std=0.60)
model = SVC(kernel='linear', C=1E10).fit(input_feature_matrix, target_values)
plt.style.use('seaborn-v0_8-whitegrid')  # 展示当前步骤的结果。
plt.figure(figsize=(9, 6))  # 展示当前步骤的结果。
plt.scatter(input_feature_matrix[:, 0], input_feature_matrix[:, 1], c=target_values, s=50, cmap='winter', edgecolors='k')  # 展示当前步骤的结果。
ax = plt.gca()
xlim, ylim = ax.get_xlim(), ax.get_ylim()
xx, yy = np.meshgrid(np.linspace(xlim[0], xlim[1], 30), np.linspace(ylim[0], ylim[1], 30))
transformed_feature_matrix = model.decision_function(np.vstack([xx.ravel(), yy.ravel()]).T).reshape(xx.shape)
ax.contour(xx, yy, transformed_feature_matrix, colors='k', levels=[-1, 0, 1], alpha=0.8, linestyles=['--', '-', '--'])
ax.scatter(model.support_vectors_[:, 0], model.support_vectors_[:, 1], s=150, linewidth=2, facecolors='none', edgecolors='red')  # 用红色空心圆直接标出支持向量,避免图例遮挡决策边界。
plt.title('SVM margin; red rings = support vectors', fontsize=42)  # 在图题中解释红圈语义,保留完整数据走廊。
plt.xlabel('Feature 1', fontsize=50); plt.ylabel('Feature 2', fontsize=50)  # 放大坐标轴标题以满足投影阅读距离。
plt.tick_params(axis='both', labelsize=50)  # 放大刻度文字以满足投影阅读距离。
plt.show()  # 展示当前步骤的结果。
The margin and support vectors in an SVM
Figure 4: The margin and support vectors in an SVM

SVM Math (Linearly Separable Case)

  • To maximize the margin, we first define its width.

  • By scaling \(\mathbf{w}\) and \(b\), we can set the margin such that for any support vector \(\mathbf{x}_s\), we have \(|\mathbf{w}^T\mathbf{x}_s + b| = 1\).

  • The distance from a point to the hyperplane is \(\frac{|\mathbf{w}^T\mathbf{x} + b|}{\|\mathbf{w}\|}\).

  • So, the distance from a support vector to the hyperplane is \(1/\|\mathbf{w}\|\).

The total width of the margin is therefore \(2 / \|\mathbf{w}\|\).

Maximizing the margin \(\iff\) Maximizing \(2 / \|\mathbf{w}\| \iff\) Minimizing \(\|\mathbf{w}\| \iff\) Minimizing \(\frac{1}{2}\|\mathbf{w}\|^2\).

Simultaneously, all points must be classified correctly, meaning for each sample \((\mathbf{x}_n, y_n)\) (where \(y_n \in \{-1, 1\}\)): \(y_n(\mathbf{w}^T\mathbf{x}_n + b) \ge 1\).

The SVM Optimization Problem (Hard Margin)

In summary, the optimization problem for a linearly separable (hard-margin) SVM is:

\[ \large{\min_{\mathbf{w}, b} \quad \frac{1}{2}\|\mathbf{w}\|^2} \]

\[ \large{\text{subject to} \quad y_n(\mathbf{w}^T\mathbf{x}_n + b) \ge 1, \quad \forall n=1, \ldots, N} \]

This is a convex quadratic programming problem with inequality constraints, which can be solved using methods like Lagrange duality.

The Real World is Messy: What if Data isn’t Linearly Separable?

In real-world economic data, perfect linear separability is almost never the case. There will always be some noise or outliers.

If we force a hard-margin SVM on such data, we might either find no solution or find a poor boundary that overfits to the noisy points.

Solution: Introduce the Soft Margin, which allows the model to make a few mistakes.

Soft-Margin SVMs Tolerate Errors via Slack Variables

We introduce a slack variable \(\xi_n \ge 0\) for each data point.

The constraint is relaxed to:

\[ \large{y_n(\mathbf{w}^T\mathbf{x}_n + b) \ge 1 - \xi_n} \]

  • If \(\xi_n = 0\), the point is correctly classified and outside the margin.
  • If \(0 < \xi_n < 1\), the point is within the margin but still correctly classified.
  • If \(\xi_n = 1\), the constraint permits the point to lie exactly on the decision boundary, so strict correct classification is not guaranteed.
  • If \(\xi_n > 1\), the constraint permits the point to cross the boundary and be misclassified.

Soft-Margin Objective: Margin vs. Violations

We then add a penalty for these ‘mistakes’ to the objective function:

\[ \large{\min_{\mathbf{w}, b, \mathbf{\xi}} \quad \frac{1}{2}\|\mathbf{w}\|^2 + C \sum_{n=1}^N \xi_n} \]

The Hyperparameter C Balances Margin Width and Errors

\(C\) is a crucial hyperparameter that controls the penalty for slack variables. Think of it as the inverse of the regularization parameter \(\lambda\).

  • Small \(C\): Low penalty for errors. The model prioritizes a wide margin, even if it means some points are inside the margin or misclassified. High tolerance, strong regularization, may underfit.
  • Large \(C\): High penalty for errors. The model tries very hard to classify every point correctly, which can lead to a narrow margin and overfitting to the training data. Low tolerance, weak regularization, may overfit.

SVM C: Visual Comparison of Margin and Errors

The Margin vs. Error Trade-off via the C Parameter in SVMs A diagram comparing a low-C (wide margin, high tolerance) SVM with a high-C (narrow margin, low tolerance) SVM. The SVM Margin vs. Error Trade-off (Parameter C) Small C: wide margin Wide margin; errors allowed Large C: narrow margin Fewer errors; overfit risk

5.5 Multiclass Linear Models

We have focused on binary classification, but many real-world tasks involve multiple categories. For example:

  • Segmenting customers into ‘High-Value’, ‘Mid-Value’, and ‘Low-Value’.
  • Recognizing handwritten digits (0-9, a 10-class problem).
  • Predicting the state of the economy: ‘Recovery’, ‘Boom’, ‘Recession’, or ‘Depression’.

How can we extend binary classifiers to handle multiclass scenarios?

Strategy 1: One-vs-Rest (OvR)

This strategy involves training one binary classifier for each class, which is trained to distinguish that class from all other classes combined.

  • For K classes, you train K classifiers.
  • Prediction compares K decision scores. They are directly comparable only under a consistent training/scaling scheme or after calibration, and they are not automatically probability confidences.

One-vs-Rest: Three Binary Views

One-vs-Rest (OvR) Multiclass Strategy Three panels reuse the same A, B, and C samples. In each panel, the target class keeps its color while the other two classes are merged into a gray negative class; the dashed boundaries correctly separate A from B plus C, B from A plus C, and C from A plus B. One-vs-Rest (OvR) Strategy Classifier 1: A vs. Rest Positive A; negative B+C Classifier 2: B vs. Rest Positive B; negative A+C Classifier 3: C vs. Rest Positive C; negative A+B

Strategy 2: One-vs-One (OvO)

This strategy involves training a binary classifier for every pair of classes.

  • For K classes, you train \(K(K-1)/2\) classifiers.

  • At prediction time, each pairwise classifier votes.

  • A unique plurality wins; ties use a predeclared deterministic rule (here, maximize the sum of signed pairwise confidences, then use a fixed class order if still tied).

  • Raw votes and uncalibrated margins are not multiclass probabilities.

One-vs-One (OvO) Multiclass Strategy A diagram illustrating the OvO strategy, showing separate binary classifiers for each pair of classes (A vs B, A vs C, B vs C). One-vs-One (OvO) Strategy Classifier 1: A vs. B Classifier 2: A vs. C Classifier 3: B vs. C

OvR vs. OvO: A Comparison

Feature One-vs-Rest (OvR) One-vs-One (OvO)
# of Classifiers K K(K-1)/2
Training Data Each classifier uses all data (can be imbalanced) Each classifier uses only the participating pair; balance depends on their sample counts
Compute trade-off Trains K classifiers on the full sample. Trains K(K-1)/2 smaller two-class models; each fit is smaller, but total cost can be higher when K is large.
Commonly used with Logistic Regression (default) Support Vector Machines

Direct Extension: Softmax Regression

A more direct approach is Softmax Regression, which generalizes logistic regression to multiple classes.

  • For K classes, the model learns K weight vectors \(\{\mathbf{w}_1, \ldots, \mathbf{w}_K\}\).

  • For a sample \(\mathbf{x}\), we compute K scores: \(s_k(\mathbf{x}) = \mathbf{w}_k^T \mathbf{x} + b_k\).

The Softmax function then converts these scores into a probability distribution:

\[ \large{P(y=k | \mathbf{x}) = \text{softmax}(s_k) = \frac{e^{s_k(\mathbf{x})}}{\sum_{j=1}^K e^{s_j(\mathbf{x})}}} \]

  • The probabilities for all classes sum to 1.
  • The loss function is the multiclass version of Cross-Entropy Loss.

5.6 The Class Imbalance Problem

In many important real-world applications, the event of interest is very rare.

  • Financial Fraud Detection: The vast majority of transactions are legitimate.
  • Rare Disease Diagnosis: Most people are healthy.
  • Ad Click-Through Prediction: A very small fraction of users click on an ad.

This situation is known as Class Imbalance. For example, a dataset might contain 99% negative samples and only 1% positive samples.

Why is Class Imbalance a Problem? The Accuracy Paradox

Standard machine learning models aim to maximize overall Accuracy.

  • On a dataset with 99% negative samples, a naive model that simply predicts ‘negative’ for every single sample will achieve 99% accuracy.

  • However, this model is completely useless because it fails to identify any positive samples.

The Core Issue

The model’s learning is dominated by the majority class, and it neglects the minority class. We need better evaluation metrics.

A Better Evaluation Tool: The Confusion Matrix

The Confusion Matrix is a table that visualizes the performance of a classification model.

The Confusion Matrix A 2x2 table showing the four outcomes of a binary classifier: True Positive, False Negative, False Positive, and True Negative. Confusion Matrix Predicted Class Actual Class TP True Positive Positive Positive FN False Negative FP False Positive Negative TN True Negative Negative

Key Metrics: Precision and Recall

Based on the confusion matrix, we can define two more meaningful metrics:

  • Precision: Of all samples predicted as positive, how many were actually positive?

    \[ \large{\text{Precision} = \frac{TP}{TP + FP}} \]

    Measures how ‘correct’ the positive predictions are.

  • Recall (or Sensitivity): Of all samples that were actually positive, how many did the model successfully find?

    \[ \large{\text{Recall} = \frac{TP}{TP + FN}} \]

    Measures how ‘complete’ the positive predictions are.

In fraud detection, we care deeply about recall (we don’t want to miss any fraudulent transactions).

Solution 1: Data-Level Resampling

The most direct approach is to fix the imbalance at the data level. There are two main strategies:

Data Resampling Methods for Class Imbalance A three-panel diagram illustrating Undersampling and Oversampling from an initial imbalanced dataset to create a balanced one. Handling Class Imbalance: Resampling Methods 1. Original imbalanced data 2. Undersampling Remove majority 3. Oversampling Add minority

Pros and Cons of Resampling Methods

Undersampling

  • Pro: Faster training time.
  • Con: May discard important information from the majority class.

Oversampling

  • Pro: No information loss.
  • Con: May lead to overfitting on the minority class.
  • Popular Algorithm: SMOTE (Synthetic Minority Over-sampling Technique).

Main lesson: SMOTE is Extension; continue from the resampling comparison to algorithm-level adjustment, then the main case.

SMOTE Creates Synthetic Minority Samples

SMOTE is one of the most effective oversampling techniques.

Core Idea

  • For each minority sample, find its k-nearest neighbors (which are also minority samples).

  • Then, randomly pick a point along the line segment connecting the sample to one of its neighbors and create a new, synthetic sample there.

This is like ‘interpolating’ within the minority class region, creating new data that is similar to the original data but not identical, which helps expand the decision region for the minority class.

How the SMOTE Algorithm Works

The SMOTE Algorithm Explained A two-panel diagram explaining SMOTE by showing the initial imbalanced state and the step-by-step process of creating a synthetic sample. Oversampling Technique: SMOTE Explained 1. Original Imbalanced Data Majority Class Minority Class 2. SMOTE synthesis ① Select sample A ② Neighbor B ③ New sample lies on A–B

Solution 2: Algorithm-Level Adjustments

Besides modifying the data, we can also adjust the learning algorithm itself.

  • Adjusting Class Weights: We can assign a higher penalty for misclassifying minority class samples in the loss function.
    • For example, setting class_weight='balanced' in scikit-learn models.
    • This forces the model to pay more attention to correctly classifying the minority class during optimization.
  • Changing the Decision Threshold: Logistic regression uses a 0.5 probability threshold by default. For imbalanced problems, we can lower this threshold (e.g., to 0.3) to increase recall for the minority class.

Core Learning Review

  • Core (70 min): linear regression, regularization, logistic regression, and out-of-sample evaluation. Extension (20 min or after class): SVM, multiclass methods, and SMOTE.

Retrieve the opening objectives: derive a linear model from its loss, explain Ridge/Lasso constraints, distinguish scores from calibrated probabilities, and handle imbalance without leakage.

  • Retrieval prompt: If an error grows from 2 to 4, by what factor does its squared-loss contribution grow?
  • Answer: From \(2^2=4\) to \(4^2=16\), a factor of four; this is why MSE emphasizes large residuals.

Formative Check 1: Regularization

Which method more often produces exactly zero coefficients, Ridge or Lasso, and why?

Answer

Lasso. Corners of the L1 constraint often meet loss contours on coordinate axes; the smooth L2 ball usually shrinks continuously without exact zeros.

Main Case: Fuyao Glass Ridge Return Prediction

  • Data used in this example:
    • Source: data/stock/stock_price_pre_adjusted.h5, key=data, Fuyao Glass 600660.XSHG.

    • Task: use 2018–2024 close and volume to predict next-day return from one-to-five-day lagged returns and volume growth.

    • Split: chronological 80/20 train/test periods.

  • Nearby method source: Hoerl & Kennard (1970), ridge regression. First prepare the chronological boundary while keeping test labels held-out; then select regularization strength using training-period windows only.
Code
from pathlib import Path  # Locate the downloaded data file

import pandas as pd  # Read local quotes into a table
from sklearn.pipeline import make_pipeline  # Fit scaling and the model on the same training rows
from sklearn.preprocessing import StandardScaler  # Unifying Lagging Feature Scales
from sklearn.linear_model import Ridge  # Use L2 regularization to stabilize correlation characteristic coefficients
from sklearn.metrics import mean_squared_error  # Evaluate Out-of-Sample Error of Continuous Forecast
# Public download: https://assets.qiufei.site/data/stock/stock_price_pre_adjusted.h5
# After downloading, change the next line to the file's actual location on your device.
# Course-relative option: Path("data/stock/stock_price_pre_adjusted.h5")
# Windows: Path(r"C:\qiufei\data\stock\stock_price_pre_adjusted.h5")
# macOS: Path("/Users/your_name/data/stock/stock_price_pre_adjusted.h5")
# Linux: Path("/home/your_name/data/stock/stock_price_pre_adjusted.h5")
price_path = Path("/home/ubuntu/r2_data_mount/data/stock/stock_price_pre_adjusted.h5")
price_rows = pd.read_hdf(price_path, key='data', where=['order_book_id=="600660.XSHG"', 'date>=Timestamp("2018-01-01")', 'date<=Timestamp("2024-12-31")'], columns=['close', 'volume'])  # Only Load Target Companies, Periods, and Fields
ridge_frame = price_rows.reset_index().sort_values('date')  # Build Forecast Order by Trading Day
ridge_frame['return_t'] = ridge_frame['close'].pct_change()  # Compute the baseline one-day return
feature_names = [f'return_lag_{lag_day}' for lag_day in range(1, 6)]  # Pre-declare five historical benefit feature names
for lag_day, feature_name in enumerate(feature_names, start=1): ridge_frame[feature_name] = ridge_frame['return_t'].shift(lag_day - 1)  # Write each available historical return to its lagged-feature column
ridge_frame['volume_growth_t'] = ridge_frame['volume'].pct_change()  # Adding the volume growth rate of the day
ridge_frame['target_return_t1'] = ridge_frame['return_t'].shift(-1)  # Define next-day return targets
ridge_frame['target_date_t1'] = ridge_frame['date'].shift(-1)  # Preserve the label-realization date for boundary purging
ridge_frame = ridge_frame.replace([float('inf'), float('-inf')], pd.NA).dropna()  # Remove non-finite observations created by transformations
Code
feature_names = feature_names + ['volume_growth_t']  # Add volume information to the model matrix
split_row = int(len(ridge_frame) * 0.8)  # Fixed First Eighty Percent as Training Period
test_start_date = ridge_frame.iloc[split_row]['date']
train_rows = ridge_frame[(ridge_frame['date'] < test_start_date) & (ridge_frame['target_date_t1'] < test_start_date)]  # Purge training labels realized in test
test_rows = ridge_frame[ridge_frame['date'] >= test_start_date]
assert train_rows['target_date_t1'].max() < test_rows['date'].min()  # Verify the label-realization boundary
pd.Series({'train_end': train_rows['date'].max(), 'test_start': test_rows['date'].min()})  # Verify only the time boundary without reading test labels or candidate-model test errors
train_end    2023-08-04
test_start   2023-08-08
dtype: datetime64[ns]

Formative Check 2: Probability and Threshold

What probability does logistic regression assign when \(z=0\)? If false negatives become more costly, should the threshold generally rise or fall?

Answer

\(\sigma(0)=1/(1+e^0)=0.5\). It generally falls to gain positive-class recall; the threshold follows loss, not convention.

Step-by-Step Exercise: Choose \(\alpha\)

  • Task: Use expanding-window training validation to compare \(\alpha\in\{0.1,1,10,100\}\), choose selected_alpha, refit once, then evaluate once on the fixed test period beside the training-mean baseline.
  • Complete solution: Refit scaler + Ridge inside each window; minimize mean validation MSE, refit on all training data, then report Ridge and baseline test MSE. Never select \(\alpha\) from test results.
Code
from sklearn.model_selection import TimeSeriesSplit  # Constructing an Extended Window Validated Only for the Future
alpha_rows = []  # Collect Validation MSE for Each Folded Regular Strength
for fold_id, (fit_index, validation_index) in enumerate(TimeSeriesSplit(n_splits=5).split(train_rows), start=1):  # Generate Five Time Windows
    fold_train = train_rows.iloc[fit_index]  # Retrieve the historical training segment
    fold_validation = train_rows.iloc[validation_index]  # Retrieve the subsequent validation segment
    fold_train = fold_train[fold_train['target_date_t1'] < fold_validation['date'].min()]  # Purge labels realized in the validation fold
    assert fold_train['target_date_t1'].max() < fold_validation['date'].min()  # Verify each fold's label boundary
    for alpha_value in [0.1, 1.0, 10.0, 100.0]:  # Compare pre-stated candidate regular strength
        fold_model = make_pipeline(StandardScaler(), Ridge(alpha=alpha_value)).fit(fold_train[feature_names], fold_train['target_return_t1'])  # Fit scaling and Ridge on the current training segment
        fold_prediction = fold_model.predict(fold_validation[feature_names])  # Generate Forecast for Subsequent Validation Periods
        alpha_rows.append({'fold': fold_id, 'alpha': alpha_value, 'validation_mse': mean_squared_error(fold_validation['target_return_t1'], fold_prediction)})  # save break errors
alpha_table = pd.DataFrame(alpha_rows)  # Organize all validation results
alpha_summary = alpha_table.groupby('alpha', as_index=False)['validation_mse'].mean().rename(columns={'validation_mse': 'mse'}).sort_values('mse')  # Summarize validation-stage MSE under one explicit metric field
alpha_summary.insert(0, 'stage', 'mean_time_validation')  # Mark these rows as training-period time-validation evidence
selected_alpha = float(alpha_summary.iloc[0]['alpha'])
final_ridge = make_pipeline(StandardScaler(), Ridge(alpha=selected_alpha)).fit(train_rows[feature_names], train_rows['target_return_t1'])  # Re-fit the fixed model with a full training period
final_prediction = final_ridge.predict(test_rows[feature_names])  # Generate the Ridge return prediction for the fixed test period only once
final_baseline = [train_rows['target_return_t1'].mean()] * len(test_rows)  # Establishing reviewable benchmarks with mean of training periods
pd.concat([alpha_summary[['stage', 'alpha', 'mse']], pd.DataFrame([{'stage': 'test_model', 'alpha': selected_alpha, 'mse': mean_squared_error(test_rows['target_return_t1'], final_prediction)}, {'stage': 'test_baseline', 'alpha': pd.NA, 'mse': mean_squared_error(test_rows['target_return_t1'], final_baseline)}])], ignore_index=True)  # Separate validation, test-period, and test-baseline evidence in a stage-explicit long table
Table 1
stage alpha mse
0 mean_time_validation 100.0 0.000508
1 mean_time_validation 10.0 0.000509
2 mean_time_validation 1.0 0.000509
3 mean_time_validation 0.1 0.000509
4 test_model 100.0 0.000252
5 test_baseline <NA> 0.000249

Exercise Result: Ridge Does Not Beat the Baseline

  • fixed test: validation chose \(\alpha=100\). Ridge MSE \(0.0002521479>0.0002491785\) for the training-mean baseline, so this held-out check does not support practical use.

Apply It to a New Case

  • Change the task to Hengrui Pharmaceuticals 600276.XSHG next-day decline; compare logistic thresholds 0.5 and a 4:1 false-negative-cost threshold.

  • Submit AP (average precision), recall, precision, and confusion matrices.

  • The value \(0.2=1/(4+1)\) is Bayes-optimal only for calibrated probabilities, a 4:1 false-negative:false-positive cost ratio, and equal zero costs for correct decisions;

  • practical use still requires validation-period checking.

  • Metric convention: AP is computed with average_precision_score, which weights precision by recall increments; it is not the trapezoidal area under the empirical PR curve.

  • Complete-answer reminder:
    • Design: show the time split and fit preprocessing on training data.

    • Decisions: obtain probabilities with predict_proba and create both Boolean-threshold decisions.

    • Evidence: report all four metrics, the cost trade-off, and the non-causal limitation.

Complete Solution for the New Case: Hengrui Logistic Regression

Table 2
Code
from sklearn.linear_model import LogisticRegression  # Estimating interpretable benchmarks for fall probabilities
from sklearn.metrics import average_precision_score, confusion_matrix, precision_score, recall_score  # Evaluation Unbalanced Classification and Cost Thresholds Calculated from Current Data
from pathlib import Path  # Locate the downloaded data file
# Public download: https://assets.qiufei.site/data/stock/stock_price_pre_adjusted.h5
# After downloading, change the next line to the file's actual location on your device.
# Course-relative option: Path("data/stock/stock_price_pre_adjusted.h5")
# Windows: Path(r"C:\qiufei\data\stock\stock_price_pre_adjusted.h5")
# macOS: Path("/Users/your_name/data/stock/stock_price_pre_adjusted.h5")
# Linux: Path("/home/your_name/data/stock/stock_price_pre_adjusted.h5")
price_path = Path("/home/ubuntu/r2_data_mount/data/stock/stock_price_pre_adjusted.h5")
transfer_rows = pd.read_hdf(price_path, key='data', where=['order_book_id=="600276.XSHG"', 'date>=Timestamp("2018-01-01")', 'date<=Timestamp("2024-12-31")'], columns=['close', 'volume'])  # Select Hengrui Medicine, Period and Required Fields
transfer_frame = transfer_rows.reset_index().sort_values('date')  # Sort by trading days in order of forecast occurrence
transfer_frame['return_t'] = transfer_frame['close'].pct_change()  # Compute one-day returns
transfer_frame['return_5d_t'] = transfer_frame['close'].pct_change(5)  # Compute five-day returns
transfer_frame['volatility_5d_t'] = transfer_frame['return_t'].rolling(5).std()  # Compute rolling five-day volatility
transfer_frame['volume_growth_t'] = transfer_frame['volume'].pct_change()  # Construct Volume Growth
transfer_frame['future_return_t1'] = transfer_frame['return_t'].shift(-1)  # Retain continuous future returns before label construction
transfer_frame['target_date_t1'] = transfer_frame['date'].shift(-1)  # Preserve the label-realization date
transfer_frame = transfer_frame.replace([float('inf'), float('-inf')], pd.NA).dropna()  # Delete unknown future and non-finite records before binary-label construction
transfer_frame['down_t1'] = (transfer_frame['future_return_t1'] < 0).astype(int)  # Create classes only for observed future returns
transfer_train = transfer_frame[(transfer_frame['date'] <= '2022-12-31') & (transfer_frame['target_date_t1'] < '2023-01-01')]  # Purge training labels realized in test
transfer_test = transfer_frame[transfer_frame['date'] >= '2023-01-01']
assert transfer_train['target_date_t1'].max() < transfer_test['date'].min()  # Verify the label-realization boundary
transfer_features = ['return_t', 'return_5d_t', 'volatility_5d_t', 'volume_growth_t']  # Fixed Four T-Points as Available Feature
transfer_logit = make_pipeline(StandardScaler(), LogisticRegression(max_iter=2000, random_state=42)).fit(transfer_train[transfer_features], transfer_train['down_t1'])  # Use only the training period to fit scaling and Logit
transfer_probability = transfer_logit.predict_proba(transfer_test[transfer_features])[:, 1]  # Generate Probability for fixed Test Period
Code
threshold_output = []  # Collect Default Threshold and Cost Threshold Results
for probability_threshold in [0.5, 0.2]:  # Compare 0.2 under calibrated probabilities, 4:1 error costs, and zero correct-decision costs
    transfer_prediction = transfer_probability >= probability_threshold  # Convert Same Probability to Category Decision
    threshold_matrix = confusion_matrix(transfer_test['down_t1'], transfer_prediction, labels=[0, 1])  # Fixed Four-Lattice Matrix as Categorical Sequence
    threshold_output.append({'threshold': probability_threshold, 'average_precision': average_precision_score(transfer_test['down_t1'], transfer_probability), 'precision': precision_score(transfer_test['down_t1'], transfer_prediction, zero_division=0), 'recall': recall_score(transfer_test['down_t1'], transfer_prediction), 'tn': threshold_matrix[0, 0], 'fp': threshold_matrix[0, 1], 'fn': threshold_matrix[1, 0], 'tp': threshold_matrix[1, 1]})  # Save all requested metrics with the estimator named explicitly
pd.DataFrame(threshold_output)  # Show the true cost trade-off between the two thresholds
Table 3
threshold average_precision precision recall tn fp fn tp
0 0.5 0.543929 0.532468 0.484252 121 108 131 123
1 0.2 0.543929 0.525880 1.000000 0 229 0 254

Hengrui Transfer Result: AP and Operating Points Answer Different Questions

  • Executed AP (average precision) is 0.543929; it is not the trapezoidal area under the empirical PR curve.

  • At 0.5, precision/recall are 0.532468/0.484252 and the matrix is \([[121,108],[131,123]]\).

  • At 0.2, precision/recall are 0.525880/1.000000 and the matrix is \([[0,229],[0,254]]\), so every observation is predicted as decline.

  • The test set has 483 observations; the last feature date is 2024-12-30, and unknown future labels are removed before integer conversion.

  • Threshold 0.2 depends on calibrated probabilities, 4:1 error costs, and zero correct-decision costs; choose it on validation data rather than treating it as universal or causal.

Formative Check 3: SMOTE Leakage

Is it valid to apply SMOTE to all data and split afterward?

Answer: No. Synthetic points would use future test neighbors. Apply SMOTE only inside each training fold; validation/test distributions remain untouched.

Sources and Further Reading

  • Hoerl & Kennard (1970), ridge regression; Tibshirani (1996), lasso.
  • Cortes & Vapnik (1995), support-vector networks.
  • Chawla et al. (2002), SMOTE.
  • Data: local pre-adjusted A-share data; file, key, fields, period, and split are stated above.

Chapter Summary: A Unified View of Linear Models

Optional topic

after Core, optionally enter SVM/multiclass methods or SMOTE; each branch links back to Core.

We’ve explored the entire ‘family’ of linear models, but they all share a unified underlying philosophy:

  1. Core Engine: Every model starts with the linear function \(\mathbf{w}^T\mathbf{x} + b\).
  2. Task Adaptation:
    • Regression: Use the linear output directly.
    • Classification: Map the output to probabilities using Sigmoid/Softmax.
    • SVM: Focus on the geometric margin around the output.
  3. Optimization Goal: Learn the optimal weights \(\mathbf{w}\) by defining different loss functions and regularization terms.
    • Loss Functions: Mean Squared Error, Cross-Entropy, Hinge Loss (SVM).
    • Regularization: L1 and L2 norms.

The Linear Model Family at a Glance

This diagram summarizes the models we’ve discussed, showing how different combinations of loss functions and regularization penalties lead to different models.

The Linear Model Family A conceptual map showing how linear regression, logistic regression, SVM, Ridge, and Lasso are all derived from a core linear predictor combined with different loss functions and regularizers. Core predictor · wᵀx + b MSE loss Cross-entropyloss Hinge lossmargin Linearregression Logisticregression Support-vectormachine L2 penaltyRidge L1 penaltyLasso

Thank You!

Q & A