人人都能学编程
English 开始学习
专项 · 人工智能第 2 课 / 共 6 课免费阅读

线性回归与损失 · 人工智能基础

怎么找出一条穿过一堆杂乱点的最好的直线?

课程目录

为什么需要它

线性回归是最简单的会学习的模型:用一条直线从特征预测一个数。它至今仍被到处用来做快速估算,而且它引出了所有模型共有的两个概念:一个带有可调数字的预测函数,以及一个给预测的错误程度打分的损失。

直觉理解

模型是一条直线,有两个可以调的数:权重 w(斜率)和偏置 b(在 x 为 0 时的位置):

预测值 = w × x + b

要比较两条直线,就量出每个预测值离真实值有多远,平方,再求平均。这就是均方误差(MSE):

MSE = (预测值 − 真实值)² 的平均值

平方有两个作用:偏高和偏低的误差不会互相抵消;一次大的偏差比小的偏差分量重得多。最好的直线就是 MSE 最小的那条。

只有一个特征时,有一个精确的公式(最小二乘法)。设 x̄ 和 ȳ 是平均值:

w = Σ (x − x̄)(y − ȳ) / Σ (x − x̄)²
b = ȳ − w × x̄

下一课你会用另一种方法一步一步找到同一条直线,那种方法对没有公式可用的模型也有效。

定义

线性回归

Predicting a number with a straight line: w × x + b.
用一条直线预测一个数:w × x + b。

权重和偏置

The tunable numbers of a model. In a line, the weight is the slope and the bias is the value at x = 0.
模型里可以调整的数。在直线里,权重是斜率,偏置是 x = 0 时的值。

损失

A number that says how wrong the predictions are. Training tries to make it small.
衡量预测有多错的一个数。训练就是想办法让它变小。

均方误差

The average of the squared differences between predictions and actual values.
预测值与真实值之差的平方的平均值。

示例

给两条直线打分

动手试试

拟合得更好的直线,损失更低。

xs = [1, 2, 3, 4]
ys = [3, 5, 7, 9]

def predict(w, b, x):
    return w * x + b

def mse(w, b):
    errors = [(predict(w, b, x) - y) ** 2 for x, y in zip(xs, ys)]
    return sum(errors) / len(errors)

print(mse(1, 1))
print(mse(2, 1))
输出
7.5
0.0
逐步执行
  1. L8每个点一个平方误差。
  2. L11预测值 2、3、4、5 分别差 1、2、3、4:(1 + 4 + 9 + 16) / 4 = 7.5。7.5
  3. L12y = 2x + 1 穿过每一个点:完全没有误差。0.0

最小二乘直线

动手试试

真实数据有噪声;公式依然能找到最好的直线。

xs = [1, 2, 3, 4, 5]
ys = [2.1, 3.9, 6.2, 7.8, 10.1]

mx = sum(xs) / len(xs)
my = sum(ys) / len(ys)
w = sum((x - mx) * (y - my) for x, y in zip(xs, ys)) / sum((x - mx) ** 2 for x in xs)
b = my - w * mx
print(round(w, 2), round(b, 2))
print(round(w * 6 + b, 1))
输出
1.99 0.05
12.0
逐步执行
  1. L4平均值:x̄ = 3,ȳ = 6.02。
  2. L6x 和 y 一起变化的程度,除以 x 自己变化的程度。
  3. L7最好的直线一定经过平均值那个点。
  4. L9用学到的直线预测 x = 6。

常见错误

用直线去拟合曲线

如果点是弯的,最好的直线仍然会有系统性的错误。先把数据画出来看看。

在数据范围之外预测

从 40–120 m² 的房子学到的直线,对一栋 900 m² 的豪宅说不出什么可靠的结论。

一个离群点拉歪整条线

平方误差会重罚大的偏差,所以一行错误的数据(比如多打了一个零)就能把整条直线拉歪。要清洗数据。

小测验

1. 这段代码会输出什么?

actual = [10, 20, 30, 40]
predicted = [12, 18, 30, 44]
errors = [(p - a) ** 2 for p, a in zip(predicted, actual)]
print(sum(errors) / len(errors))
  1. A
    6.0
  2. B
    2.0
  3. C
    24
查看答案

答案:A

平方误差 4、4、0、16,加起来 24;平均是 6.0。

2. 为什么要把误差平方,而不是直接求平均?

  1. A让偏高和偏低的误差不能互相抵消,并让大的偏差分量更重
  2. B因为负数不能求平均
  3. C为了让损失更好读
查看答案

答案:A

+5 和 −5 平均是 0,会掩盖两个糟糕的预测。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出沿着直线走

    准确写出它打印的内容。

  2. 改需求互相抵消的误差

    这个损失函数对明显错误的预测也报告完美的 0.0:一个偏高、一个偏低,正好抵消。修改 mse,让它返回均方误差(要平方)。

  3. 从零写拟合直线

    写一个 fit(xs, ys),用本课的公式返回最小二乘直线的 (w, b)。xs 里至少有两个不同的值。

    fit([1, 2, 3, 4], [3, 5, 7, 9])   # (2.0, 1.0)

在互动课里练这一课

打开互动课,这些例子都能直接改、直接运行,练习题提交马上判题。免费开始,不用注册。

互动课按顺序解锁:前面的课还没学,会先带你到课程地图。

本课术语

术语中文英文定义
Linear regression线性回归Predicting a number with a straight line.
Loss损失A score for how wrong predictions are.
Mean squared error均方误差The average of squared prediction errors.