01 Foundations of Machine Learning

90-Minute Main Lesson: From Task to Out-of-Sample Evidence

  • Objectives: Define \((X,y)\) and the forecast time; split train/validation/test chronologically; choose metrics from error costs; explain loss, gradient, and learning rate.

  • learning path:

    • Foundations: prerequisite and task framing 10 min → representation and learning types 15 min → evaluation and leakage 20 min.

    • Application: loss, gradient, and learning rate 20 min → Fuyao Glass main case 15 min → exercise and feedback 10 min.

    • Advanced optimizers are an extension.

  • Answer first: What is \([2,3]\cdot[4,-1]\)? Why must test data not tune the model? Commit an answer before the reveal.

  • Feedback: The inner product is \(5\). Test-driven tuning feeds out-of-sample information back into the model and makes error optimistic. Review inner products and data splitting if either step is unclear.

The Core Question: Why Should Economists Learn Machine Learning?

Traditional econometrics and machine learning represent two different ‘cultures’ for solving problems.

  • Econometrics: The core is Causal Inference.
    • Goal: To understand ‘why’ the world works the way it does.
    • Concern: Unbiasedness and consistency of parameter estimates.
    • Example: By how much did the minimum wage increase cause a change in the unemployment rate?
  • Machine Learning: The core is Prediction.
    • Goal: To predict ‘what’ will happen in the world.
    • Concern: The model’s generalization ability on unseen data.
    • Example: Based on current macroeconomic indicators, predict next quarter’s GDP growth rate.

A Visual Contrast of the Two Cultures

The two methodologies have fundamental differences in model selection and objectives.

Econometrics vs. Machine Learning A comparative diagram showing causal inference in econometrics on the left and prediction in machine learning on the right. Econometrics Goal: Causal Inference X Treatment Y Outcome β Interpret β and causal effects Simple, easy to check models Machine Learning Goal: Accurate Prediction f(x) Input X Prediction Ŷ Reduce out-of-sample error Flexible predictive models

Why Prediction Matters to Economists

In a data-driven era, predictive power is itself a potent economic tool.

  • Financial Markets: Predicting asset prices, volatility, and credit risk.
  • Macroeconomics: Forecasting inflation, GDP growth, and unemployment to inform policy.
  • Business Decisions: Forecasting product sales, customer churn, and supply chain demand.
  • Policy Evaluation: Predicting the likely economic impact of a policy (e.g., a tax cut).

Causal inference explains the past; accurate prediction provides insight into the future. Combined, their power is multiplied.

Today’s Goal: Build a Complete Mental Framework for Machine Learning

After this chapter, you will be able to systematically understand any machine learning project from the perspective of ‘The Four Pillars’.

The Four Pillars of Machine Learning This diagram shows the four core components of machine learning: Framing the Problem, Modeling, Evaluation, and Optimization. ? 1. Frame Problem (Framing) Task f(x) 2. Define Model (Modeling) Complexity 3. Define 'Good' (Evaluation) Metric 4. Define 'Learning' (Optimization) Optimization

Pillar I: Frame the Problem (Framing)

This is the starting point for all work.

Before any technical details, you must clearly define the business problem and translate it into a specific machine learning task.

  • What are you trying to predict?
    • A continuous value (e.g., tomorrow’s stock price) \(\rightarrow\) Regression
    • A discrete category (e.g., whether a customer will default) \(\rightarrow\) Classification
  • What data do you have?
    • Does the data come with the ‘answer’ you want to predict (i.e., a label y)?
      • Yes \(\rightarrow\) Supervised Learning
      • No \(\rightarrow\) Unsupervised Learning

Pillar II: Define the Model (Modeling)

A model is essentially a mathematical function \(f(x, \theta)\) that tries to capture the relationship between input features \(x\) and the output \(y\).

  • \(x\): The input feature vector (e.g., house area, location).
  • \(\theta\): The model’s parameters. These are the values that need to be determined through ‘learning’ (e.g., coefficients in a linear regression).
  • \(f\): The form of the function. This is what we, as modelers, choose.

The range of models is vast:

  • Simple Models: Linear Regression, Logistic Regression (highly interpretable).
  • Complex Models: Random Forest, Gradient Boosting Trees, Neural Networks (powerful prediction).

Pillar III: Define ‘Good’ (Evaluation)

How do we objectively measure how good a model is? We need an evaluation metric.

  • This metric must reflect the business objective.
  • During model development, calculate it on validation data; after choosing the final model, report it once on test data untouched by selection.

Common Evaluation Metrics:

  • Regression Tasks:
    • Mean Squared Error (MSE)
    • R-squared (R²)
  • Classification Tasks:
    • Accuracy
    • Precision, Recall, F1-Score

Pillar IV: Define ‘Learning’ (Optimization)

The process of ‘learning’ is the process of automatically finding the best parameters \(\theta\).

  1. We first define a Loss Function \(J(\theta)\), which measures how bad the model’s predictions are with the current parameters \(\theta\). The smaller the loss, the better the model.

  2. Then, we use an Optimizer, such as Gradient Descent, to systematically and iteratively adjust the parameters \(\theta\) to find the set of values \(\theta^*\) that minimizes the loss function \(J(\theta)\).

\[ \large \theta^* = \arg\min_{\theta} J(\theta) \]

What is Machine Learning? Learning Functions from Data

The essence of Machine Learning (ML) is to have a computer automatically learn a function from data, rather than through explicit programming, where this function can make predictions on unknown data.

Fundamental Machine Learning Workflow A diagram showing the ML workflow: a learning algorithm uses training data and a performance metric to produce a predictive model, which then makes predictions on new data. Fundamental ML Workflow Training Data (D) Performance Metric (P) Learning Algorithm (A) Predictive Model f(x) New Data (x) Prediction (ŷ)

Data Representation in ML: Everything is a Vector

In machine learning, we need to convert real-world objects into a language computers understand—numbers.

  • Dataset: A collection of N samples \(X = \{x_1, x_2, \dots, x_N\}\).
  • Sample: A single data point (a house, a customer).
  • Feature: A dimension describing a sample (area, number of bedrooms).
  • Feature Vector: A vector of all features for one sample \(x = (x_{\text{area}}, x_{\text{bedrooms}}, \dots)^T\).
  • Label: The target value we want to predict, y (house price).

From the Real World to Mathematical Objects

This transformation process is at the heart of data preprocessing.

Data Vectorization This diagram shows how a tabular dataset is converted into a feature matrix X and a label vector Y for machine learning. 1. Raw Data (m², $10k) Area Beds Zone Price 120 3 Zone A 500 85 2 Zone B 320 ... 200 4 Zone A 850 N samples Vectorize 2. ML Representation Features X [120 3 1 0] [ 85 2 0 1] ... [200 4 1 0] N × d Target y [500] [320] ... [850] N × 1

A Sample = A Point in d-Dimensional Space

Once we represent samples as feature vectors, each sample can be viewed as a point in a d-dimensional feature space.

This provides a geometric foundation for understanding machine learning algorithms.

Data Samples in 2D Feature Space A plot showing two data points in a 2D space defined by 'Feature 1 (Area)' and 'Feature 2 (Bedrooms)'. Feature 1 (Area) Feature 2 (Bedrooms) 0 1 2 3 4 0 100 200 Sample 1 Sample 2

Case Study: Feature Vectors from Local A-Share Data

Use the local pre-adjusted daily prices of Jiangsu Hengrui Pharmaceuticals (600276.XSHG). One sample contains today’s close and volume; the next trading day’s close is the label.

Trading date Pre-adjusted close Volume (shares) Next-trading-day close \(y\)
2023-01-03 37.9796 25,756,493 38.3056
2023-01-04 38.3056 25,766,800 39.0763
  • Sample: one row represents one trading day.

  • Feature vector: \(x_t=(\text{close}_t,\text{volume}_t)^T\), a point in two-dimensional space.

  • Label: \(y_t=\text{close}_{t+1}\); preserve chronological alignment and never leak it into the features.

  • Data used in this example: data/stock/stock_price_pre_adjusted.h5, key data, fields close, volume; prices follow the pre-adjusted-price convention and volume is in shares.

  • The displayed values are selectively read from that local data.

The Three Main Categories of Machine Learning

Based on the data we have (especially whether we have the label y), machine learning tasks can be divided into three main categories.

  1. Supervised Learning
  2. Unsupervised Learning
  3. Reinforcement Learning

We will introduce them one by one.

Category 1: Supervised Learning

Used when the data comes with clear ‘answers’ or ‘labels’.

Supervised Learning Workflow A flowchart of the supervised learning process: labeled data is used to train a model, which then makes predictions on new, unlabeled data. Supervised Learning Workflow 1 · Labeled data 2 · Train 3 · Predict Dataset D D = {(xᵢ, yᵢ)}i = 1, …, N Cat image“cat” Dog image“dog” Model f learns X → Y New data x_new Output ŷ f ŷ = f(x_new)

Unsupervised Learning

Used when data has no ‘answers’, and we want to discover its internal structure.

Unsupervised Learning: Clustering A diagram illustrating the process of unsupervised learning, where an algorithm finds hidden structures (clusters) in unlabeled data. Unsupervised Learning Unlabeled input Clustering algorithm Discovered structure

Category 3: Reinforcement Learning

Used when we need to learn an optimal strategy through ‘trial and error’ with an environment.

Reinforcement Learning Loop A diagram showing the reinforcement learning cycle: an agent takes an action, the environment returns a new state and a reward, and the agent uses this feedback to learn an optimal policy. Reinforcement Learning Agent Environment Action Aₜ State Sₜ₊₁, Reward Rₜ₊₁ Data: interaction trajectories Goal: maximize discounted return Examples: games · robotics · trading

Focusing on Supervised Learning: Regression vs. Classification

The vast majority of tasks in economics and business fall under supervised learning. It can be further divided into two major tasks based on the type of the label y.

  • Regression:
    • Goal: Predict a continuous numerical value.
    • Output: \(y \in \mathbb{R}\)
    • Examples: Predicting GDP growth rate, company sales figures.
  • Classification:
    • Goal: Predict a discrete category.
    • Output: \(y \in \{C_1, C_2, \dots, C_K\}\)
    • Examples: Determining if a customer will churn, if a transaction is fraudulent.

Geometric Intuition of Regression and Classification

Supervised Learning: Regression vs. Classification A side-by-side comparison of regression, which fits a line to continuous data, and classification, which finds a boundary to separate discrete classes. Supervised Learning: Regression vs. Classification Regression Predicting a continuous value Continuous Target Feature Best-Fit Line Classification Predicting a discrete class Feature 2 Feature 1 Decision Boundary

Pillar III: How to Evaluate if a Model is Good?

How do we know if the model we trained, \(f(x; \theta)\), is a ‘good’ model?

Core principle

Fit parameters on training data, choose features, hyperparameters, and stopping points on validation data, then perform one final generalization check on an untouched test period after the workflow is fixed.

  • This leads to a simple practice: use training and validation data to make modeling choices, and save the test data for one final check.

  • A train/test split is enough only when every modeling choice is made before the test results are viewed.

Keep Training, Validation, and Test Data Separate

Use earlier observations for training and validation. Keep the later test period out of every model-selection decision.

Separate training, validation, and test data The full dataset is split into training, validation, and test periods. Modeling choices use training and validation, while the test period is used once at the end. Full Dataset Use 80% Set aside 20% Model choices Train 60% Validate 20% Final test Open once Fit, validate, choose Check performance on new data

Why Must We Split? The Ghost of Overfitting

Overfitting occurs when a model learns the training data “too well,” to the point that it memorizes the noise and random fluctuations in the data as if they were general patterns.

  • Symptom: Performs extremely well on the training set, but very poorly on the test set.
  • Cause: The model is too complex, with too much freedom relative to the amount of data.

Validation is the mock exam used to improve; the test set is a held-out final opened once. Changing the model after seeing it turns it into another validation set.

Cornerstone of Classification Evaluation: The Confusion Matrix

For binary classification problems (e.g., predicting customer default), all evaluation metrics derive from a simple table: the Confusion Matrix.

Predicted Positive Predicted Negative
Actual Positive True Positive (TP) False Negative (FN)
Actual Negative False Positive (FP) True Negative (TN)
  • Positive: The event we care about, like ‘default’ or ‘fraud’.
  • Negative: The other case, like ‘no default’.
  • True/False: Refers to whether the prediction was correct.

Understanding the Four Quadrants of the Confusion Matrix

  • TP (True Positive): Correct prediction, the customer did default. (Hit)
  • TN (True Negative): Correct prediction, the customer did not default. (Correct Rejection)
  • FP (False Positive): Incorrect prediction, predicted default, but they didn’t. (False Alarm, Type I Error)
  • FN (False Negative): Incorrect prediction, predicted no default, but they did. (Miss, Type II Error)

In fields like financial risk management, the cost of an FN (missing a bad customer) is often far greater than the cost of an FP (misjudging a good customer).

Classification Metric (1): Accuracy

Accuracy measures the proportion of total samples that the model predicted correctly.

\[ \large \begin{aligned} \text{Accuracy} &= \frac{\text{Number of Correct Predictions}}{\text{Total Number of Samples}} \\ &= \frac{TP + TN}{TP + TN + FP + FN} \end{aligned} \]

Advantage: Very intuitive and easy to understand.

Disadvantage: Highly misleading on imbalanced datasets.

The Accuracy Trap: An Example

Imagine a credit card fraud detection scenario:

  • Total transactions: 10,000
  • Normal transactions: 9,990 (99.9%)
  • Fraudulent transactions: 10 (0.1%)

How does a ‘lazy’ model that predicts all transactions as ‘normal’ perform?

  • TP = 0, TN = 9990
  • FP = 0, FN = 10
  • Accuracy = (0 + 9990) / 10000 = 99.9%

This model has extremely high accuracy but is completely useless, as it fails to identify a single case of fraud.

Classification Metric (2): Precision

Precision measures the proportion of all samples predicted as positive that are actually positive.

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

  • Business Meaning: ‘Of all the fraud alerts I raised, how many were real?’
  • Focus: The purity of the predictions. High precision means fewer false alarms (FP).

Precision Diagram: The Intersection Contains True Positives

Precision Illustrated A Venn diagram explaining the concept of precision, highlighting the intersection of predicted positive and actual positive sets. Predicted Positive (TP + FP) Actual Positive (TP + FN) FP TP FN

Classification Metric (3): Recall

Recall measures the proportion of all actual positive samples that we successfully identified.

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

  • Business Meaning: ‘Of all the actual fraud cases that occurred, how many did my model catch?’
  • Focus: How complete the search is. High recall means fewer misses (FN).

Recall Diagram: How Many Actual Positives Were Found

Recall Illustrated A Venn diagram explaining the concept of recall, focusing on the proportion of actual positives that were correctly identified. FP TP FN Predicted Positive (TP+FP) Actual Positive (TP+FN)

Precision vs. Recall: An Eternal Trade-off

For a fixed scoring model, threshold changes often produce an empirical precision–recall trade-off, but precision is not monotone in the threshold.

  • Lower the threshold:
    • the predicted-positive set can only expand, so TP and FP counts cannot decrease and recall cannot fall.

    • If the added cases are mostly true positives, however, precision may fall, stay flat, or rise.

  • Raise the threshold: the predicted-positive set can only shrink, so TP and FP counts cannot increase and recall cannot rise. Precision is still not guaranteed to move monotonically.

Empirical PR curves are therefore stepwise and may locally improve in both coordinates. Select the threshold from validation-period business costs, not from a mechanical inverse rule.

Business Decision

We need to decide which balance point to choose in this trade-off based on the different business costs of FPs and FNs.

Visualizing the Precision-Recall Trade-off

Precision-Recall Tradeoff A curve showing the inverse relationship between precision and recall. As one increases, the other tends to decrease, depending on the model's decision threshold. Precision-Recall Tradeoff Precision Recall A: High Threshold (High P, Low R) B: Low ThresholdLow P, High R

Classification Metric (4): F1-Score

To balance precision and recall, we use the F1-Score, which is their harmonic mean.

\[ \large F_1 = 2 \cdot \frac{\text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}} \]

  • The F1-Score will only be high if both precision and recall are both relatively high.
  • If one of the metrics is low, the F1-Score will also be pulled down.
  • It is a more robust single evaluation metric than accuracy on imbalanced datasets.

Mechanism Demo: Metrics from Fixed Counts (1/2)

Let’s use a hypothetical credit default prediction example to demonstrate how to calculate these metrics.

Code
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd  # Report fixed count metrics with a named sequence
import numpy as np
y_true = np.array([0]*950 + [1]*50)
y_pred = np.array([0]*940 + [1]*10 + [0]*20 + [1]*30)
probability_value = np.random.permutation(len(y_true))
y_true, y_pred = y_true[probability_value], y_pred[probability_value]
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred, zero_division=0)
recall = recall_score(y_true, y_pred, zero_division=0)
f1 = f1_score(y_true, y_pred, zero_division=0)
cm = confusion_matrix(y_true, y_pred)
pd.Series({  # Report metrics implied by the fixed counts.
    'accuracy': accuracy, 'precision': precision, 'recall': recall, 'f1': f1,
    'tn': cm[0, 0], 'fp': cm[0, 1], 'fn': cm[1, 0], 'tp': cm[1, 1]
})
Table 1
accuracy       0.970000
precision      0.750000
recall         0.600000
f1             0.666667
tn           940.000000
fp            10.000000
fn            20.000000
tp            30.000000
dtype: float64

Mechanism Demo: Confusion Matrix from Fixed Counts (2/2)

Code
fig, ax = plt.subplots(figsize=(6, 4.5))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
            xticklabels=['No\ndefault', 'Default'],
            yticklabels=['No\ndefault', 'Default'], ax=ax, annot_kws={'size': 34})
ax.collections[0].colorbar.ax.tick_params(labelsize=36)  # Keep colorbar ticks projection-legible after Reveal scaling.
ax.set_ylabel('Actual', fontsize=32)
ax.set_xlabel('Predicted', fontsize=32)
ax.set_title('Confusion Matrix', fontsize=34)
ax.tick_params(axis='both', labelsize=32)
plt.show()  # 展示当前步骤的结果。
Confusion-matrix heatmap with 940 true negatives, 10 false positives, 20 false negatives, and 30 true positives
Figure 1: Teaching illustration: confusion matrix from fixed counts

Regression Metric: Mean Squared Error (MSE)

For regression tasks (predicting continuous values), the most common evaluation metric is the Mean Squared Error (MSE).

\[ \large \text{MSE} = \frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y}_i)^2 \]

  • \(y_i\) is the true value for sample \(i\).
  • \(\hat{y}_i\) is the model’s prediction for sample \(i\).
  • \((y_i - \hat{y}_i)\) is the residual.

MSE calculates the average of the squared residuals. Because it uses squares, it penalizes large errors more heavily.

Visualizing Mean Squared Error (MSE)

Mean Squared Error Visualization A plot showing a regression line and data points. The residuals (errors) are shown as dashed lines, and the squared errors are represented as squares, illustrating that larger residuals contribute more to the total error. Mean Squared Error MSE penalizes large errors more heavily Prediction ŷ Observed y Residual (y - ŷ) Squared residual (y - ŷ)²

The Essence of Learning: Optimization

We’ve defined the model and evaluation criteria, but how does a machine actually ‘learn’? The essence of learning is an Optimization process.

  1. We define a Loss Function \(J(\theta)\), which measures how bad the model’s predictions are on the training set with the current parameters \(\theta\).
  • The lower the loss function’s value, the better the model performs.
  1. The goal of ‘learning’ is to find a set of parameters \(\theta^*\) that minimizes the loss function \(J(\theta)\).

For regression problems, MSE is the most commonly used loss function.

Loss Function: The ‘Navigation Map’ for Optimization

The loss function \(J(\theta)\) describes a ‘topographical map’, where the altitude is the loss value. Our goal is to start from a random point and walk to the lowest valley in this terrain.

Code
fig = plt.figure(figsize=(9, 6))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(input_feature_matrix, target_grid_values, transformed_feature_matrix, cmap='viridis', edgecolor='none', alpha=0.85, rstride=2, cstride=2)
global_min_value = loss_function_2d(2, 3)
local_min_value = loss_function_2d(-0.5, -0.5)
ax.scatter(2, 3, global_min_value, color='red', s=120, zorder=10, depthshade=False)
ax.scatter(-0.5, -0.5, local_min_value, color='orange', s=120, zorder=10, depthshade=False)
ax.set_title(title_text, fontsize=48)
ax.set_xlabel(xlabel_text, fontsize=42, labelpad=12)
ax.set_ylabel(ylabel_text, fontsize=42, labelpad=12)
ax.set_zlabel(zlabel_text, fontsize=42, labelpad=12)
ax.tick_params(labelsize=40)
ax.set_xticks([-1, 2, 5])
ax.set_yticks([-1, 2, 5])
ax.set_zticks([0, 10, 20])
ax.view_init(elev=30., azim=120)
fig.canvas.draw()
global_x, global_y, _ = proj3d.proj_transform(2, 3, global_min_value, ax.get_proj())
local_x, local_y, _ = proj3d.proj_transform(-0.5, -0.5, local_min_value, ax.get_proj())
annotation_box = dict(boxstyle='round,pad=0.18', facecolor='white', edgecolor='none', alpha=0.92)
annotation_arrow = dict(arrowstyle='-', color='#555555', linewidth=2.5)
ax.annotate(global_min_text, xy=(global_x, global_y), xytext=(-92, -64), textcoords='offset points',
            color='#A61B29', fontsize=44, ha='center', va='top', bbox=annotation_box,
            arrowprops=annotation_arrow, zorder=20)
ax.annotate(local_min_text, xy=(local_x, local_y), xytext=(76, 46), textcoords='offset points',
            color='#8A4A00', fontsize=44, ha='center', va='bottom', bbox=annotation_box,
            arrowprops=annotation_arrow, zorder=20)
fig.tight_layout()
plt.show()  # 展示当前步骤的结果。
The landscape of a loss function: Our goal is to find the global minimum.
Figure 2: The landscape of a loss function: Our goal is to find the global minimum.

Loss Function for Classification: Cross-Entropy

For classification problems, we commonly use Cross-Entropy Loss.

  • Intuitive Understanding: It measures the ‘distance’ between the probability distribution predicted by the model and the true probability distribution.
  • For binary classification: \[ \large L(\theta) = - \frac{1}{N} \sum_{i=1}^N \left[ y_i \log(\hat{y}_i) + (1-y_i) \log(1-\hat{y}_i) \right] \] where \(y_i \in \{0, 1\}\) is the true label, and \(\hat{y}_i \in (0, 1)\) is the model’s predicted probability of class 1.

This function has a nice property: when the model makes a very confident and wrong prediction, the loss becomes very large, giving the model a strong ‘penalty’ signal.

Pillar IV: Define ‘Learning’ (Optimization)

We have the map (the loss function), but how do we find the way down the mountain?

The most classic and important method is Gradient Descent.

Core Idea

  • Imagine you are on a foggy mountainside, and you can only see the small patch of ground at your feet.

  • To get down the fastest, you should take a step in the direction of the steepest descent from your current position.

Mathematically, the negative of the gradient of a function at a point is the direction in which the function’s value decreases most rapidly.

The Mathematical Principle of Gradient Descent

Gradient descent is an iterative algorithm. At each step t, it updates the parameters \(\theta\) according to the following rule:

\[ \large \theta_{t+1} = \theta_t - \eta \nabla J(\theta_t) \]

  • \(\theta_t\): The value of the parameters at step t.
  • \(\nabla J(\theta_t)\): The gradient of the loss function \(J\) at \(\theta_t\). It is a vector pointing in the direction of the fastest increase in the function’s value.
  • \(\eta\): The Learning Rate, a hyperparameter that controls how far we step each time.
  • \(-\eta \nabla J(\theta_t)\): We take a small step in the direction opposite to the gradient.

We repeat this process until the parameters converge.

Visualizing Gradient Descent

Gradient Descent Optimization Path A contour plot showing the path of gradient descent, starting from an initial point and iteratively moving towards the minimum of the loss function. Minimum θ* Start θ₀ θ₁ θ₂ -η∇J(θ₀)

The Learning Rate (η): Determining Optimization Speed and Success

Code
def gradient_path(learning_rate, step_count):  # Calculate Gradient Descent Path for a Given Learning Rate
    current_parameter = -1.8  # Fixed Common Origin of Three Paths
    parameter_path = [current_parameter]  # Save Parameter Locations Per Step
    loss_path = [current_parameter**2]  # Save Secondary Losses Per Step
    for gradient_step_index in range(step_count):  # Perform Gradient Update at Specified Steps
        current_parameter -= learning_rate * (2 * current_parameter)  # Moving the parameter along the negative gradient
        parameter_path.append(current_parameter)  # Record Updated Parameters
        loss_path.append(current_parameter**2)  # Record Updated Losses
    return parameter_path, loss_path  # Returns a path that can be drawn directly
learning_axis = np.linspace(-2, 2, 400)  # Prepare common parameter axes
learning_loss = learning_axis**2  # Calculate the common quadratic loss curve
small_path = gradient_path(.15, 10)  # Pre-Calculated Path with Excessive Learning Rate
good_path = gradient_path(.8, 5)  # Path to pre-calculate moderate learning rate
large_path = gradient_path(1.02, 5)  # Pre-Calculated Path with Excessive Learning Rate
Code
def plot_learning_rate_analogy():  # 定义当前教学案例所需的函数。
    fig, axs = plt.subplots(1, 3, figsize=(14, 3.4), sharey=True); fig.suptitle('The Impact of Learning Rate (η)', fontsize=28)
    ax1 = axs[0]
    ax1.plot(learning_axis, learning_loss, color='#0d6efd')
    path_x, path_y = small_path
    ax1.plot(path_x, path_y, 'o-', color='#dc3545', markersize=5, mfc='white', mew=1.5)
    ax1.set_title('η Too Small:\nSlow Convergence', fontsize=22); ax1.set_xlabel('θ', fontsize=24); ax1.set_ylabel('J(θ)', fontsize=24)
    ax2 = axs[1]
    ax2.plot(learning_axis, learning_loss, color='#0d6efd')
    path_x, path_y = good_path
    ax2.plot(path_x, path_y, 'o-', color='#198754', markersize=5, mfc='white', mew=1.5)
    ax2.set_title('η Just Right:\nEfficient Convergence', fontsize=22); ax2.set_xlabel('θ', fontsize=24)
    ax3 = axs[2]
    ax3.plot(learning_axis, learning_loss, color='#0d6efd')
    path_x, path_y = large_path
    ax3.plot(path_x, path_y, 'o-', color='#ffc107', markersize=5, mfc='white', mew=1.5)
    ax3.set_title('η Too Large:\nOvershooting / Divergence', fontsize=22); ax3.set_xlabel('θ', fontsize=24)
    # Iterate over `axs` to create comparable validation evidence item by item.
    for ax in axs:  # 遍历当前教学对象以完成重复计算。
        ax.spines[['top', 'right']].set_visible(False)
        ax.set_ylim(-0.5, 4)
        ax.tick_params(axis='both', labelsize=22)
        ax.grid(True, linestyle='--', alpha=0.6)
    plt.tight_layout(rect=[0, 0, 1, 0.94])  # 展示当前步骤的结果。
    plt.show()  # 展示当前步骤的结果。
plot_learning_rate_analogy()
The impact of the learning rate (η) on the gradient descent process
Figure 3: The impact of the learning rate (η) on the gradient descent process

Takeaway: Too small stalls; too large overshoots; validate a stable middle range.

Variants of Gradient Descent: Handling Large-Scale Data

When our training set is very large, computing the gradient over the entire dataset becomes very time-consuming. For this reason, variants of gradient descent have been developed.

Comparison of Gradient Descent Variant Paths Compares the optimization paths of Batch Gradient Descent (BGD), Stochastic Gradient Descent (SGD), and Mini-batch Gradient Descent (MBGD). Convergence Paths of Different Gradient Descent Algorithms Start End BGD (smooth) SGD (noisy) Mini-batch

Comparison of Gradient Descent Variants

Type Gradient Calculation Method Advantages Disadvantages
Batch GD (BGD) Uses all training samples Accurate gradient, smooth convergence High computational cost, slow
Stochastic GD (SGD) Uses one randomly picked sample Fast, can escape local minima High variance in updates, noisy path
Mini-batch GD (MBGD) Uses a small batch of samples (e.g., 32) Combines benefits of BGD and SGD, the default choice Requires tuning batch size

Main lesson: advanced optimizers are Extension; continue directly to the Fuyao Glass main case.

Advanced Optimizers: Making the Descent Smarter

Optional topic: after the learning-rate check, the 90-minute Core goes directly to the Fuyao Glass main case. Return here only after the principal exercise and summary, then continue to the final summary.

Basic gradient descent can struggle in complex loss landscapes. In modern deep learning, we use more advanced optimizers.

  • Momentum
    • Idea: Simulates momentum from physics. The update considers not only the current gradient but also the previous update direction, like a ball rolling down a hill.
    • Effect: Helps the algorithm “power through” flat regions and local minima, accelerating convergence.
  • Adam (Adaptive Moment Estimation)
    • Idea: Combines momentum with adaptive learning rates (adjusting the learning rate independently for each parameter).
    • Effect: Performs well across a wide range of tasks and is often the go-to default optimizer.

For beginners: Using the Adam optimizer directly will often yield excellent results.

Retrieval Check Before the Main Case

Retrieve the opening objectives: express a business question as \((X,y)\) and a prediction time; make chronological train/validation/test splits; choose metrics from error costs; and relate loss, gradient, and learning rate.

  • Check: What is the dot product of \([2,3]\) and \([4,-1]\)? Why must the test set not tune the model?
  • Answer: \(2\times4+3\times(-1)=5\). Test-set tuning feeds out-of-sample information back into development and makes reported generalization error optimistic.

Formative Check 1: Define the Task First

At the close of day \(t\), use information available by then to predict Fuyao Glass’s next-day return. Which label is correct?

  • A. \(r_t\) B. \(r_{t+1}\) C. day-\(t\) volume D. full-sample mean

Answer: B. Features are known at \(t\) and the label is future \(r_{t+1}\); using \(r_{t+1}\) as a feature would be look-ahead leakage.

Main Case: Fuyao Glass Next-Day Return

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

    • Scope: 2018-01-01 to 2024-12-31; close is pre-adjusted price and volume is shares.

    • Split: the first 60%, middle 20%, and last 20% form chronological train, validation, and held-out test periods.

  • Nearby method source: scikit-learn model-evaluation guide; the code operationalizes it as a strict time split and out-of-sample MSE.
Code
from pathlib import Path  # Locate the downloaded data file

import pandas as pd  # Read the local HDF5 data into a table
from sklearn.linear_model import LinearRegression  # Use linear regression to establish interpretable benchmarks
from sklearn.metrics import mean_squared_error  # Evaluate a continuous prediction with a out-of-sample mean squared error
# 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
model_frame = price_rows.reset_index().sort_values('date')  # Restore Date Columns and Guarantee Chronology
model_frame['return_t'] = model_frame['close'].pct_change()  # Calculate daily returns from pre-adjusted closing prices
model_frame['volume_growth_t'] = model_frame['volume'].pct_change()  # Construct Volume Growth Characteristics
model_frame['target_return_t1'] = model_frame['return_t'].shift(-1)  # Define the next-trading-day return target
model_frame['target_date_t1'] = model_frame['date'].shift(-1)  # Preserve the label-realization date for boundary purging
model_frame = model_frame.replace([float('inf'), float('-inf')], pd.NA).dropna()  # Remove non-finite observations created by transformations
Code
train_end = int(len(model_frame) * 0.6)  # Fixed First Sixty Percent as Training Period
validation_end = int(len(model_frame) * 0.8)  # Fixed 20% Validation Period
validation_start_date = model_frame.iloc[train_end]['date']
test_start_date = model_frame.iloc[validation_end]['date']
train_rows = model_frame[(model_frame['date'] < validation_start_date) & (model_frame['target_date_t1'] < validation_start_date)]  # Purge training labels realized in validation
validation_rows = model_frame[(model_frame['date'] >= validation_start_date) & (model_frame['date'] < test_start_date) & (model_frame['target_date_t1'] < test_start_date)]  # Purge validation labels realized in test
test_rows = model_frame[model_frame['date'] >= test_start_date]  # Keep the final window held-out
assert train_rows['target_date_t1'].max() < validation_rows['date'].min() and validation_rows['target_date_t1'].max() < test_rows['date'].min()  # Verify label-realization boundaries
feature_names = ['return_t', 'volume_growth_t']  # Clarify the set of information available at time t
return_model = LinearRegression().fit(train_rows[feature_names], train_rows['target_return_t1'])  # estimate model only on training period
validation_prediction = return_model.predict(validation_rows[feature_names])  # Evaluate the current benchmark during the validation period without touching the test period
pd.Series({'validation_mse': mean_squared_error(validation_rows['target_return_t1'], validation_prediction), 'train_end': train_rows['date'].max(), 'validation_start': validation_rows['date'].min(), 'test_start': test_rows['date'].min()})  # Report development evidence and the held-out test boundary
validation_mse                 0.000318
train_end           2022-03-14 00:00:00
validation_start    2022-03-16 00:00:00
test_start          2023-08-07 00:00:00
dtype: object

Formative Check 2: Evaluate the Evidence

If defaults are 2% and a model predicts “no default” for everyone, what is accuracy, and is the model useful?

Answer

Accuracy is 98%, but default recall is zero. When false negatives are costly, report recall, precision, PR-AUC, and the confusion matrix rather than accuracy alone.

Step-by-Step Exercise: Add a Second Lag

  • Task: Add return_t2 = return_t.shift(1), keep the same split, compare validation MSE, choose one feature set, refit on train+validation, and evaluate the test period once.
  • Complete solution:
    • Add the lag before dropna() and use only validation MSE to choose the baseline or extended features.

    • Keep the three time-window boundaries fixed, do not choose from test results, and calculate test MSE only once after choosing the features.

Code
from sklearn.linear_model import LinearRegression  # Reuse the same linear benchmark to isolate the impact of newly added lagging items
from sklearn.metrics import mean_squared_error  # Compare two sets of features with a fixed test period mean square error
lag_answer = model_frame.copy()  # Create a Copy of Answers from Post-Cleaning Data of Primary Practice
lag_answer['return_t2'] = lag_answer['return_t'].shift(1)  # Adding a second lagged return known at time t
lag_answer = lag_answer.dropna()  # Drop the first row made unavailable by the added lag
fixed_train_end = train_rows['date'].max()
fixed_validation_end = validation_rows['date'].max()
lag_train = lag_answer[lag_answer['date'] <= fixed_train_end]  # keep original training period unchanged
lag_validation = lag_answer[(lag_answer['date'] > fixed_train_end) & (lag_answer['date'] <= fixed_validation_end)]  # select only in middle window
lag_test = lag_answer[lag_answer['date'] > fixed_validation_end]  # Last Window Remains Archived During Selection
baseline_features = ['return_t', 'volume_growth_t']  # Define the original benchmark information set
extended_features = ['return_t', 'return_t2', 'volume_growth_t']  # Define the lagging information set
baseline_fit = LinearRegression().fit(lag_train[baseline_features], lag_train['target_return_t1'])  # Re-Fit Benchmark on Fixed Training Period
extended_fit = LinearRegression().fit(lag_train[extended_features], lag_train['target_return_t1'])  # Fit Extended Model on Same Training Period
baseline_val_mse = mean_squared_error(lag_validation['target_return_t1'], baseline_fit.predict(lag_validation[baseline_features]))  # Evaluate Benchmark with Validation Period
extended_val_mse = mean_squared_error(lag_validation['target_return_t1'], extended_fit.predict(lag_validation[extended_features]))  # Evaluate the extended model with the same validation period
selected_features = extended_features if extended_val_mse < baseline_val_mse else baseline_features
lag_development = lag_answer[lag_answer['date'] <= fixed_validation_end]  # Merging Training and Validation Periods for Final Fit
final_fit = LinearRegression().fit(lag_development[selected_features], lag_development['target_return_t1'])  # Re-fit after lockout
final_test_mse = mean_squared_error(lag_test['target_return_t1'], final_fit.predict(lag_test[selected_features]))  # Only check Archive Test Period
pd.Series({'baseline_validation_mse': baseline_val_mse, 'extended_validation_mse': extended_val_mse, 'selected_features': ', '.join(selected_features), 'final_test_mse': final_test_mse, 'test_start': lag_test['date'].min()})  # Clearly distinguishing the selection evidence from the final check
Table 2
baseline_validation_mse                                0.000323
extended_validation_mse                                0.000323
selected_features          return_t, return_t2, volume_growth_t
final_test_mse                                         0.000252
test_start                                  2023-08-04 00:00:00
dtype: object

Apply It to a New Case

  • Replace the firm with Jiangsu Hengrui Pharmaceuticals 600276.XSHG; use 2018–2021 for training, 2022 for validation, and 2023–2024 as held-out test; then add five-day volatility.

  • Submit candidate validation MSEs, the fixed model’s one test MSE, a residual plot, and a 150-word limitation.

Complete-answer reminder

use a chronological three-period split, report fields, units and sample size, make choices only with training and validation data, evaluate the test period once, interpret residuals, and state that predictive association is not causation.

New Data: Choose on Validation, Evaluate Once on Test

Table 3
Code
from pathlib import Path  # Locate the downloaded data file

import pandas as pd  # Read and Organize Local Real A-Shares Quotes
from sklearn.linear_model import LinearRegression  # Establish explainable yield forecast baseline
from sklearn.metrics import mean_squared_error  # Compare two sets of models during the fixed test period
# 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")
transfer_path = Path("/home/ubuntu/r2_data_mount/data/stock/stock_price_pre_adjusted.h5")
transfer_rows = pd.read_hdf(transfer_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 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()  # Construct daily return features
transfer_frame['volume_growth_t'] = transfer_frame['volume'].pct_change()  # Compute one-day volume growth
transfer_frame['volatility_5d_t'] = transfer_frame['return_t'].rolling(5).std()  # Use only the historical five-day yield to estimate the volatility
transfer_frame['target_return_t1'] = transfer_frame['return_t'].shift(-1)  # keep next-trading-day return target
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 records that are not available for prediction or evaluation
transfer_train = transfer_frame[(transfer_frame['date'] <= '2021-12-31') & (transfer_frame['target_date_t1'] < '2022-01-01')]  # Purge training labels realized in validation
transfer_validation = transfer_frame[(transfer_frame['date'] >= '2022-01-01') & (transfer_frame['date'] <= '2022-12-31') & (transfer_frame['target_date_t1'] < '2023-01-01')]  # Purge validation labels realized in test
transfer_test = transfer_frame[transfer_frame['date'] >= '2023-01-01']
assert transfer_train['target_date_t1'].max() < transfer_validation['date'].min() and transfer_validation['target_date_t1'].max() < transfer_test['date'].min()  # Verify label-realization boundaries
transfer_baseline_features = ['return_t', 'volume_growth_t']  # Define the benchmark information set without volatility
transfer_extended_features = transfer_baseline_features + ['volatility_5d_t']  # Only Extend One Historical Volatility Feature
Code
transfer_baseline = LinearRegression().fit(transfer_train[transfer_baseline_features], transfer_train['target_return_t1'])  # Fit Benchmark on Full Training Period
transfer_extended = LinearRegression().fit(transfer_train[transfer_extended_features], transfer_train['target_return_t1'])  # Fit Extended Model on Same Training Period
transfer_baseline_val_mse = mean_squared_error(transfer_validation['target_return_t1'], transfer_baseline.predict(transfer_validation[transfer_baseline_features]))  # Record the baseline validation error
transfer_extended_val_mse = mean_squared_error(transfer_validation['target_return_t1'], transfer_extended.predict(transfer_validation[transfer_extended_features]))  # Record Extended Model Validation Error
transfer_selected_features = transfer_extended_features if transfer_extended_val_mse < transfer_baseline_val_mse else transfer_baseline_features
transfer_development = pd.concat([transfer_train, transfer_validation])
transfer_final = LinearRegression().fit(transfer_development[transfer_selected_features], transfer_development['target_return_t1'])
transfer_prediction = transfer_final.predict(transfer_test[transfer_selected_features])  # Only Predict Archive Test Period Once
transfer_residual = transfer_test['target_return_t1'].to_numpy() - transfer_prediction  # Calculate Residual Difference for Diagnostic Graph Use
pd.Series({'train_n': len(transfer_train), 'validation_n': len(transfer_validation), 'test_n': len(transfer_test), 'baseline_validation_mse': transfer_baseline_val_mse, 'extended_validation_mse': transfer_extended_val_mse, 'selected_features': ', '.join(transfer_selected_features), 'final_test_mse': mean_squared_error(transfer_test['target_return_t1'], transfer_prediction)})  # Strictly Separate Selected Evidence from Test check
Table 4
train_n                                                           967
validation_n                                                      241
test_n                                                            483
baseline_validation_mse                                      0.000546
extended_validation_mse                                      0.000544
selected_features          return_t, volume_growth_t, volatility_5d_t
final_test_mse                                               0.000399
dtype: object

Executed answer

  • n = 967/241/483.

  • Validation MSE 0.000546119023 (baseline) versus 0.000544403032 locks the extended features.

  • After the 2018–2022 refit, held-out test MSE is 0.000398683922 through 2024-12-30; predictive association is not causation.

Complete Solution for the New Case: Residual Diagnostic

Code
import matplotlib.pyplot as plt  # Drawing Out-of-Sample Residuals Sorted by Time
fig, ax = plt.subplots(figsize=(9, 3.2))  # Suitable for One-Page Display horizontal canvas
ax.plot(transfer_test['date'], transfer_residual, color='#006F99', linewidth=1)  # Demonstrate Time Aggregation and Extremes for Residuals
ax.axhline(0, color='#536164', linestyle='--', linewidth=1)  # Mark the reference lines without system deviations
ax.set(xlabel='Date', ylabel='actual return − prediction', title='test-period residuals')  # Clarify the business meaning of coordinates
ax.tick_params(axis='both', labelsize=24)
ax.xaxis.label.set_size(26); ax.yaxis.label.set_size(26); ax.title.set_size(28)
import matplotlib.dates as mdates
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=6))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y\n%m'))
fig.tight_layout()  # Avoid fitting axis labels outside the graphical boundaries
plt.show()  # Output residual charts for diagnosis
Residuals fluctuate around zero over test dates, with several large outliers.
Figure 4: Hengrui residuals in the fixed 2023–2024 test period

Residual mean is about 0.00051 and standard deviation about 0.01998. A near-zero mean does not remove risk: tail errors still dominate squared loss.

Formative Check 3: Has Optimization Succeeded?

Training loss keeps falling while test loss first falls and then rises. Should training continue?

Answer

Not on training loss alone. The pattern indicates overfitting; choose the stopping point on a validation period and evaluate once on an untouched test period.

Sources and Further Reading

  • Shalev-Shwartz & Ben-David, Understanding Machine Learning, Chapters 2–5.
  • Hastie, Tibshirani & Friedman, The Elements of Statistical Learning, Chapters 2 and 7.
  • scikit-learn User Guide: model selection, metrics, and linear models.
  • Data: local pre-adjusted A-share data. This slide records only repository-verifiable file, key, fields, and filters; it does not infer an undocumented vendor.

Chapter Summary: The Four Pillars of Machine Learning

Optional topic

after Core, optionally enter advanced optimizers, then continue to the final summary without replaying the main case.

Today, we built a complete framework for thinking about machine learning problems.

. . .

1. Frame the Problem

  • Task: Regression vs. Classification
  • Learning Type: Supervised vs. Unsupervised

2. Define the Model

  • Choose a function \(f(x, \theta)\)
  • e.g., Linear Regression

3. Define ‘Good’ (Evaluation)

  • Core: select on train/validation data; check once on the held-out test period
  • Regression: MSE, R²
  • Classification: F1-Score, Recall

4. Define ‘Learning’ (Optimization)

  • Minimize a Loss Function \(J(\theta)\)
  • Gradient Descent is the core algorithm

Thank you!

Q & A