Skip to content

20.1 数学与统计面试题

量化面试中数学和统计是最基础也最核心的考察维度。面试官不仅考察你能否算出正确答案,更看重你的推理过程和概率直觉。本章系统梳理高频考点,附 Python 模拟验证代码,帮助你建立从理论到实践的理解。

概率题

条件概率与贝叶斯定理

条件概率是量化面试中出现频率最高的数学题型之一。贝叶斯定理是解决条件概率问题的核心工具:

$$P(A|B) = \frac{P(B|A) \cdot P(A)}{P(B)} = \frac{P(B|A) \cdot P(A)}{P(B|A)P(A) + P(B|\neg A)P(\neg A)}$$

典型题:疾病检测问题

一种疾病在人群中的发病率为 1%。检测方法的准确率为 99%(即患者检测为阳性的概率为 99%,健康人检测为阴性的概率为 99%)。问:一个人检测为阳性,他真正患病的概率是多少?

这道题的核心陷阱在于忽略先验概率。直觉上很多人会回答 99%,但正确概率只有约 50%:

$$P(\text{患病}|\text{阳性}) = \frac{0.99 \times 0.01}{0.99 \times 0.01 + 0.01 \times 0.99} = 0.5 = 50\%$$

原因是健康人群基数(99%)远大于患病人群(1%),即使假阳性率只有 1%,产生的假阳性人数也等于真阳性人数。

PYTHON45 行 · 1.6 KB
📄此处有展示代码45 行 · 1.6 KB展开 ▼
python
import numpy as np


def simulate_disease_test(n_population: int = 100000,
                           prevalence: float = 0.01,
                           sensitivity: float = 0.99,
                           specificity: float = 0.99) -> dict:
    """蒙特卡洛模拟疾病检测问题"""
    
    # 生成人群
    n_sick = int(n_population * prevalence)
    n_healthy = n_population - n_sick
    
    # 检测结果
    # 患病者检测阳性概率 = sensitivity
    sick_positive = np.random.binomial(1, sensitivity, n_sick).sum()
    
    # 健康者检测阳性概率 = 1 - specificity
    healthy_positive = np.random.binomial(1, 1 - specificity, n_healthy).sum()
    
    total_positive = sick_positive + healthy_positive
    
    true_positive_rate = sick_positive / total_positive if total_positive > 0 else 0
    
    theoretical = (sensitivity * prevalence) / \
                  (sensitivity * prevalence + (1 - specificity) * (1 - prevalence))
    
    return {
        'simulated_rate': true_positive_rate,
        'theoretical_rate': theoretical,
        'n_sick': n_sick,
        'n_healthy': n_healthy,
        'sick_positive': sick_positive,
        'healthy_positive': healthy_positive,
        'total_positive': total_positive
    }


# 运行模拟
result = simulate_disease_test()
print(f"理论概率: {result['theoretical_rate']:.4f}")
print(f"模拟概率: {result['simulated_rate']:.4f}")
print(f"检测阳性总人数: {result['total_positive']}")
print(f"其中真患病者: {result['sick_positive']}")
print(f"其中假阳性: {result['healthy_positive']}")
点击展开可浏览运行结果
理论概率: 0.5000
模拟概率: 0.5071
检测阳性总人数: 1960
其中真患病者: 994
其中假阳性: 966

经典概率问题集锦

Monty Hall 问题(三门问题)

有三扇门,其中一扇后面有汽车,另外两扇后面是山羊。参赛者选择一扇门后,主持人(知道汽车在哪)会打开另一扇有山羊的门,然后问参赛者是否换门。问:换门是否增加获胜概率?

答案:换门获胜概率为 2/3,不换为 1/3。核心在于主持人的行为不是随机的——他一定不会打开有汽车的门。

PYTHON29 行 · 933 B
📄此处有展示代码29 行 · 933 B展开 ▼
python
def simulate_monty_hall(n_trials: int = 100000) -> dict:
    """蒙特卡洛模拟三门问题"""
    stay_wins = 0
    switch_wins = 0
    
    for _ in range(n_trials):
        doors = [0, 0, 0]
        car = np.random.randint(0, 3)
        doors[car] = 1  # 1 表示汽车
        
        # 参赛者初始选择
        choice = np.random.randint(0, 3)
        
        # 主持人打开一扇有山羊的门(不是参赛者的选择,也不是汽车)
        available = [i for i in range(3) if i != choice and doors[i] == 0]
        opened = np.random.choice(available)
        
        # 换门选择
        other = [i for i in range(3) if i != choice and i != opened][0]
        
        if doors[choice] == 1:
            stay_wins += 1
        if doors[other] == 1:
            switch_wins += 1
    
    return {
        'stay_win_rate': stay_wins / n_trials,
        'switch_win_rate': switch_wins / n_trials
    }
点击展开可浏览运行结果
Monty Hall 问题模拟 (n=10,000)
坚持原选择胜率: 33.3%
换门胜率: 66.7%

结论: 换门的获胜概率是坚持的 2.0 倍

生日问题

一个房间至少需要多少人,才能使得至少两人同一天生日的概率超过 50%?

答案:只需要 23 人。直觉上这个数字小得惊人。

$$P(\text{至少两人同生日}) = 1 - \frac{365 \times 364 \times ... \times (365-n+1)}{365^n}$$
PYTHON20 行 · 651 B
📄此处有展示代码20 行 · 651 B展开 ▼
python
def birthday_probability(n_people: int, days: int = 365) -> float:
    """计算n人中至少两人同生日的概率"""
    prob_all_different = 1.0
    for i in range(n_people):
        prob_all_different *= (days - i) / days
    return 1 - prob_all_different


def find_birthday_threshold(target_prob: float = 0.5, days: int = 365) -> int:
    """找到达到目标概率所需的最小人数"""
    prob = 0
    n = 1
    while prob < target_prob:
        n += 1
        prob = birthday_probability(n, days)
    return n


print(f"23人生日概率: {birthday_probability(23):.3f}")
print(f"50%概率需要人数: {find_birthday_threshold(0.5)}")
点击展开可浏览运行结果
📘 本段代码定义了 2 个函数/类:函数 `birthday_probability`(计算n人中至少两人同生日的概率)、函数 `find_birthday_threshold`(找到达到目标概率所需的最小人数)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

赌徒破产问题

一个赌徒初始有 i 元,每次下注 1 元,赢的概率为 p(获得 1 元),输的概率为 q=1p(失去 1 元)。目标赢到 N 元,破产为 0 元。求最终破产的概率。

p0.5 时:

$$P(\text{破产}|\text{初始资金}=i) = \frac{(q/p)^i - (q/p)^N}{1 - (q/p)^N}$$

p=0.5 时(公平赌博):

$$P(\text{破产}|\text{初始资金}=i) = 1 - \frac{i}{N}$$

关键洞见:即使 p=0.5(公平游戏),初始资金为 1 元、目标为 100 元时,破产概率高达 99%。这是"赌徒最终必定破产"这一直觉的数学基础。

统计题

假设检验

名词解释:假设检验

假设检验(Hypothesis Testing)是统计推断的核心方法。它通过样本数据来判断关于总体的某个假设是否成立。框架包括:原假设 H0(通常是无效应假设)、备择假设 H1、检验统计量、显著性水平 α 和 p 值。

p 值的正确定义

p 值是"在原假设为真的条件下,观察到当前检验统计量或更极端值的概率"。它不是"原假设为真的概率",也不是"效应量的度量"。

常见的面试误区:

  • p 值不是原假设为真的概率(那是贝叶斯后验概率)。
  • p < 0.05 只是说"如果原假设为真,这样的结果不太可能出现",不能说"备择假设为真的概率是 95%"。
  • p 值受样本量影响:样本量足够大时,任何微小的效应都能产生显著的 p 值。

置信区间

95% 置信区间的正确解释:

如果我们重复抽样无限多次,对每个样本计算 95% 置信区间,那么这些区间中有 95% 会包含真实的总体参数。

NOT:有 95% 的概率真值落在给定的区间内。(这个表述实际上是在做贝叶斯推断。)

均值的置信区间:

$$\bar{X} \pm t_{\alpha/2, n-1} \cdot \frac{s}{\sqrt{n}}$$

其中 tα/2,n1 是自由度为 n1 的 t 分布临界值,s 为样本标准差。

线性代数核心

特征值与特征向量

$$A\mathbf{v} = \lambda \mathbf{v}$$

在量化领域的应用:

  • PCA(主成分分析):协方差矩阵的特征向量对应主成分方向,特征值对应方差解释量。
  • 因子模型:对协方差矩阵进行特征分解,最大的几个特征值对应的因子可以解释大部分风险。
  • 投资组合优化:最小方差组合与协方差矩阵的特征分解密切相关。

PCA 推导要点

  1. 数据中心化:X=XX¯
  2. 计算协方差矩阵:Σ=1n1XTX
  3. 特征分解:Σ=VΛVT
  4. 投影:Z=XVk(选取前 k 个特征向量)
PYTHON54 行 · 1.4 KB
📄此处有展示代码54 行 · 1.4 KB展开 ▼
python
import numpy as np
from numpy.linalg import eig


def pca_from_scratch(X: np.ndarray, n_components: int = 2) -> dict:
    """
    手动实现 PCA
    
    Parameters
    ----------
    X : np.ndarray
        数据矩阵,shape (n_samples, n_features)
    n_components : int
        保留的主成分数量
    """
    n_samples = X.shape[0]
    
    # 1. 中心化
    X_centered = X - X.mean(axis=0)
    
    # 2. 协方差矩阵
    cov_matrix = X_centered.T @ X_centered / (n_samples - 1)
    
    # 3. 特征分解
    eigenvalues, eigenvectors = eig(cov_matrix)
    
    # 4. 按特征值降序排列
    idx = eigenvalues.argsort()[::-1]
    eigenvalues = eigenvalues[idx].real
    eigenvectors = eigenvectors[:, idx].real
    
    # 5. 投影到前 k 个主成分
    W = eigenvectors[:, :n_components]
    X_pca = X_centered @ W
    
    # 6. 方差解释比例
    explained_variance_ratio = eigenvalues[:n_components] / eigenvalues.sum()
    
    return {
        'transformed': X_pca,
        'components': W,
        'eigenvalues': eigenvalues[:n_components],
        'explained_variance_ratio': explained_variance_ratio
    }


# 测试PCA
np.random.seed(42)
X = np.random.randn(100, 5)
X[:, 1] = X[:, 0] * 0.8 + np.random.randn(100) * 0.2  # 添加相关性

result = pca_from_scratch(X, n_components=2)
print(f"前2个主成分的方差解释比例: {result['explained_variance_ratio']}")
print(f"累计解释: {result['explained_variance_ratio'].sum():.3f}")
点击展开可浏览运行结果
前2个主成分的方差解释比例: [0.32906059 0.24912032]
累计解释: 0.578

时间序列核心概念

平稳性(Stationarity):一个时间序列的均值和方差不随时间变化,且协方差只依赖于时间间隔。

单位根检验(ADF检验):检验时间序列是否存在单位根(即是否非平稳)。

协整(Cointegration):两个或多个非平稳时间序列的线性组合可能是平稳的。这是配对交易策略的统计学基础。

PYTHON26 行 · 837 B
📄此处有展示代码26 行 · 837 B展开 ▼
python
from scipy import stats


def test_stationarity(series: np.ndarray) -> dict:
    """手动实现简化的 DF 检验"""
    n = len(series)
    delta_y = np.diff(series)
    y_lag = series[:-1]
    
    # 回归: delta_y_t = gamma * y_{t-1} + e_t
    # 如果 gamma = 0,则存在单位根(非平稳)
    slope, intercept, r_value, p_value, std_err = stats.linregress(y_lag, delta_y)
    
    # DF 检验的临界值(比标准 t 分布更负)
    # 简化处理:使用 t 统计量
    se = std_err
    t_stat = slope / se
    
    # 近似的 DF 分布临界值(n=100 时约为 -2.89 at 5%)
    # 这里用绝对值粗略判断
    return {
        'test_statistic': t_stat,
        'p_value': p_value,
        'is_stationary': p_value < 0.05,
        'note': 'p值可能不精确,建议使用 statmodels.adfuller'
    }
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `test_stationarity`(手动实现简化的 DF 检验)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

常见面试题速查

线性回归的前提假设是什么?

  1. 线性关系(Linearity):因变量与自变量之间是线性关系
  2. 独立性(Independence):观测值之间相互独立
  3. 同方差性(Homoscedasticity):误差项的方差恒定
  4. 正态性(Normality):误差项服从正态分布
  5. 无多重共线性(No Multicollinearity):自变量之间不能高度相关

R2 和调整 R2 的区别是什么?R2 随变量增加单调不减;调整 R2 对多余的变量进行惩罚,只有变量带来的信息增量超过惩罚时才会增加。

中心极限定理是什么? 当样本量足够大时,样本均值的分布近似服从正态分布,无论原始总体的分布是什么。这是为什么正态分布如此重要,也是很多统计检验的理论基础。

量化面试中的数学和统计考察重在"概率直觉"和"概念理解"而非机械计算。使用 Python 模拟验证你的推理是一个很好的习惯——既能确认答案正确性,也能在面试中展示你的计算思维。