02 数学以及统计学回顾

本章会用到的数据

  • 公开下载A 股前复权日行情。代码会在首次运行时下载并保存到 data/course/

  • 这些数据能做什么:用真实股价练习向量、相关系数和描述统计。

  • 分析时注意:计算收益率前先按公司和日期排序,并明确价格采用前复权口径。

  • 示例说明:小型人工数据用于手算和理解公式,不代表真实市场规律。

【课堂核心】2 学时学习安排

学习内容 分钟
动机与先修 15
向量与缩放 20
形成性检查 15
矩阵 15
导数与跟做示例 20
独立任务与反馈 25
本章小结 10

【可选拓展】完整推导与更多图形题

完整矩阵推导、更多函数极值题与图形证明均为表外拓展,不计入 120 分钟课堂核心。

本章学习目标:为何数学是金融的基石?

  • 本章视角:暂不引入具体经济模型,从金融应用重新审视数学工具。
  • 表示目标:看到投资组合时,能把资产与权重组织成向量和矩阵。
  • 分析目标:把风险、变化率与不确定性连接到可计算的统计量和代码。

本章学习路线图

我们将分三步,构建起金融量化分析的数学大厦。

本章学习路线图 一个包含三个部分的路线图:线性代数、微积分和统计学。 金融量化分析的数学大厦 1. 线性代数 描述多维世界的语言 2. 微积分 捕捉动态变化的工具 3. 统计学 量化不确定性的科学

机器学习为何离不开数学?

机器学习,尤其是在金融领域的应用,本质上是一个数学优化问题。我们将理论、数据和目标,用数学语言串联起来。

机器学习的数学支柱 中心思想“金融机器学习”被三个支柱支撑:数据表示、模型构建与训练、结果评估。 金融机器学习 (本质是数学优化问题) 数据表示 线性代数 (向量, 矩阵) 模型构建与训练 微积分 (梯度, 优化) 结果评估 统计学 (期望, 方差, R²)

第一部分:线性代数回顾

线性代数:描述多维金融世界的语言

想象一下,你如何向计算机描述一个包含100只股票的投资组合?或者如何表示整个市场过去一年的每日收益率?

线性代数提供了一套优雅而高效的语言来完成这项任务。

  • 向量 (Vectors):表示有序的金融数据,如资产权重或价格序列。
  • 矩阵 (Matrices):表示二维数据集,如多只股票的收益率或协方差。
从金融概念到数学对象 长三角上市公司教学示例:投资组合被抽象成向量,两只股票的示例收益被抽象成矩阵;数值只用于说明数学对象。 投资组合 (Portfolio) 上汽集团: 60% 恒瑞医药: 30% 公牛集团: 10% w = [ 0.6 0.3 0.1 ] 市场收益率 (Returns) 上汽 恒瑞 Day1: +0.5% -0.2% Day2: -0.1% +0.3% 长三角上市公司教学示例;权重与收益仅用于演示向量、矩阵 R= [ 0.005, -0.002 -0.001, 0.003 ]

基本构件 1:标量 (Scalar)

标量 是最简单的数学对象:一个单独的数字。

在金融语境中,它可以代表:

  • 无风险利率: \(r_f = 0.02\)
  • 某时点的示例股票价格: \(P_{\text{上汽集团}} = 25.50\)
  • 一项资产的权重: \(w_1 = 0.4\)

我们通常用小写斜体字母表示标量,例如 \(a=1\)\(x=3.14\)

标量可视化 一条数轴,上面标记了多个整数点,并在1.5的位置有一个蓝点,表示一个标量值。 -2 -1 0 1 2 x = 1.5

基本构件 2:向量 (Vector)

向量 是一列有序的数字。这个“有序”的特性至关重要。

例如,一个两资产投资组合的权重向量:

\[ \large{\mathbf{w} = \begin{bmatrix} 0.6 \\ 0.4 \end{bmatrix}} \]

这明确表示第一个资产(比如股票)占60%,第二个资产(比如债券)占40%。顺序不能颠倒。

我们通常用小写粗体字母(如 \(\mathbf{x}\))表示向量。其标准形式是一个用方括号包围的列。

\[ \large{\mathbf{x} = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{bmatrix}} \]

向量的几何直观:空间中的箭头

我们可以把一个 \(n\) 维向量看作是 \(n\) 维空间中的一个点,或者更直观地,一个从原点出发,指向该点的箭头

例如,向量 \(\mathbf{x} = \begin{bmatrix} 2 \\ 1 \end{bmatrix}\) 在二维空间中,代表从 \((0,0)\) 指向 \((2,1)\) 的箭头。

向量的几何表示 一个二维坐标系,其中一个从原点(0,0)指向点(2,1)的蓝色箭头代表向量x。 x₁ x₂ x = (2, 1) (0,0)

行向量 vs. 列向量

默认情况下,我们通常将向量视为列向量(如前页所示)。

通过转置 (Transpose) 操作(记为 \(T\)),我们可以将其变为行向量

\[ \large{\mathbf{x} = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{bmatrix} \quad \xrightarrow{\text{Transpose}} \quad \mathbf{x}^T = \begin{bmatrix} x_1, x_2, \dots, x_n \end{bmatrix}} \]

这个看似简单的区分在矩阵运算中至关重要,它决定了向量之间如何相乘。

在 Python 中创建向量

接下来,我们将在 Python 中使用 NumPy 库来创建和操作向量。NumPy 是 Python 科学计算的核心库。

我们将演示:

  1. 如何创建一个基本的 NumPy 数组来表示向量。
  2. 如何明确区分行向量和列向量的维度。
  3. 如何执行转置操作。

在 Python 中创建向量

在Python中,一个向量就是一个NumPy数组。

代码
# 为“在 Python 中创建向量”导入 `numpy` 并绑定 `np`,用于执行当前任务的数组、数值或随机机制计算。
import numpy as np

# 构造二维向量 x。
x = np.array([1, 2])
# 输出二维向量的两个元素,核对一维数组的数值内容。
print(f'向量 x: {x}')
# 报告“向量 x 的维度: {x.shape}”中的 `x`,核对“在 Python 中创建向量”的样本形状。
print(f'向量 x 的维度: {x.shape}') # 期望一维形状为 (2,)

# 要明确创建一个列向量 (2x1 矩阵), 可以这样做:
x_col = np.array([[1], [2]])
# 输出显式列向量,观察两个元素沿行方向排列。
print(f'\n明确的列向量 x_col:\n{x_col}')
# 报告“列向量的维度: {x_col.shape}”中的 `x_col`,核对“在 Python 中创建向量”的样本形状。
print(f'列向量的维度: {x_col.shape}') # 期望列向量形状为 (2, 1)

# 转置操作
x_row = x_col.T
# 输出转置后的行向量,观察形状由 2×1 变为 1×2。
print(f'\n转置后的行向量 x_row:\n{x_row}')
# 报告“行向量的维度: {x_row.shape}”中的 `x_row`,核对“在 Python 中创建向量”的样本形状。
print(f'行向量的维度: {x_row.shape}') # 期望行向量形状为 (1, 2)
向量 x: [1 2]
向量 x 的维度: (2,)

明确的列向量 x_col:
[[1]
 [2]]
列向量的维度: (2, 1)

转置后的行向量 x_row:
[[1 2]]
行向量的维度: (1, 2)

向量加法:合并两种效应

假设一个投资组合的收益由两部分构成:

  1. 市场整体变动带来的收益: \(\mathbf{r}_{\text{market}} = \begin{bmatrix} 0.02 \\ -0.01 \end{bmatrix}\)
  2. 公司特有事件带来的收益: \(\mathbf{r}_{\text{firm}} = \begin{bmatrix} 0.005 \\ 0.015 \end{bmatrix}\)

总收益就是这两个向量的和,代表了两种效应的叠加。

向量加法的代数法则:逐元素相加

向量加法非常直观:将两个向量对应的元素相加。前提是两个向量的维度必须相同

\[ \large{\mathbf{x} + \mathbf{y} = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{bmatrix} + \begin{bmatrix} y_1 \\ y_2 \\ \vdots \\ y_n \end{bmatrix} = \begin{bmatrix} x_1 + y_1 \\ x_2 + y_2 \\ \vdots \\ x_n + y_n \end{bmatrix}} \]

例如:

\[ \large{\begin{bmatrix} 2 \\ 1 \end{bmatrix} + \begin{bmatrix} 0.5 \\ 1.5 \end{bmatrix} = \begin{bmatrix} 2 + 0.5 \\ 1 + 1.5 \end{bmatrix} = \begin{bmatrix} 2.5 \\ 2.5 \end{bmatrix}} \]

向量减法同理,也是逐元素相减。

向量加法的几何诠释:平行四边形法则

几何上,向量加法遵循“头尾相接”或“平行四边形”法则。将第二个向量的起点移动到第一个向量的终点,从原点到第二个向量终点的新箭头就是它们的和。

向量加法的平行四边形法则向量x与y从共同原点出发,平移后构成平行四边形,对角线表示和向量x+y。 向量加法:平行四边形法则 (Vector Addition: Parallelogram Rule) x y x+y O

向量加法在 Python 中的实现

NumPy 的设计使得向量运算和标量运算一样简单,使用 +- 运算符即可。

代码
# 定义两个向量
x = np.array([1.0, 2.0])
# 固定 `y` 的数值分量,作为“向量加法在 Python 中的实现”的可手算输入。
y = np.array([0.5, 1.5])

# 向量加法
z_add = x + y
# 打印逐元素向量和,核对结果为 `[1.5, 3.5]`。
print(f'x + y = {z_add}')

# 向量减法
z_sub = x - y
# 打印逐元素向量差,核对结果为 `[0.5, 0.5]` 并与加法区分。
print(f'x - y = {z_sub}')
x + y = [1.5 3.5]
x - y = [0.5 0.5]

标量与向量的乘法:缩放向量

假设你决定将某个投资策略的风险敞口(由向量 \(\mathbf{x}\) 代表)加倍。这在数学上如何表示?

这就是标量与向量的乘法:用一个标量 \(a\) 乘以一个向量 \(\mathbf{x}\)

\[ \large{a\mathbf{x} = a \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{bmatrix} = \begin{bmatrix} ax_1 \\ ax_2 \\ \vdots \\ ax_n \end{bmatrix}} \]

它的作用是缩放 (scale) 向量的长度,而不改变其基本方向。

标量乘法的几何效果

  • 如果 \(a > 1\):向量被拉长
  • 如果 \(0 < a < 1\):向量被缩短
  • 如果 \(a < 0\):向量的方向反转180度,并根据 \(|a|\) 的大小进行缩放。
标量乘法的几何效果 一个原始向量x,一个被2倍拉长的向量2x,以及一个方向相反且被-1倍缩短的向量-x。 x 2x -x

标量乘法的 Python 实现

NumPy 中,标量与向量的乘法就像普通数字乘法一样,使用 * 运算符。

代码
# 为“标量乘法的 Python 实现”导入 `numpy` 并绑定 `np`,用于执行当前任务的数组、数值或随机机制计算。
import numpy as np

# 原始向量
x = np.array([1.0, 2.0])

# 标量
a1 = 2
# 对 `1.5` 取负,得到 `a2 = -1.5`。
a2 = -1.5

# 标量乘法
x1 = a1 * x
# 打印原向量,作为后续正、负标量伸缩的共同基准。
print(f'Original x = {x}')
# 打印正标量乘法结果,核对每个分量都按 `a1` 同比例放大。
print(f'   {a1} * x = {x1}')

# 将向量每个分量乘以标量 -1.5,演示方向反转并把长度放大到 1.5 倍。
x2 = a2 * x
# 打印负标量乘法结果,核对每个分量按 `a2` 缩放并反向。
print(f' {a2} * x = {x2}')
Original x = [1. 2.]
   2 * x = [2. 4.]
 -1.5 * x = [-1.5 -3. ]

线性组合:用基本向量构建一切

  • 组成:线性组合把向量加法与标量乘法结合起来。
  • 输入:向量 \(\{\mathbf{v}_1, \mathbf{v}_2, \dots, \mathbf{v}_k\}\) 与标量 \(\{c_1, c_2, \dots, c_k\}\)

\[ \large{\mathbf{z} = c_1\mathbf{v}_1 + c_2\mathbf{v}_2 + \dots + c_k\mathbf{v}_k} \]

金融应用:投资组合总回报,是各资产回报向量 \(\mathbf{v}_i\) 按投资权重 \(c_i\) 的线性组合。

向量的点积:衡量“一致性”

  • 输入:两个维度相同的向量。
  • 运算:对应分量相乘后求和。
  • 输出:一个标量,也称点积(Dot Product)或内积(Inner Product)。

假设我们有两个向量:

  • 投资组合权重向量 \(\mathbf{w} = \begin{bmatrix} 0.6 \\ 0.3 \\ 0.1 \end{bmatrix}\)
  • 资产预期收益率向量 \(\mathbf{r} = \begin{bmatrix} 0.10 \\ 0.08 \\ 0.05 \end{bmatrix}\)

投资组合的总预期收益率就是这两个向量的点积。

点积的计算公式

点积的计算方法是:将两个向量的对应元素相乘,然后将结果相加。

\[ \large{\mathbf{x}^T \mathbf{y} = \mathbf{x} \cdot \mathbf{y} = \sum_{i=1}^n x_i y_i = x_1y_1 + x_2y_2 + \dots + x_ny_n} \]

例如: \(\mathbf{x} = \begin{bmatrix} 1 \\ 0 \\ 2 \end{bmatrix}\), \(\mathbf{y} = \begin{bmatrix} -1 \\ -5 \\ 3 \end{bmatrix}\)

\[ \large{\mathbf{x}^T \mathbf{y} = (1 \times -1) + (0 \times -5) + (2 \times 3) = -1 + 0 + 6 = 5} \]

点积的几何意义:投影与角度

点积的真正威力在于它的几何意义。它与两个向量之间的夹角 \(\theta\) 密切相关:

\[ \large{\mathbf{x}^T \mathbf{y} = \lVert\mathbf{x}\rVert \lVert\mathbf{y}\rVert \cos(\theta)} \]

点积符号 几何含义
\(\mathbf{x}^T\mathbf{y}>0\) 夹角小于 \(90^\circ\),方向大致相同
\(\mathbf{x}^T\mathbf{y}=0\) 夹角等于 \(90^\circ\),两向量正交
\(\mathbf{x}^T\mathbf{y}<0\) 夹角大于 \(90^\circ\),方向大致相反

金融解释边界:先在同一时间窗内分别减去样本均值。中心化收益的正点积才表示样本协动为正;原始收益的正点积还可能来自共同的非零均值。

点积几何意义的可视化

点积衡量了一个向量在另一个向量方向上的投影长度。

点积的投影几何意义 向量y在向量x上的投影。点积的大小与这个投影的长度有关。 x y θ y在x上的投影 (长度 = ||y|| cos(θ))

点积在 Python 中的实现

NumPy 提供了多种方式计算点积。在现代 Python (3.5+) 和 NumPy 中,推荐使用 @ 运算符,因为它最清晰地表达了数学意图。

代码
# 固定 `x` 的数值分量,作为“点积在 Python 中的实现”的可手算输入。
x = np.array([1,  2,  3])
# 固定 `y` 的数值分量,作为“点积在 Python 中的实现”的可手算输入。
y = np.array([-1, -5, 3])

# 方法 1: 使用 @ 运算符 (推荐)
dot_product_1 = x @ y
# 打印 `@` 运算符得到的点积标量,作为三种实现一致性的第一项证据。
print(f'使用 @ 运算符: {dot_product_1}')

# 方法 2: 使用 np.dot() 函数
dot_product_2 = np.dot(x, y)
# 打印 `np.dot` 得到的同一点积标量,与 `@` 结果交叉核对。
print(f'使用 np.dot(): {dot_product_2}')

# 方法 3: 逐元素相乘再求和 (展示了其定义)
dot_product_3 = np.sum(x * y)
# 打印逐元素乘积求和得到的点积标量,确认三种表达式数值一致。
print(f'逐元素相乘再求和: {dot_product_3}')
使用 @ 运算符: -2
使用 np.dot(): -2
逐元素相乘再求和: -2

向量范数:衡量向量的“大小”或“长度”

我们如何量化一个向量的“大小”?例如,一个代表投资组合每日收益波动的向量,我们如何衡量其整体波动幅度?

范数 (Norm) 就是一个衡量向量大小的函数,记作 \(\lVert\mathbf{x}\rVert\)。它必须满足三个性质:

  1. 正定性\(\lVert\mathbf{x}\rVert \ge 0\),且仅当 \(\mathbf{x} = \mathbf{0}\) 时等号成立。
  2. 齐次性\(\lVert k\mathbf{x}\rVert = |k| \lVert\mathbf{x}\rVert\)
  3. 三角不等式\(\lVert\mathbf{x} + \mathbf{y}\rVert \le \lVert\mathbf{x}\rVert + \lVert\mathbf{y}\rVert\)

L1 范数:曼哈顿距离

L1 范数 (或称 Manhattan Norm) 是向量中所有元素绝对值之和

\[ \large{\lVert\mathbf{x}\rVert_1 = \sum_{i=1}^n |x_i|} \]

直观理解:想象在像曼哈顿这样的棋盘格城市中,从原点到一个点必须沿着街道走,L1范数就是你需要走过的总街区数。

例子: \(\mathbf{x} = \begin{bmatrix} 1 \\ -2 \end{bmatrix}\)

\[ \large{\lVert\mathbf{x}\rVert_1 = |1| + |-2| = 1 + 2 = 3} \]

在机器学习中,L1范数常用于特征选择(Lasso回归),因为它倾向于产生稀疏解(许多权重为零)。

L2 范数:欧几里得距离

L2 范数 (或称 Euclidean Norm) 是我们最熟悉的“距离”概念。它是向量元素平方和的平方根

\[ \large{\lVert\mathbf{x}\rVert_2 = \sqrt{\sum_{i=1}^n x_i^2}} \]

几何意义:它就是从原点到向量所指向的点的直线距离

例子: \(\mathbf{x} = \begin{bmatrix} 1 \\ -2 \end{bmatrix}\)

\[ \large{\lVert\mathbf{x}\rVert_2 = \sqrt{1^2 + (-2)^2} = \sqrt{1 + 4} = \sqrt{5} \approx 2.236} \]

如果没有特别指明,通常所说的“范数”或“向量长度”都指L2范数。

L1 vs. L2 范数可视化

L1 和 L2 范数的差异可以通过“单位球”的形状直观地理解,即所有范数值为1的点的集合。

L1和L2范数的单位球 两个坐标系,左边显示L1范数的单位球(一个菱形),右边显示L2范数的单位球(一个圆形)。 L1 范数: ||x||₁ = 1 (菱形/Diamond) L2 范数: ||x||₂ = 1 (圆形/Circle)

范数在 Python 中的计算

NumPylinalg 模块可以方便地计算各种范数,通过 ord 参数指定范数的阶数。

代码
# 固定 `x` 的数值分量,作为“范数在 Python 中的计算”的可手算输入。
x = np.array([1, -2, 2])

# L1 范数 (ord=1)
l1_norm = np.linalg.norm(x, ord=1)
# 输出绝对值之和,核对向量的 L1 范数。
print(f'L1 Norm of x (|1|+|-2|+|2|): {l1_norm}')

# L2 范数 (ord=2 is default)
l2_norm = np.linalg.norm(x)
# 输出平方和开根号,核对向量的 L2 范数。
print(f'L2 Norm of x (sqrt(1²+2²+2²)): {l2_norm}')
L1 Norm of x (|1|+|-2|+|2|): 5.0
L2 Norm of x (sqrt(1²+2²+2²)): 3.0

单位向量:只关心方向

  • 定义:单位向量(Unit Vector)的 L2 范数为 1。
  • 作用:保留方向,去除原向量的绝对大小。
  • 转换:任意非零向量除以自身的 L2 范数。

\[ \large{\hat{\mathbf{x}} = \frac{\mathbf{x}}{\lVert\mathbf{x}\rVert_2}} \]

归一化、中心化与标准化不同

三种操作服务于不同目标:

操作 目标
L2 归一化 \(\mathbf{x}/\lVert\mathbf{x}\rVert_2\),令单个向量长度为 1
中心化 \(\mathbf{x}-\bar{x}\mathbf{1}\),令样本均值为 0
z-score \((\mathbf{x}-\bar{x}\mathbf{1})/s\),令样本均值为 0、按所选 ddof 计算的标准差为 1

反例:L2 归一化不等于标准化。

  • \(\mathbf{x}=(1,3)\) 的 L2 归一化为 \((1/\sqrt{10},3/\sqrt{10})\)
  • 该结果均值不为 0、方差也不为 1。
  • 使用总体标准差(ddof=0)的 z-score 才得到 \((-1,1)\)

向量相似度:欧几里得距离

我们如何量化两个投资策略(表示为向量)的相似性?

方法一:欧几里得距离

计算两个向量终点之间的直线距离。这可以通过计算差向量的L2范数来实现: \(d(\mathbf{x}, \mathbf{y}) = \lVert\mathbf{x} - \mathbf{y}\rVert_2\)

  • 距离越小,向量越相似。
  • 这个方法同时考虑了大小方向。对于比较投资组合的绝对表现差异可能很有用。

向量相似度:余弦相似度

方法二:余弦相似度 (Cosine Similarity)

这个方法只关心方向,不关心大小。它计算两个向量之间夹角的余弦值。

\[ \large{\cos(\theta) = \frac{\mathbf{x}^T \mathbf{y}}{\lVert\mathbf{x}\rVert_2 \lVert\mathbf{y}\rVert_2}} \]

  • 结果在 [-1, 1] 之间。
  • 1: 方向完全相同。
  • 0: 在当前向量空间中方向正交;不能据此断言经济或语义“无关”。
  • -1: 方向完全相反。

金融应用边界

  • 原始收益向量的余弦会受非零均值影响;比较共同涨跌模式时应先分别中心化。
  • 两个中心化向量范数非零时,其余弦等于 Pearson 相关系数。
  • 任一向量为零向量时,余弦未定义,不能强行记为 0。

形成性检查:归一化不是标准化

独立作答:对 \(\mathbf{x}=(1,3)\),哪种操作保证均值为 0、总体标准差为 1?余弦相似度为 0 能否推出两只股票经济上无关?

形成性检查反馈:先说目标,再选操作

  • 标准化答案:z-score(ddof=0);L2 归一化只固定向量长度。
  • 相似度答案:余弦为 0 只说明当前表示正交,不能推出经济无关。
  • 订正路径:答错者返回 相关内容,重算三个结果后再进入矩阵部分。

相似度计算可视化

下面的图表演示了这两种相似度度量的区别。

欧氏距离与余弦相似度比较双面板比较两组向量:同方向但长度不同会有高余弦相似度和较大欧氏距离,正交向量则余弦相似度为零。 欧氏距离 vs. 余弦相似度 (Euclidean Distance vs. Cosine Similarity) 情景A: 方向一致,大小不同 x y 欧氏距离 余弦相似度 = 1.0 (方向相同) 欧氏距离 = 大 (大小差异) 情景B: 方向垂直,大小相似 x y 欧氏距离 θ=90° 余弦相似度 = 0.0 (方向垂直) 欧氏距离 = 大 (空间分离)

矩阵:二维数据表

矩阵 (Matrix) 是一个二维的数字数组,可以看作是向量的推广。我们用大写粗体字母表示矩阵,如 \(\mathbf{A}\)

一个 \(m \times n\) 的矩阵有 \(m\) 行和 \(n\) 列。

\[ \large{\mathbf{A} = \begin{bmatrix} a_{11} & a_{12} & \dots & a_{1n} \\ a_{21} & a_{22} & \dots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \dots & a_{mn} \end{bmatrix}} \]

金融应用

  • 一个 \(m \times n\) 矩阵可以表示 \(m\) 只股票过去 \(n\) 天的收益率数据。
  • 一个 \(m \times m\)协方差矩阵可以表示 \(m\) 只股票收益率之间的联动关系。

矩阵在 Python 中的表示

我们同样使用 NumPy 数组来表示矩阵,此时它是一个二维数组。

代码
# 构造一个 2x3 的矩阵 (2 行, 3 列)
A = np.array([
    # 写入矩阵 `A` 的第一行,固定三个列元素的教学数值。
    [1,2,3],
    # 写入矩阵 `A` 的第二行,使其形状为 2×3。
    [-2, 12, 4]
# 完成矩阵 `A` 的二维数组定义,供形状与矩阵乘法示例复用。
])

# 标出随后展示的是矩阵 A,便于把打印结果与二维数组定义对应起来。
print('矩阵 A:')
# 输出二维数组 `A`,核对两行三列的矩阵布局。
print(A)

# 获取矩阵的维度
print(f'\n矩阵 A 的维度 (行, 列): {A.shape}')
矩阵 A:
[[ 1  2  3]
 [-2 12  4]]

矩阵 A 的维度 (行, 列): (2, 3)

矩阵乘法:核心运算

  • 可乘条件\(\mathbf{A}\) 的列数必须等于 \(\mathbf{B}\) 的行数。
  • 结果维度\(m\times p\) 矩阵乘 \(p\times n\) 矩阵,得到 \(m\times n\) 矩阵。
  • 元素计算\((C)_{ij}\)\(\mathbf{A}\)\(i\) 行与 \(\mathbf{B}\)\(j\) 列的点积。

\[ \large{(C)_{ij} = \sum_{k=1}^p a_{ik}b_{kj}} \]

矩阵乘法图解

计算 \(C_{11}\):取 A 的第 1 行和 B 的第 1 列,做点积。

矩阵乘法可视化 展示了矩阵A的第一行和矩阵B的第一列如何相乘得到结果矩阵C的第一个元素。 A (m × p) a₁₁ a₁₂ a₂₁ a₂₂ × B (p × n) b₁₁ b₁₂ b₂₁ b₂₂ = C (m × n) C₁₁ C₁₁ = (a₁₁ × b₁₁) + (a₁₂ × b₂₁)

矩阵乘法示例

给定 \(\mathbf{A} \in \mathbb{R}^{2 \times 3}\)\(\mathbf{B} \in \mathbb{R}^{3 \times 2}\),求 \(\mathbf{C} = \mathbf{AB}\)

\[ \large{\mathbf{A} = \begin{bmatrix} 1 & 0 & 2 \\ -2 & 12 & 4 \end{bmatrix}, \quad \mathbf{B} = \begin{bmatrix} 10 & -2 \\ 4 & 1 \\ 0 & 7 \end{bmatrix}} \]

\[ \large{C_{11} = (1 \cdot 10) + (0 \cdot 4) + (2 \cdot 0) = 10} \]

\[ \large{C_{12} = (1 \cdot -2) + (0 \cdot 1) + (2 \cdot 7) = 12} \]

\[ \large{C_{21} = (-2 \cdot 10) + (12 \cdot 4) + (4 \cdot 0) = 28} \]

\[ \large{C_{22} = (-2 \cdot -2) + (12 \cdot 1) + (4 \cdot 7) = 4 + 12 + 28 = 44} \]

\[ \large{\mathbf{C} = \begin{bmatrix} 10 & 12 \\ 28 & 44 \end{bmatrix}} \]

矩阵乘法在 Python 中的实现

与向量点积一样,我们使用 @ 运算符进行矩阵乘法。NumPy 会自动处理行与列的点积。

代码
# 复用上一页手算矩阵 `A`,让 Python 输出直接核对四个逐项结果。
A = np.array([[1, 0, 2], [-2, 12, 4]])
# 复用上一页手算矩阵 `B`,保持 2×3 @ 3×2 的维度关系不变。
B = np.array([[10, -2], [4, 1], [0, 7]])

# 矩阵乘法
C = A @ B

# 标出左乘矩阵 A,便于核对其 2×3 维度。
print('矩阵 A (2x3):')
# 输出 2×3 矩阵 `A`,确认左乘矩阵的维度。
print(A)
# 标出右乘矩阵 B,便于核对其 3×2 维度与乘法相容性。
print('\n矩阵 B (3x2):')
# 输出 3×2 矩阵 `B`,确认其行数与 `A` 的列数相等。
print(B)
# 标出矩阵 A 与 B 相乘得到的 2×2 结果。
print('\n结果 C = A @ B (2x2):')
# 输出乘积 `C`,验证 2×3 与 3×2 相乘得到 2×2 矩阵。
print(C)
矩阵 A (2x3):
[[ 1  0  2]
 [-2 12  4]]

矩阵 B (3x2):
[[10 -2]
 [ 4  1]
 [ 0  7]]

结果 C = A @ B (2x2):
[[10 12]
 [28 44]]

矩阵与向量的乘法

  • 特例:把 \(p\) 维列向量看作 \(p\times1\) 矩阵。
  • 维度\(m\times p\)\(\mathbf{A}\)\(p\)\(\mathbf{x}\),得到 \(m\)\(\mathbf{y}\)
  • 直觉\(\mathbf{A}\) 表示线性变换,把输入 \(\mathbf{x}\) 映射为输出 \(\mathbf{y}=\mathbf{Ax}\)

矩阵与标量的乘法

这与向量和标量的乘法类似:将矩阵中的每一个元素都与该标量相乘。

例如: \(a=2, \mathbf{B} = \begin{bmatrix} 10 & -2 \\ 4 & 1 \\ 0 & 7 \end{bmatrix}\)

\[ \large{a\mathbf{B} = 2 \begin{bmatrix} 10 & -2 \\ 4 & 1 \\ 0 & 7 \end{bmatrix} = \begin{bmatrix} 20 & -4 \\ 8 & 2 \\ 0 & 14 \end{bmatrix}} \]

代码
# 将缩放系数固定为 2,用于观察矩阵每个元素同步倍增。
a = 2
# 固定 `B` 的数值分量,作为“矩阵与标量的乘法”的可手算输入。
B = np.array([[10, -2],[1,2],[3,4]])
# 将矩阵 B 的每个元素乘以标量 2。
aB = a * B
# 输出 `aB`,核对标量 2 已作用于矩阵 `B` 的每个元素。
print(aB)
[[20 -4]
 [ 2  4]
 [ 6  8]]

矩阵的逆:线性代数中的“除法”

  • 标量类比\(a\ne0\) 时,\(a\cdot a^{-1}=1\)
  • 矩阵对象\(\mathbf{A}\) 必须是 \(n\times n\) 方阵。
  • 可逆条件:存在同阶矩阵 \(\mathbf{B}\),使

\[ \mathbf{A}\mathbf{B}=\mathbf{B}\mathbf{A}=\mathbf{I}. \]

  • 记号:此时 \(\mathbf{B}=\mathbf{A}^{-1}\)\(\mathbf{I}\) 是主对角线为 1、其余为 0 的单位矩阵。

单位矩阵 (Identity Matrix)

单位矩阵 \(\mathbf{I}\) 在矩阵乘法中的作用,就像数字 1 在普通乘法中的作用。任何矩阵乘以单位矩阵,都等于其自身。

\[ \large{\mathbf{AI} = \mathbf{IA} = \mathbf{A}} \]

\[ \large{\mathbf{I}_3 = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}} \]

为何矩阵求逆很重要?

矩阵求逆的核心应用是求解线性方程组

考虑一个简单的线性方程组:

\[ \large{\mathbf{Ax} = \mathbf{b}} \]

这里,\(\mathbf{A}\) 是系数矩阵,\(\mathbf{x}\) 是未知变量向量,\(\mathbf{b}\) 是常数向量。

如果我们知道 \(\mathbf{A}^{-1}\),我们可以两边左乘 \(\mathbf{A}^{-1}\)

\[ \large{\mathbf{A}^{-1}\mathbf{A}\mathbf{x} = \mathbf{A}^{-1}\mathbf{b}} \]

\[ \large{\mathbf{I}\mathbf{x} = \mathbf{A}^{-1}\mathbf{b}} \]

\[ \large{\mathbf{x} = \mathbf{A}^{-1}\mathbf{b}} \]

我们就直接解出了 \(\mathbf{x}\)

金融应用:在投资组合优化中,求解最优权重通常归结为求解一个大型线性方程组。

求解 2x2 矩阵的逆:一个例子

我们用一个例子来展示如何求解。求矩阵 \(\mathbf{A}\) 的逆 \(\mathbf{A}^{-1}\)

\[ \large{\mathbf{A} = \begin{bmatrix} 4 & 7 \\ 2 & 6 \end{bmatrix}} \]

我们设所求的逆矩阵为:

\[ \large{\mathbf{A}^{-1} = \begin{bmatrix} a & b \\ c & d \end{bmatrix}} \]

我们的目标是求解 \(a, b, c, d\)

求解 2x2 矩阵的逆:建立方程

根据定义 \(\mathbf{A}\mathbf{A}^{-1} = \mathbf{I}\)

\[ \large{\begin{bmatrix} 4 & 7 \\ 2 & 6 \end{bmatrix} \begin{bmatrix} a & b \\ c & d \end{bmatrix} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}} \]

通过矩阵乘法,我们得到:

\[ \large{\begin{bmatrix} 4a + 7c & 4b + 7d \\ 2a + 6c & 2b + 6d \end{bmatrix} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}} \]

这给了我们两组独立的 \(2 \times 2\) 线性方程组。

求解 2x2 矩阵的逆:求解方程组

第一组 (求解 a, c):

  1. \(4a + 7c = 1\)
  2. \(2a + 6c = 0 \implies a = -3c\)

将 (2) 代入 (1): \(4(-3c) + 7c = 1 \implies -12c + 7c = 1 \implies -5c = 1 \implies c = -0.2\) 代回 (2): \(a = -3(-0.2) = 0.6\)

第二组 (求解 b, d):

  1. \(4b + 7d = 0 \implies b = -7d/4\)
  2. \(2b + 6d = 1\)

将 (3) 代入 (4): \(2(-7d/4) + 6d = 1 \implies -3.5d + 6d = 1 \implies 2.5d = 1 \implies d = 0.4\) 代回 (3): \(b = -7(0.4)/4 = -0.7\)

求解 2x2 矩阵的逆:最终结果

我们解出了 \(a=0.6, b=-0.7, c=-0.2, d=0.4\)。 所以,逆矩阵为:

\[ \large{\mathbf{A}^{-1} = \begin{bmatrix} 0.6 & -0.7 \\ -0.2 & 0.4 \end{bmatrix}} \]

验证:

\[ \large{\mathbf{A}\mathbf{A}^{-1} = \begin{bmatrix} 4 & 7 \\ 2 & 6 \end{bmatrix} \begin{bmatrix} 0.6 & -0.7 \\ -0.2 & 0.4 \end{bmatrix} = \begin{bmatrix} 2.4-1.4 & -2.8+2.8 \\ 1.2-1.2 & -1.4+2.4 \end{bmatrix} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}} = \mathbf{I} \]

验证通过!

矩阵求逆的 Python 实现

在实际应用中,我们从不手动求逆。我们让计算机来做,这更快也更不容易出错。

代码
# 固定 `A` 的数值分量,作为“矩阵求逆的 Python 实现”的可手算输入。
A = np.array([[1,2],[3,4]])

# 使用 np.linalg.inv() 函数求逆
try:
    # 计算非奇异矩阵 `A` 的逆矩阵,供单位矩阵乘积检验。
    A_inv = np.linalg.inv(A)
    # 标出原矩阵 A,使逆矩阵结果保留可核对的输入。
    print('矩阵 A:')
    # 输出原矩阵 `A`,保留逆矩阵计算的输入证据。
    print(A)
    # 标出随后展示的是 A 的数值逆矩阵。
    print('\n矩阵 A 的逆 A_inv:')
    # 输出四舍五入后的逆矩阵,便于手算核对各元素。
    print(np.round(A_inv, decimals=2))

    # 验证 A @ A_inv 是否为单位矩阵
    I = A @ A_inv
    # 标出 A 与其逆矩阵的乘积,核对结果是否接近单位矩阵。
    print('\n验证 A @ A_inv (结果应接近单位矩阵):')
    # np.round() 用于处理微小的浮点数误差
    print(np.round(I, decimals=5))

# 若矩阵奇异而无法求逆,则捕获线性代数错误并转入不可逆提示。
except np.linalg.LinAlgError:
    # 报告矩阵不可逆,避免继续解读不存在的逆矩阵。
    print("矩阵 A 是奇异矩阵 (singular), 不可逆。")
矩阵 A:
[[1 2]
 [3 4]]

矩阵 A 的逆 A_inv:
[[-2.   1. ]
 [ 1.5 -0.5]]

验证 A @ A_inv (结果应接近单位矩阵):
[[1. 0.]
 [0. 1.]]

线性代数部分练习与应用

现在,让我们通过解决课本上的练习题来巩固我们学到的知识。这不仅是计算,更是将抽象概念应用到具体数字上的过程。

习题 2.5.1 向量运算 给定向量: \(\mathbf{x} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix}, \quad \mathbf{y} = \begin{bmatrix} -0.5 \\ 2 \\ 0 \end{bmatrix}\)

请计算:

  1. \(-2\mathbf{x}\)
  2. \(\mathbf{x}+\mathbf{y}\)
  3. \(\mathbf{x} \cdot \mathbf{y}\) (点积)
  4. \(\mathbf{x}^T\mathbf{y}\)

练习 2.5.1 Python 求解

代码
# 固定 `x` 的数值分量,作为“练习 2.5.1 Python 求解”的可手算输入。
x = np.array([1.0, 2.0,3.0])
# 固定 `y` 的数值分量,作为“练习 2.5.1 Python 求解”的可手算输入。
y = np.array([-0.5, 2, 0])

# 第 1 问:计算 -2x
# 将向量 x 的每个分量乘以 -2,求练习第一问。
neg_2x = -2 * x
# 打印 `-2x` 的三维结果,核对负标量同时改变方向和长度。
print(f'1. -2x = {neg_2x}')

# 第 2 问:计算 x + y
# 逐分量相加 `x` 与 `y`,得到练习第二问的三维向量和。
x_plus_y = x + y
# 打印 `x + y`,核对第二问的逐分量加法结果。
print(f'2. x + y = {x_plus_y}')

# 计算 `x` 与 `y` 的点积标量,回答第三问并核对向量维度相容。
dot_product = x @ y
# 输出 x 与 y 对应分量乘积之和,核对第三问点积。
print(f'3. x . y (dot product) = {dot_product}')

# 第 4 问:计算 x 的转置与 y 的乘积
# 在 NumPy 中, x.T @ y 对于一维数组和 x @ y 结果相同
# 但为了概念清晰,我们明确其数学含义
transpose_dot = x.T @ y
# 打印 `x^T y` 的标量结果,核对转置向量与列向量的内积。
print(f'4. x^T y = {transpose_dot}')

# 总结一维 NumPy 数组下点积与转置乘积给出同一标量。
print('\n结论: 向量的点积 (x.y) 和 x^T y 在计算上是等价的。')
1. -2x = [-2. -4. -6.]
2. x + y = [0.5 4.  3. ]
3. x . y (dot product) = 3.5
4. x^T y = 3.5

结论: 向量的点积 (x.y) 和 x^T y 在计算上是等价的。

练习 2.5.2 矩阵运算

给定矩阵 \(\mathbf{A} = \begin{pmatrix} 0.3 & -2.9 & -10 \\ -3 & 1 & 0.5 \end{pmatrix}\) 和上题中的向量 \(\mathbf{x} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix}\)

请回答和计算:

  1. 该矩阵的维度是什么?
  2. 计算 \(\mathbf{Ax}\)
  3. \(\mathbf{A}^T\)

练习 2.5.2 Python 求解

代码
# 为“练习 2.5.2 Python 求解”导入 `numpy` 并绑定 `np`,用于执行当前任务的数组、数值或随机机制计算。
import numpy as np

# 构造 2×3 矩阵 A
# 固定 `A` 的数值分量,作为“练习 2.5.2 Python 求解”的可手算输入。
A = np.array([
    # 写入练习矩阵 `A` 的第一行系数,用于手算第一项线性组合。
    [0.3, -2.9, -10],
    # 写入练习矩阵 `A` 的第二行系数,用于手算第二项线性组合。
    [-3, 1, 0.5]
# 完成练习矩阵 `A` 的 2×3 定义,使其列数与三元素向量 `x` 对齐。
])

# 向量 x 必须有三个元素才能与 A 的列数匹配
# 固定 `x` 的数值分量,作为“练习 2.5.2 Python 求解”的可手算输入。
x = np.array([1.0, 2.0, 3.0])

# 解包矩阵 `A` 的行数与列数,回答第一问的形状判断。
rows, cols = A.shape
# 报告“1. 矩阵 A 的维度是: {rows} 行, {cols} 列”中的 `rows`、`cols`,核对“练习 2.5.2 Python 求解”的样本形状。
print(f'1. 矩阵 A 的维度是: {rows} 行, {cols} 列')

# 计算矩阵 `A` 与向量 `x` 的乘积,回答第二问并核对输出维度。
# A(2x3) @ x(3,) -> 结果是 (2,) 向量
Ax = A @ x
# 打印矩阵—向量乘积 `Ax`,核对结果维度等于矩阵行数。
print(f'\n2. Ax = {Ax}')
# 展开矩阵第一行与向量的内积,供手算核对 Ax 的首个分量。
print(f'   计算过程 (第一行): (0.3*1) + (-2.9*2) + (-10*3) = {0.3 * 1 - 2.9 * 2 - 10 * 3}')
# 展开矩阵第二行与向量的内积,供手算核对 Ax 的第二个分量。
print(f'   计算过程 (第二行): (-3*1) + (1*2) + (0.5*3) = {-3 * 1 + 1 * 2 + 0.5 * 3}')

# 交换矩阵 `A` 的两个轴得到转置,回答第三问并核对形状反转。
A_T = A.T
# 打印转置矩阵 `A^T`,核对原矩阵行列互换后的形状与元素位置。
print(f'\n3. A 的转置 A^T 是:\n{A_T}')
# 报告“A^T 的维度是: {A_T.shape}”中的 `A_T`,核对“练习 2.5.2 Python 求解”的样本形状。
print(f'   A^T 的维度是: {A_T.shape}')
1. 矩阵 A 的维度是: 2 行, 3 列

2. Ax = [-35.5   0.5]
   计算过程 (第一行): (0.3*1) + (-2.9*2) + (-10*3) = -35.5
   计算过程 (第二行): (-3*1) + (1*2) + (0.5*3) = 0.5

3. A 的转置 A^T 是:
[[  0.3  -3. ]
 [ -2.9   1. ]
 [-10.    0.5]]
   A^T 的维度是: (3, 2)

第二部分:微积分回顾

微积分:捕捉金融世界的动态变化

金融市场瞬息万变。资产价格、利率、风险,所有这些都不是静止的。我们如何描述和分析这些变化

微积分,特别是微分,是研究“变化率”的数学语言。

  • 导数 (Derivative):衡量当一个变量发生微小变化时,另一个函数变量会如何响应。
  • 梯度 (Gradient):导数在多维空间中的推广,它指向函数增长最快的方向。

这对于金融中的优化问题——例如,最大化收益或最小化风险——至关重要。

一维微分:函数的变化率

微分的直观意义是函数在某一点的瞬时变化率,也就是该点切线的斜率

  • 记号\(f'(x_0)\)\(\frac{df}{dx}|_{x_0}\)
  • 含义\(x\)\(x_0\) 附近微小变动时,\(f(x)\) 的局部响应率。

金融应用:期权定价中的 “Delta” 就是期权价格(函数)相对于标的资产价格(变量)的导数。它告诉我们股票价格每变动1美元,期权价格会变动多少。

常见函数的导数

以下是一些我们需要熟记的求导法则:

  1. 常数: \(f(x) = c \implies f'(x) = 0\)
  2. 线性函数: \(f(x) = ax \implies f'(x) = a\)
  3. 幂函数: \(f(x) = x^n \implies f'(x) = nx^{n-1}\)
  4. 加法法则: \((f+g)' = f' + g'\)
  5. 乘法法则: \((fg)' = f'g + fg'\)
  6. 自然对数: \(f(x) = \ln(x) \implies f'(x) = \frac{1}{x}\)
  7. 指数函数: \(f(x) = e^x \implies f'(x) = e^x\)

链式法则:求解复合函数的导数

当我们处理嵌套函数(复合函数)时,例如 \(f(g(x))\),我们需要使用链式法则 (Chain Rule)

\[ \large{\frac{d}{dx}f(g(x)) = f'(g(x)) \cdot g'(x)} \]

直观解释:“外层函数的导数(保持内层不变)”乘以“内层函数的导数”。

例子:求 \(h(x) = (x^2+1)^3\) 的导数。

  • 外层函数 \(f(g) = g^3 \implies f'(g) = 3g^2\)
  • 内层函数 \(g(x) = x^2+1 \implies g'(x) = 2x\)
  • \(h'(x) = f'(g(x)) \cdot g'(x) = 3(x^2+1)^2 \cdot (2x) = 6x(x^2+1)^2\)

多维微分:梯度 (Gradient)

当函数有多个输入变量时,例如 \(f(x_1, x_2, \dots, x_n)\),我们如何描述它的变化?

  • 偏导数 \(\frac{\partial f}{\partial x_k}\):只让 \(x_k\) 变动,其他变量保持不变时的变化率。
  • 梯度 \(\nabla f(\mathbf{x})\):把所有偏导数按变量顺序收集成一个向量。

\[ \large{\nabla f(\mathbf{x}) = \begin{bmatrix} \frac{\partial f}{\partial x_1} \\ \frac{\partial f}{\partial x_2} \\ \vdots \\ \frac{\partial f}{\partial x_n} \end{bmatrix}} \]

梯度的几何意义:最陡峭的登山路径

梯度向量 \(\nabla f(\mathbf{x})\) 指向函数 \(f\) 在点 \(\mathbf{x}\) 处增长最快的方向。

梯度的几何意义 一个表示山丘的等高线图。在某一点上,梯度向量指向最陡峭的上坡方向,负梯度指向最陡峭的下坡方向。 当前位置 (x) ∇f(x) (最陡峭上坡) -∇f(x) (最陡峭下坡)

梯度下降法:机器学习的引擎

这个“最陡峭下坡”的概念是机器学习模型训练的核心算法——梯度下降 (Gradient Descent)——的基础。

为了找到一个函数(例如,模型的“损失函数”)的最小值,我们从一个随机点开始,然后反复地沿着负梯度方向小步移动。

\[ \large{\mathbf{x}_{\text{new}} = \mathbf{x}_{\text{old}} - \eta \nabla f(\mathbf{x}_{\text{old}})} \]

  • \(\eta\) (eta) 是学习率 (learning rate),控制我们每一步走多远。

这个简单的迭代过程,是训练从线性回归到深度神经网络等众多模型的基础。

寻找局部最大/最小值

一个可微函数的局部最大值或最小值(统称为极值点)在哪里出现?

  • 一维情况:在 \(f'(x_0) = 0\) 的点。即函数切线斜率为0(水平)的地方。
  • 多维情况:在 \(\nabla f(\mathbf{x}_0) = \mathbf{0}\) 的点。即梯度为零向量,在任何方向上函数值的瞬时变化率都为0。

这个条件是函数取得极值的必要条件 (Necessary Condition),但不是充分条件 (Sufficient Condition)。一个梯度为0的点也可能是鞍点。

寻找极值的例子

我们来看一个函数 \(f(x) = x^3 - 6x^2 + 5x + 12\)

  1. 求导\(f'(x) = 3x^2 - 12x + 5\)

  2. 令导数为0\(3x^2 - 12x + 5 = 0\)

  3. 求解:使用求根公式 \(x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}\)

    \[ \large{x = \frac{12 \pm \sqrt{(-12)^2 - 4(3)(5)}}{2(3)} = \frac{12 \pm \sqrt{144 - 60}}{6} = \frac{12 \pm \sqrt{84}}{6}} \]

    所以极值点大约在 \(x \approx 0.47\)\(x \approx 3.53\)

极值点可视化

代码
# 为“极值点可视化”导入 `numpy` 并绑定 `np`,用于执行当前任务的数组、数值或随机机制计算。
import numpy as np
# 为“极值点可视化”导入 `matplotlib.pyplot` 并绑定 `plt`,用于构建当前任务的坐标轴并呈现比较结果。
import matplotlib.pyplot as plt

# 定义 `f`,计算给定多项式的函数值。
def f(x):
    # 返回 `x**3 - 6*x**2 + 5*x + 12`,把“极值点可视化”的计算结果交给调用方。
    return x**3 - 6*x**2 + 5*x + 12

# 求解导数为0的点
# 驻点满足导数方程 f'(x) = 3x² - 12x + 5 = 0
# 求解导函数二次方程的两个根,定位三次函数的驻点。
roots = np.roots([3, -12, 5])
# 将两个驻点按横坐标排序:左侧对应局部极大值,右侧对应局部极小值。
x_max, x_min = np.sort(roots)

# 绘图
x_vals = np.linspace(-1, 5, 400)
# 在等距横轴网格上计算三次函数值,形成连续曲线纵坐标。
y_vals = f(x_vals)

# 为“极值点可视化”建立投影画布,给坐标、图例与标注预留空间。
plt.figure(figsize=(10, 6))
# 绘出三次函数主曲线,为两个驻点标记提供共同坐标参照。
plt.plot(x_vals, y_vals, label='$f(x) = x^3 - 6x^2 + 5x + 12$', color='#0A369D')
# 标出导数为零且曲率向下的局部最大值。
plt.plot(x_max, f(x_max), 'o', color='#F79F79', markersize=8, label=f'局部最大值 at x={x_max:.2f}')
# 标出另一驻点对应的局部最小值,便于与最大值比较。
plt.plot(x_min, f(x_min), 'o', color='#228B22', markersize=8, label=f'局部最小值 at x={x_min:.2f}')

# 将图题设为“函数及其局部极值点”,直接说明当前图形的比较目的。
plt.title('函数及其局部极值点', fontsize=16)
# 为“极值点可视化”,将横轴标为“x”,明确横向编码的变量。
plt.xlabel('x', fontsize=12)
# 将纵轴标为“f(x)”,明确纵向编码的变量。
plt.ylabel('f(x)', fontsize=12)
# 固定 `plt.axhline(0, color` 的业务取值与顺序,作为“极值点可视化”的可复算输入。
plt.axhline(0, color='gray', linestyle='--', linewidth=0.5)
# 为“极值点可视化”添加辅助网格,便于比较位置、斜率或组间差异。
plt.grid(True, linestyle='--', alpha=0.6)
# 显示“极值点可视化”图例,使颜色或线型与比较对象一一对应。
plt.legend(fontsize=12)
# 显示目标函数曲线及驻点标记,核对导数为零的位置对应局部极值候选。
plt.show()
横轴为 x、纵轴为三次函数 f(x);曲线上以不同颜色标出导数为零的局部最大值和局部最小值。
图 1: 函数 f(x) = x³ - 6x² + 5x + 12 的局部极值点

练习 2.5.2.1 微积分计算

给定函数 \(f(x_1, x_2) = -5x_1^3 - x_2^2 + x_1x_2 - 5\)

\(x_1=5, x_2=-1\) 时,求:

  1. \(\frac{\partial f(x_1, x_2)}{\partial x_1}\)
  2. \(\nabla f(x_1, x_2)\)

练习 2.5.2.1 手动求解

1. 求关于 \(x_1\) 的偏导数\(x_2\) 看作常数,对 \(x_1\) 求导:

\[ \large{\frac{\partial f}{\partial x_1} = \frac{\partial}{\partial x_1}(-5x_1^3 - x_2^2 + x_1x_2 - 5)} \]

\[ \large{= -5(3x_1^2) - 0 + (1 \cdot x_2) - 0 = -15x_1^2 + x_2} \]

代入 \(x_1=5, x_2=-1\)

\[ \large{\frac{\partial f}{\partial x_1} \bigg|_{(5, -1)} = -15(5^2) + (-1) = -15(25) - 1 = -375 - 1 = -376} \]

练习 2.5.2.1 手动求解 (续)

2. 求梯度 首先求关于 \(x_2\) 的偏导数 (把 \(x_1\) 看作常数):

\[ \large{\frac{\partial f}{\partial x_2} = \frac{\partial}{\partial x_2}(-5x_1^3 - x_2^2 + x_1x_2 - 5)} \]

\[ \large{= 0 - 2x_2 + (x_1 \cdot 1) - 0 = -2x_2 + x_1} \]

梯度向量是:

\[ \large{\nabla f(x_1, x_2) = \begin{bmatrix} \frac{\partial f}{\partial x_1} \\ \frac{\partial f}{\partial x_2} \end{bmatrix} = \begin{bmatrix} -15x_1^2 + x_2 \\ -2x_2 + x_1 \end{bmatrix}} \]

代入 \(x_1=5, x_2=-1\)

\[ \large{\nabla f(5, -1) = \begin{bmatrix} -15(5^2) + (-1) \\ -2(-1) + 5 \end{bmatrix} = \begin{bmatrix} -376 \\ 2 + 5 \end{bmatrix} = \begin{bmatrix} -376 \\ 7 \end{bmatrix}} \]

练习 2.5.2.1 Python 求解 (使用 SymPy)

我们可以使用符号计算库 SymPy 来验证我们的结果。

代码
# 导入 SymPy 并绑定为 `sp`,用于符号求偏导、构造梯度及在指定点代入求值。
import sympy as sp

# 定义符号变量
x1, x2 = sp.symbols('x1 x2')

# 定义函数
f = -5*x1**3 - x2**2 + x1*x2 - 5

# 对目标函数关于 `x1` 做符号求导,保留交叉项对该分量的贡献。
df_dx1 = sp.diff(f, x1)
# 打印关于 `x1` 的符号偏导,核对幂函数与交叉项的求导规则。
print(f'df/dx1 = {df_dx1}')

# 代入数值
val_df_dx1 = df_dx1.subs({x1: 5, x2: -1})
# 输出偏导数在 (5, -1) 的取值,核对局部变化率。
print(f'在 (5, -1) 处 df/dx1 的值为: {val_df_dx1}')

# 按 `x1`、`x2` 顺序计算两个符号偏导,组成梯度向量。
grad_f = [sp.diff(f, var) for var in (x1, x2)]
# 打印由两个符号偏导组成的梯度向量,核对分量顺序为 `x1`、`x2`。
print(f'\n梯度向量 ∇f = {grad_f}')

# 代入数值
val_grad_f = [expr.subs({x1: 5, x2: -1}) for expr in grad_f]
# 打印梯度在 `(5, -1)` 的数值 `[-376, 7]`,核对手算代入结果。
print(f'在 (5, -1) 处 ∇f 的值为: {val_grad_f}')
df/dx1 = -15*x1**2 + x2
在 (5, -1) 处 df/dx1 的值为: -376

梯度向量 ∇f = [-15*x1**2 + x2, x1 - 2*x2]
在 (5, -1) 处 ∇f 的值为: [-376, 7]

第三部分:统计学回顾

统计学:在不确定性中寻找规律

金融市场充满了不确定性随机性。明天的股价是多少?下个季度的GDP增长率如何?我们无法精确预测。

统计学是科学地处理不确定性的工具。它帮助我们:

  • 描述数据:用均值、方差等指标总结数据的特征。
  • 推断关系:用相关性、回归等方法发现变量间的联系。
  • 量化风险:概率论是衡量和管理金融风险的基础。

随机变量:不确定的数值结果

随机变量 (Random Variable) 是一个其数值取决于随机事件结果的变量。我们通常用大写字母表示,如 \(X\)

  • 离散随机变量:只能取有限个或可数个值。
    • 例子:掷骰子的点数 (1, 2, 3, 4, 5, 6);一天内某支股票上涨的天数。
  • 连续随机变量:可以取某一区间内的任何值。
    • 例子:明天沪深300指数的收益率;一家中国上市公司未来的盈利。

随机变量的一个具体实现值(观测值)用小写字母表示,如 \(x_i\)

期望:随机变量的“平均”取值

期望 (Expectation) 或期望值 \(E(X)\),是随机变量 \(X\) 所有可能取值按其概率加权的平均值。它是对随机变量中心趋势的度量。

  • 离散型\(E(X) = \sum_{k} x_k p(x_k)\)
    • 例子:掷一个公平骰子,期望值是 \(1\cdot\frac{1}{6} + 2\cdot\frac{1}{6} + \dots + 6\cdot\frac{1}{6} = 3.5\)
  • 连续型\(E(X) = \int_{-\infty}^{\infty} x f(x) dx\),其中 \(f(x)\) 是概率密度函数。

在金融中,预期收益率 (Expected Return) 就是资产未来收益率这个随机变量的期望值。

样本均值 vs. 期望

设样本均值为:

\[ \large{\bar X_n = \frac{1}{n}\sum_{i=1}^n X_i} \]

\(X_i\) 独立同分布且 \(E|X_i|<\infty\),大数定律给出 \(\bar X_n\xrightarrow{p}\mu=E(X)\):对任意 \(\varepsilon>0\)\(P(|\bar X_n-\mu|>\varepsilon)\to0\)

弱依赖序列也有相应定律,但须另加平稳/遍历或混合性与矩条件。金融收益可能存在依赖、非平稳或厚尾,不能只凭样本量大就假定近似可靠。

方差衡量离散,风险解释需要口径

方差 (Variance) 记为 \(\operatorname{Var}(X)\)\(\sigma^2\),衡量相对期望的平方离散程度。

  • 理论方差 (概率论中):

    \[ \large{\text{Var}(X) = E[(X - E(X))^2] = E(X^2) - [E(X)]^2} \]

  • 样本方差 (统计学中):

    \[ \large{s^2 = \frac{1}{n-1}\sum_{i=1}^n (x_i - \bar{x})^2} \]

\(X_1,\ldots,X_n\) 是同一总体的独立同分布随机样本且 \(E(X^2)<\infty\),则 \(E(s^2)=\sigma^2\)。这一无偏性不能外推到任意依赖或非平稳收益序列。

标准差 (Standard Deviation) \(\sigma = \sqrt{\text{Var}(X)}\),是方差的平方根,其单位与原始数据相同,更易于解释。

给定持有期、收益口径与风险偏好后,方差/标准差可作为波动风险代理之一;它不单独覆盖尾部风险、下行不对称或流动性损失。

固定预测点定义偏差、方差与噪声

\(\mathcal D\) 表示重复抽取的训练集,\(m(x_0)=E(Y\mid X=x_0)\)。固定 \(x_0\)

  • 偏差\(E_{\mathcal D}[\hat f_{\mathcal D}(x_0)]-m(x_0)\),相对真实条件均值定义。
  • 方差\(\operatorname{Var}_{\mathcal D}[\hat f_{\mathcal D}(x_0)]\),衡量重复训练样本下的预测波动。
  • 不可约噪声:若 \(Y_0=m(x_0)+\varepsilon_0\)\(E(\varepsilon_0\mid X=x_0)=0\),则 \(\operatorname{Var}(\varepsilon_0\mid X=x_0)\) 单列。

平方预测损失的期望同时对重复训练样本与新响应噪声取值。

偏差-方差的权衡

一个好的模型需要在偏差和方差之间取得平衡。

偏差-方差权衡 三个靶子展示了理想模型、欠拟合模型和过拟合模型的射击结果。 低偏差, 低方差 (理想模型) 高偏差, 低方差 (欠拟合) 低偏差, 高方差 (过拟合)

相关性:衡量线性关系

相关性 (Correlation) 是量化两个变量之间变动一致性程度的指标。

  • 正相关:一个变量增加时,另一个变量也倾向于增加。
  • 负相关:一个变量增加时,另一个变量倾向于减少。
  • 不相关:两个变量之间没有明显的线性关系。

重要警告:相关性 \(\neq\) 因果性! (Correlation does not imply causation!) 一个经典的例子:夏天的冰淇淋销量和溺水人数高度正相关,但这不意味着吃冰淇淋会导致溺水。背后隐藏的变量是“天气炎热”。

相关性可视化

代码
# 为“相关性可视化”导入 `numpy` 并绑定 `np`,用于执行当前任务的数组、数值或随机机制计算。
import numpy as np
# 为“相关性可视化”导入 `matplotlib.pyplot` 并绑定 `plt`,用于构建当前任务的坐标轴并呈现比较结果。
import matplotlib.pyplot as plt

# 为“相关性可视化”,固定随机数序列,使课堂示例可重复。
np.random.seed(42)
# 在给定区间均匀抽取 `x`,覆盖“相关性可视化”的输入范围。
x = np.random.rand(50)

# 构造正相关样本
# 在 `x` 上叠加标准差 0.1 的噪声,构造接近 45 度线的正相关响应。
y1 = x + np.random.normal(0, 0.1, 50)
# 构造近似不相关样本
# 在给定区间均匀抽取 `y2`,覆盖“相关性可视化”的输入范围。
y2 = np.random.rand(50)
# 构造负相关样本
# 在 `-x` 上叠加同尺度噪声,构造斜率为负的相关响应。
y3 = -x + np.random.normal(0, 0.1, 50)

# 创建本图所需画布与坐标轴,并保存到 `(fig, (ax1, ax2, ax3))`。
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5), sharex=True, sharey=True)

# 以 `x` 为横轴、`y1` 为纵轴绘制散点,展示“正相关、不相关与负相关”。
ax1.scatter(x, y1, alpha=0.7, c='#0A369D')
# 计算 `corr1`(相关系数),概括“相关性可视化”中的样本特征。
corr1 = np.corrcoef(x, y1)[0, 1]
# 将图题设为“正相关 (r ≈ {corr1:.2f})”,明确这里展示有限样本统计量。
ax1.set_title(f'正相关 (r ≈ {corr1:.2f})', fontsize=16)

# 以 `x` 为横轴、`y2` 为纵轴绘制散点,展示“正相关、不相关与负相关”。
ax2.scatter(x, y2, alpha=0.7, c='#465659')
# 计算 `corr2`(相关系数),概括“相关性可视化”中的样本特征。
corr2 = np.corrcoef(x, y2)[0, 1]
# 将图题设为“不相关 (r ≈ {corr2:.2f})”,明确这里展示有限样本统计量。
ax2.set_title(f'不相关 (r ≈ {corr2:.2f})', fontsize=16)

# 以 `x` 为横轴、`y3` 为纵轴绘制散点,展示“正相关、不相关与负相关”。
ax3.scatter(x, y3, alpha=0.7, c='#DC143C')
# 计算 `corr3`(相关系数),概括“相关性可视化”中的样本特征。
corr3 = np.corrcoef(x, y3)[0, 1]
# 将图题设为“负相关 (r ≈ {corr3:.2f})”,明确这里展示有限样本统计量。
ax3.set_title(f'负相关 (r ≈ {corr3:.2f})', fontsize=16)

# 遍历 `[ax1, ax2, ax3]` 的候选或观测,为“相关性可视化”逐项更新结果。
for ax in [ax1, ax2, ax3]:
    # 为“相关性可视化”,将横轴标为“X”,明确横向编码的变量。
    ax.set_xlabel('X')
    # 为“相关性可视化”添加辅助网格,便于比较位置、斜率或组间差异。
    ax.grid(True, linestyle='--', alpha=0.6)
# 将纵轴标为“Y”,明确纵向编码的变量。
ax1.set_ylabel('Y')

# 为“相关性可视化”,压缩子图留白,避免标题和坐标标签相互遮挡。
plt.tight_layout()
# 显示不同相关系数下的散点图,比较正相关、近零相关与负相关的方向和紧密程度。
plt.show()
三个散点面板共用横轴 x:左图点云向右上延伸表示正相关,中图无明显线性方向表示近似不相关,右图向右下延伸表示负相关。
图 2: 正相关、不相关与负相关

Pearson 相关系数

样本 Pearson 相关系数 \(r_{xy}\) 衡量有限样本中两个连续变量的线性关系;总体参数另记为 \(\rho_{XY}\)

\[ \large{r_{xy} = \frac{\sum_{i=1}^n (x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum_{i=1}^n (x_i - \bar{x})^2} \sqrt{\sum_{i=1}^n (y_i - \bar{y})^2}}} \]

总体相关系数定义为 \(\rho_{XY}=\operatorname{Cov}(X,Y)/(\sigma_X\sigma_Y)\);样本公式用同一批中心化观测直接计算,无需混用总体协方差符号。

  • \(r_{xy}\)\(\rho_{XY}\) 的取值范围均为 \([-1,1]\),但前者是样本统计量,后者是总体参数。
  • 绝对值越接近 1,线性关系越强;等于 \(1\)\(-1\) 表示完全正/负线性关系。
  • 接近 0 只表示线性关系弱,不排除非线性关系。

回归分析中的重要指标

在用模型(例如线性回归)进行预测时,我们需要一些指标来评估模型的好坏。这些指标都围绕着残差 (Residual)——真实值与预测值之间的差异——来构建。

  • 残差平方和 (RSS): 衡量模型整体误差的大小。
  • 总离差平方和 (TSS): 衡量数据本身的总波动。
  • 判定系数 (R²): 衡量模型解释了数据总波动的百分比。

残差平方和 (RSS) vs. 总离差平方和 (TSS)

\[ \large{\text{RSS} = \sum_{i=1}^n (y_i - \hat{y}_i)^2 \quad (\text{残差平方和})} \]

\[ \large{\text{TSS} = \sum_{i=1}^n (y_i - \bar{y})^2 \quad (\text{总离差平方和})} \]

  • TSS 代表了如果我们只用最简单的模型(即用均值 \(\bar{y}\) 去预测所有 \(y_i\))时,会产生的总误差。它为我们提供了一个比较基准。
  • RSS 是我们的复杂模型预测后,剩下的误差。
  • 一个好模型的 RSS 应该远小于 TSS。

判定系数 R²

判定系数 (Coefficient of Determination, R²) 是衡量模型拟合优度的核心指标。它表示因变量 \(y\) 的总变异中,可以被自变量 \(x\) 解释的比例

\[ \large{R^2 = 1 - \frac{\text{RSS}}{\text{TSS}} = \frac{\text{TSS} - \text{RSS}}{\text{TSS}}} \]

  • \(R^2\) 的取值范围通常在 [0, 1] 之间。
  • \(R^2 = 0.9\) 意味着按 TSS 口径,模型解释了样本总变异的 90%。
  • \(R^2\) 越高,模型的解释能力越强。
  • 边界:R² 是相对于同一目标样本均值基准的量。只有目标定义、样本和评估口径一致时,才适合比较模型;不能把不同数据集上的 R² 直接排序。

统计学部分练习:真实金融数据分析

理论知识需要通过实践来巩固。现在我们不再使用书上的小数据集,而是用真实的金融数据来计算这些统计量。

任务:分析江苏恒瑞医药 (600276.XSHG) 与浙江海康威视 (002415.XSHE) 在 2023 年的日收益率关系。

我们将从公开前复权行情 HDF5 选择性读取数据,并计算:

  1. 各自的平均日收益率和标准差。
  2. 它们之间的 Pearson 相关系数。

在查看实现前,提交数据文件/key/字段/复权口径/样本期、两股收益均值与标准差、共同交易日数及相关系数。缺共同日期对齐或复权口径者先补齐。

练习:先完成再查看答案:金融统计作业结果

提交一张统计表、一张对齐检查表和一句风险解释。以字段可追溯、日期内连接、统计量可复算为通过;提交后再进入参考实现。

获取并处理金融数据

代码
from pathlib import Path  # 管理下载后的课程数据路径
from urllib.request import urlretrieve  # 复用本章隐藏设置单元安装的浏览器标识下载器
import numpy as np  # 计算对数收益率
import pandas as pd  # 整理长三角公司行情
# 按 Linux 共享数据、Windows 共享数据、项目缓存的顺序选择行情文件。
price_data_path = next((candidate_path for candidate_path in [Path('/home/ubuntu/r2_data_mount/data/stock/stock_price_pre_adjusted.h5'), Path('C:/qiufei/data/stock/stock_price_pre_adjusted.h5'), Path('data/course/stock_price_pre_adjusted.h5')] if candidate_path.exists()), Path('data/course/stock_price_pre_adjusted.h5'))
if not price_data_path.exists():
    price_data_path.parent.mkdir(parents=True, exist_ok=True)
    urlretrieve('https://assets.qiufei.site/data/stock/stock_price_pre_adjusted.h5', price_data_path)
company_ids = ['600276.XSHG', '002415.XSHE']  # 固定江苏与浙江公司样本
company_price_frames = []  # 收集选择性读取的日行情
for company_id in company_ids:  # 逐公司读取以避免载入全市场文件
    company_prices = pd.read_hdf(price_data_path, key='data', where=f'order_book_id == "{company_id}"', columns=['order_book_id', 'date', 'close']).reset_index()  # 将 HDF 索引恢复为公司与日期列
    company_price_frames.append(company_prices)  # 保存当前公司记录
company_prices = pd.concat(company_price_frames, ignore_index=True)  # 合并两家公司行情
company_prices = company_prices.query("'2023-01-01' <= date <= '2023-12-31'")  # 固定 2023 年样本
close_prices = company_prices.pivot(index='date', columns='order_book_id', values='close').sort_index().dropna()  # 对齐共同交易日
returns = np.log(close_prices / close_prices.shift(1)).dropna()  # 以前复权收盘价计算对数收益率
returns = returns.rename(columns={'600276.XSHG': 'Hengrui', '002415.XSHE': 'Hikvision'})  # 使用可读公司简称
print(returns.head())  # 核对公开数据结果
order_book_id  Hikvision   Hengrui
date                              
2023-01-04     -0.010849  0.008547
2023-01-05      0.012597  0.019920
2023-01-06     -0.017623 -0.006086
2023-01-09     -0.020355  0.006086
2023-01-10      0.008132 -0.004309

参考答案(1/3):输入与对齐检查

代码
sample_row_counts = company_prices.groupby('order_book_id').size()  # 统计2023年筛选后两股原始价格行数
duplicate_key_count = company_prices.duplicated(['order_book_id', 'date']).sum()  # 核对公司日期键是否重复
missing_input_count = company_prices[['date', 'close']].isna().sum().sum()  # 核对日期与收盘价字段是否缺失
alignment_audit_table = pd.DataFrame({  # 采用两列纵向表,避免十一项检查横向溢出
    '检查项': ['文件', 'key', '字段', '复权口径', '样本期', '恒瑞原始行数', '海康原始行数', '共同价格日数', '收益共同日数', '重复键数', '日期或收盘价缺失数'],  # 固定提交要求的自查顺序
    '结果': ['stock/stock_price_pre_adjusted.h5', 'data', '证券代码、交易日、收盘价', '前复权收盘价', '2023-01-01至2023-12-31', int(sample_row_counts['600276.XSHG']), int(sample_row_counts['002415.XSHE']), len(close_prices), len(returns), int(duplicate_key_count), int(missing_input_count)]  # 用公开数据说明和动态行数填入检查结果
})
display(alignment_audit_table)  # 展示可直接自查的对齐检查表
表 1: 双股票收益任务的输入与日期对齐检查
检查项 结果
0 文件 stock/stock_price_pre_adjusted.h5
1 key data
2 字段 证券代码、交易日、收盘价
3 复权口径 前复权收盘价
4 样本期 2023-01-01至2023-12-31
5 恒瑞原始行数 242
6 海康原始行数 242
7 共同价格日数 242
8 收益共同日数 241
9 重复键数 0
10 日期或收盘价缺失数 0

练习 2.5.3 统计量计算

我们以恒瑞医药收益为 \(y\),海康威视收益为 \(x\)

代码
required_return_columns = {'Hengrui', 'Hikvision'}  # 确定统计表所需的两只股票列
assert required_return_columns.issubset(returns.columns)  # 缺任一目标列时立即停止,避免静默漏报
correlation = returns['Hengrui'].corr(returns['Hikvision'])  # 计算共同交易日样本 Pearson 相关系数
statistics_result_table = pd.DataFrame({  # 形成与提交要求一一对应的两行统计表
    '公司': ['恒瑞医药', '海康威视'],  # 使用业务可读的公司名称
    '平均日对数收益': [returns['Hengrui'].mean(), returns['Hikvision'].mean()],  # 报告两股样本均值
    '日收益标准差(ddof=1)': [returns['Hengrui'].std(), returns['Hikvision'].std()],  # 报告两股样本标准差
    '共同样本数': [len(returns), len(returns)],  # 显式报告同一日期内连接样本量
    '两股Pearson r': [correlation, correlation]  # 在两行保留同一个同期共动统计量
})
display(statistics_result_table.round(6))  # 展示可直接自查的统计结果表
公司 平均日对数收益 日收益标准差(ddof=1) 共同样本数 两股Pearson r
0 恒瑞医药 0.000690 0.018970 241 0.208435
1 海康威视 0.000134 0.020606 241 0.208435

结果解读与可视化

相关系数以当前公开数据版本的实际输出为准,不预设为 0.7。它只描述 2023 年共同交易日的线性共动,不代表稳定关系或因果联系。

代码
# 为“结果解读与可视化”导入 `seaborn` 并绑定 `sns`,用于编码当前任务的统计分布或分组关系。
import seaborn as sns
# 为“结果解读与可视化”导入 `matplotlib.pyplot` 并绑定 `plt`,用于构建当前任务的坐标轴并呈现比较结果。
import matplotlib.pyplot as plt

# 为“结果解读与可视化”建立投影画布,给坐标、图例与标注预留空间。
plt.figure(figsize=(11, 6))
# 用 `sns.regplot` 绘制散点并叠加线性拟合。
sns.regplot(data=returns, x='Hikvision', y='Hengrui',
            # 将散点设为半透明深蓝色,便于观察重叠密度。
            scatter_kws={'alpha':0.5, 'color': '#0A369D'},
            # 将拟合线设为红色,使其与散点清楚区分。
            line_kws={'color': '#DC143C'})
# 用图题概括“结果解读与可视化”的比较对象与当前计算结果。
plt.title(f'恒瑞医药与海康威视的日收益率(2023)\n相关系数 = {correlation:.2f}', fontsize=18)
# 将横轴标为“海康威视日收益率”,明确横向编码的变量。
plt.xlabel('海康威视日收益率', fontsize=14)
# 将纵轴标为“恒瑞医药日收益率”,明确纵向编码的变量。
plt.ylabel('恒瑞医药日收益率', fontsize=14)
# 为“结果解读与可视化”添加辅助网格,便于比较位置、斜率或组间差异。
plt.grid(True, linestyle='--', alpha=0.6)
# 呈现海康威视横轴与恒瑞医药纵轴的收益散点,供核对相关方向与离群点。
plt.show()
横轴为海康威视日收益率、纵轴为恒瑞医药日收益率;每点对应 2023 年共同交易日,点云斜率与离散反映同期联动。
图 3: 恒瑞医药与海康威视 2023 年日收益率散点图

章节总结:我们的数学工具箱

今天,我们重新审视了构建现代金融和量化分析的三大数学支柱:

  • 线性代数:提供了描述和操作多维金融数据的语言。
  • 微积分:让我们能够分析和优化动态变化的金融系统。
  • 统计学:使我们能在不确定性中量化规律、风险和关系。
数学工具箱总结 一个中心标题“数学工具箱”,分支出三个代表线性代数、微积分和统计学的图标。 金融量化分析的数学工具箱 线性代数 微积分 统计学

结束语

这些不是孤立的工具。在接下来的课程中,我们将看到它们如何协同工作,构建起强大的金融机器学习模型。

请务必花时间用Python复现今天的每一个例子。 这些基础越扎实,我们后面学习复杂模型时就会越轻松。

谢谢大家。

本章小结

  • 能区分 L2 归一化、中心化与 z-score,并在分母非零时解释中心化余弦与 Pearson 相关。
  • 维度、单位、ddof 与零范数必须在计算前声明。
  • 相关性和几何相似度不建立因果或经济机制。
  • 下一必修章先进入第 6 章验证基础,再把这些工具用于回归与分类。