type: note
title: 线性回归编程作业(复习周第1天)
date: 2026-08-21
description: 复习周第1天,自己动手重写 C1 线性回归:compute_cost + compute_gradient
2026-08-21 学习笔记
笔记区
核心观点
-
线性回归模型:预测 `f_wb = w·x + b`,任务是找到让代价最小的 w、b。
-
代价函数 `J(w,b) = (1/2m) Σ (f_wb − y)²` ------ 衡量预测与实际的差距,/2m 是为了求导方便把 2 消掉。
-
梯度下降:`w := w − α·∂J/∂w`,`b := b − α·∂J/∂b`,一步步往最低点爬。
-
梯度就是代价对各自参数的偏导:
-
对 w:`∂J/∂w = (1/m) Σ (f_wb − y)·x` ------ **带 x**
-
对 b:`∂J/∂b = (1/m) Σ (f_wb − y)` ------ **不带 x**
关键方法/流程
**compute_cost(代价函数)**
```python
cost = 0
for i in range(m):
f_wb = w*xi + b
cost += (f_wb - yi)**2 # 累加误差平方
total_cost = cost/(2*m) # 循环外统一 /2m
```
**compute_gradient(梯度)**
```python
for i in range(m):
f_wb = w*xi + b
dj_dw += (f_wb - yi)*xi # 对 w:乘 x
dj_db += f_wb - yi # 对 b:不乘 x
dj_dw /= m
dj_db /= m
```
**代码提醒**
-
`wxi` 是错的 → 要 `w*xi`。w 和 x 是两个变量,`wx` 不是一个东西。
-
结果要赋给函数骨架要返回的变量:`total_cost`(compute_cost)、`dj_dw`/`dj_db`(compute_gradient)。骨架里已有 `return total_cost` 和 `return dj_dw, dj_db`。
-
w 的梯度乘 x,b 的梯度不乘 x ------ 记法:"w 是斜率,爬坡看 x;b 是截距,平移跟 x 无关"。
-
**括号别掉**:`dj_dw += (f_wb - yi)*xi`。乘法优先级高于减号,掉括号写成 `f_wb - yi*xi` 会先算 `yi*xi`(错的)。要乘的是**整个预测偏差**,必须用括号包住 `(f_wb - yi)`。
实战记录
**向量化(用 np 替代 for 循环)** ------ 今天重新学的核心
| for 版 | 向量化版 | 干的啥 |
| --------------------------- | --------------------- | --------------- |
| `for ...: f_wb = w*xi+b` | `f_wb = w*x + b` | 一次算全部预测 |
| `cost += (f_wb-yi)**2` | `np.sum((f_wb-y)**2)` | 一次求和 |
| `dj_dw += (f_wb-yi)*xi` | `np.dot(err, x)` | 误差×x 点积求和 |
| `dj_db += f_wb-yi` | `np.sum(err)` | 误差求和 |
-
`np.dot` 底层是 **C 语言**,快得多;`for` 是 Python 逐条遍历,慢。样本少(97 个)没感觉,样本一多(100 万)差距就明显。
-
`np.dot(err, x)` = `Σ erri·xi`,正好替代 for 里那句 `dj_dw += (f_wb-yi)*xi`。
-
本作业是单变量(w 是标量),所以 `f_wb = w*x + b` 能直接数组乘;多变量时预测是 `np.dot(x, w) + b`,np 威力才真正显现。
**学习率 α**
-
太大:一步跨太大直接**跳过谷底**(overshoot),在谷底两侧来回震荡,严重时发散越走越远。
-
太小:每步挪一点,**收敛极慢**,龟速爬山。
-
所以 α 要取中庸值。
线索区(合上材料自问自答)
**Q: 代价函数为什么要除以 2m?**
A: 除以 m 是取平均,除以 2 是为了求导时把平方带来的 2 消掉,让梯度公式前面是 1/m 而不是 2/m,方便。
**Q: 梯度里对 w 为什么要乘 x、对 b 不乘?**
A: 因为 f = w·x + b,对 w 求偏导剩 x(斜率爬坡看 x),对 b 求偏导剩 1(平移跟 x 无关)。
**Q: 学习率设太大会怎样?太小呢?**
A: 太大会跳过谷底震荡/发散;太小收敛极慢。要取中间值。
**Q: 向量化为什么比 for 循环快?**
A: np.dot/np.sum 底层是 C 语言,一次性算所有样本;for 是 Python 逐条遍历。数据量大时差距明显。
**Q: for 版和向量化版算出来的结果一样吗?**
A: 一模一样,只是快慢差别。
总结
自己动手写线性回归的代价函数和梯度,理解了"梯度就是代价对参数的偏导"------w 的梯度带 x、b 的不带;学习率要取中间值;用 np 点积/求和替代 for 循环能大幅提速。
复习卡片
| 概念 | 一句话 | 我的场景 |
| ---------- | ----------------- | ---------------- |
| 代价函数 J | (1/2m)Σ(f−y)² | 衡量回归拟合好坏 |
| 梯度 ∂J/∂w | (1/m)Σ(f−y)x | w 怎么调 |
| 梯度 ∂J/∂b | (1/m)Σ(f−y) | b 怎么调 |
| 学习率 α | 太大震荡/太小龟速 | 调参中庸值 |
| 向量化 | np.dot/np.sum | 替代 for 提速 |