数学基础
线代、概率、统计、微积分直觉。
40 分钟
数学基础
这一课你将能做到
- 用向量和点积表达「加权求和」,并会用余弦相似度计算两道题的相似程度
- 用条件概率和贝叶斯公式解释「做对一道题之后,掌握概率怎么更新」
- 手写一个梯度下降循环,拟合一元线性回归,看着 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