CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
机器学习入门/课时/数学基础
RawBlame
课时目录12 节

机器学习入门

  1. 01机器学习是什么
  2. 02数学基础
  3. 03Python 与数据栈
  4. 04数据预处理
  5. 05监督学习
  6. 06无监督学习
  7. 07模型评估
  8. 08Scikit-learn 工作流
  9. 09深度学习基础
  10. 10NLP 与 Transformer
  11. 11TensorFlow 与 PyTorch
  12. 12综合练习

数学基础

线代、概率、统计、微积分直觉。

40 分钟

数学基础

这一课你将能做到

  1. 用向量和点积表达「加权求和」,并会用余弦相似度计算两道题的相似程度
  2. 用条件概率和贝叶斯公式解释「做对一道题之后,掌握概率怎么更新」
  3. 手写一个梯度下降循环,拟合一元线性回归,看着 loss 一步步下降

为什么要学

机器学习的三大支柱全是数学:线性代数负责「数据怎么表示」(一张做题记录表就是一个矩阵),概率负责「不确定性怎么量化」(掌握度本质上是个概率),导数负责「模型怎么变好」(梯度下降就是顺着导数下坡)。初学者不需要会手推公式,但必须建立这三个直觉——否则调参时不知道学习率是什么,面试时讲不清模型怎么训练。

好消息:这一课的每个概念都会立刻翻译成 Python 代码,数学在这里是工具不是考试。

先建立图像

点积 = 加权求和:
  用户画像 [正确率 0.85, 用时 0.40, 题量 0.60]
  权重     [0.6,     0.2,      0.2   ]
  掌握分 = 0.6×0.85 + 0.2×0.40 + 0.2×0.60 = 0.71

梯度下降 = 下山:
        ╲
         ╲●        ●当前损失位置
          ╲ ↘ 每步沿「最陡下坡方向」(负梯度)走一小步
           ╲_
             ‾‾\__        ← 山谷底部 = 最小损失
                 ‾‾‾──__

跟着做

步骤 1:点积——把「加权求和」变成一行代码

import numpy as np

# 用户画像:[正确率, 平均用时(归一化), 做题量(归一化)]
user = np.array([0.85, 0.40, 0.60])
weights = np.array([0.6, 0.2, 0.2])       # 三项指标的重要程度

mastery_score = user @ weights            # @ 就是点积
print(f"掌握度得分: {mastery_score:.2f}")  # 0.71

user @ weights 等价于 np.dot(user, weights),等于 (0.6*0.85) + (0.2*0.40) + (0.2*0.60)。神经网络里每一层本质上都是一次大号点积。

步骤 2:余弦相似度——给题目找「相似题」

import numpy as np

def cos_sim(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))

# 每道题用「知识点考察向量」表示:[循环, 集合, 多线程, 异常]
q1 = np.array([0.9, 0.8, 0.1, 0.2])   # 主考循环+集合
q2 = np.array([0.8, 0.7, 0.2, 0.1])   # 和 q1 很像
q3 = np.array([0.1, 0.2, 0.9, 0.8])   # 主考多线程+异常

print(f"q1-q2 相似度: {cos_sim(q1, q2):.2f}")   # 0.99
print(f"q1-q3 相似度: {cos_sim(q1, q3):.2f}")   # 0.27

余弦相似度只看方向不看长度,取值 -1 到 1,越接近 1 越相似。推荐系统「相似题推荐」、向量检索都是它的变体。

步骤 3:贝叶斯——做对一道题后,掌握概率怎么更新

# 先验:做题之前估计 P(掌握) = 0.5
# 条件概率:掌握了的人 P(答对|掌握) = 0.9;没掌握的人 P(答对|没掌握) = 0.3
prior = 0.5
p_c_m = 0.9    # P(答对|掌握)
p_c_n = 0.3    # P(答对|没掌握)

p_correct = prior * p_c_m + (1 - prior) * p_c_n   # P(答对)
posterior = prior * p_c_m / p_correct             # P(掌握|答对)
print(f"答对一道题后,掌握概率从 {prior:.2f} 更新为 {posterior:.2f}")  # 0.75

这就是「知识追踪」的最简形式:每做一道题,用贝叶斯把掌握概率往真实水平修正一步。adaptive 出题系统的底层逻辑与此同源。

步骤 4:手写梯度下降——从 0 拟合 y = wx + b

import numpy as np

X = np.array([1, 2, 3, 4, 5], dtype=float)
y = np.array([3, 5, 7, 9, 11], dtype=float)   # 真实规律 y = 2x + 1

w, b = 0.0, 0.0        # 从零开始猜
lr = 0.01              # 学习率:每步走多远

for epoch in range(200):
    y_pred = w * X + b
    error = y_pred - y
    loss = np.mean(error ** 2)              # 均方误差
    grad_w = 2 * np.mean(error * X)         # loss 对 w 的导数
    grad_b = 2 * np.mean(error)             # loss 对 b 的导数
    w -= lr * grad_w                        # 顺着下坡方向更新
    b -= lr * grad_b
    if epoch % 40 == 0:
        print(f"epoch={epoch} loss={loss:.4f} w={w:.3f} b={b:.3f}")

print(f"最终: y = {w:.3f}x + {b:.3f}")      # 收敛到 y ≈ 2x + 1

运行后能看到 loss 从几百一路降到接近 0,w、b 收敛到 2 和 1。这 20 行代码就是所有模型训练的内核:算预测 → 算损失 → 算梯度 → 更新参数,循环。

讲清楚要点

  1. 向量和矩阵是数据的「容器语言」:一个用户画像是一行向量,一张做题记录表是一个矩阵,模型参数也是向量。把运算写成矩阵形式,代码短、底层还快(向量化)。
  2. 点积衡量「对齐程度」:加权求和、神经网络的线性层、相似度计算,底层全是点积。
  3. 条件概率 P(A|B) 有方向:P(答对|掌握) 和 P(掌握|答对) 是两个数,混用是最经典的概率错误。贝叶斯公式就是两者的换算器。
  4. 梯度是「多元函数的导数」:对每个参数分别求导,得到损失上升最快的方向;反方向走,损失就下降。
  5. 学习率决定训练成败:太大,一步迈过山谷来回震荡甚至发散(loss 变 NaN);太小,收敛极慢。0.001~0.1 是常用起点。

你可能会懵的地方

  • 数学要学到什么程度才能开始机器学习? 够用就行:点积/矩阵乘法、条件概率/贝叶斯、导数和链式法则。特征值分解、协方差矩阵这些等到 ml-unsupervised 讲 PCA 时再回来补,带着问题学效率最高。
  • 为什么文本相似度用余弦相似度而不用欧氏距离? 文本向量往往很长且稀疏,两篇长度差很多的文章方向可能一致(主题相同)。余弦只比方向,对向量长度不敏感;欧氏距离会被「文本长短」这种量纲差异带偏。
  • 梯度下降只保证找到局部最优,为什么还敢用? 线性回归、逻辑回归的损失函数是凸的,局部最优=全局最优;深度网络虽然非凸,但实践发现局部最优通常也足够好,加上随机性和动量,效果稳定可用。
  • 链式法则在机器学习里是干嘛的? 深度模型是函数套函数(一层套一层),反向传播就是用链式法则把「损失对最外层参数的导数」逐层往里传,从而算出每一层参数的梯度。ml-dl 会实际演练。
  • 概率模型输出的 0.8 能当成「80% 把握」吗? 看模型。逻辑回归经良好校准后接近真实概率;树模型和未校准模型的分数只是相对排序用。涉及决策阈值时要做概率校准(如 CalibratedClassifierCV)。

错法对照

错法问题正解
上来就啃《统计学习方法》推导推导脱离直觉,容易弃坑先跑通代码建立直觉,再回头补推导
学习率设 1.0 还问为什么 loss 爆炸步子太大直接发散从 0.01 起步,看 loss 曲线调
把 P(答对|掌握) 当 P(掌握|答对) 用条件方向搞反,结论完全错贝叶斯换算后再用
特征量纲悬殊直接算点积数值大的特征主导结果先标准化(ml-preprocess 详讲)
手写梯度下降忘了除以样本数 nlr 对批量大小敏感用 mean 而不是 sum

卡点急救

  1. 手写梯度下降 loss 变成 NaN:学习率太大,先除以 10;还不行检查数据里有没有极端值。
  2. loss 下降极慢:学习率太小,或特征没归一化(X 范围 0~240 时梯度天然很小,先除以量纲)。
  3. np.linalg.norm 报错或相似度全是 1:检查输入是不是一维向量;全 1 说明向量没有区分度,看看是不是忘了减均值或特征选错了。

面试常问

  • 讲一下梯度下降的原理。 目标是最小化损失函数。对参数求梯度(导数),沿负梯度方向以学习率为步长迭代更新,损失逐步下降;凸函数保证到全局最优,深度模型实践中收敛到足够好的局部最优。变体有批量/小批量/随机(SGD),深度学习默认小批量。
  • 余弦相似度和欧氏距离怎么选? 关注方向/形状(文本主题、用户偏好)用余弦;关注绝对位置和尺度(地理坐标、已经归一化的特征空间)用欧氏距离。高维稀疏向量通常余弦更稳。
  • 写一下贝叶斯公式并说个应用场景。 P(A|B) = P(B|A)·P(A) / P(B)。应用:自适应刷题系统,用先验掌握概率和「答对条件下各水平用户的答对率」,在每次作答后更新后验掌握概率。

自测三问

  1. user @ weights 在算什么?和神经网络哪一步对应?
  2. 为什么 P(A|B) ≠ P(B|A)?贝叶斯公式怎么把两者联系起来?
  3. 学习率 0.01 时 loss 稳定下降,改成 1.0 会发生什么?

小结一句话

线性代数负责表示数据,概率负责量化不确定,梯度下降负责让模型变好——三个直觉建起来,后面的模型课就不虚。

延伸

  • NumPy 官方文档
  • 下一课:ml-python Python 与数据栈——numpy/pandas/matplotlib 三件套,处理真实做题记录。
加载本节练习…
← 上一课机器学习是什么下一课 →Python 与数据栈