📊 第8章 机器学习 Scikit-Learn
📄 一句话概括

十八套房、两个特征,学出面积系数 1.0489、房龄系数 -2.2789。 训练集 R 方 0.9962,测试集 0.9830,测试 RMSE 3.93 万元。 训练集分数比测试集高是正常的,差得太多才叫过拟合。

📝 本章和前面几章的关系

这一篇把上一篇的三步走完整跑一遍:划分数据、训练、打分。 数据是自造的十八套房,面积、房龄两个特征,单位分别是平米、年、万元。

一、最小二乘在干什么

它要找一条直线(或平面),让所有点到这条线的竖直距离平方和最小。 「平方」是为了让正负误差不互相抵消,也让大误差罚得更重。 有解析解,直接算出来,不用迭代。这正是它快的原因。

sklearn 里就是 LinearRegression(),一行建好,一行 fit 完。

二、为什么要留一份测试集

十八套房,分十三套训练、五套测试,比例大约七三开。 训练集学规律,测试集考成绩。 拿训练集考自己,等于考前把答案给了学生,考一百分也说明不了什么。

train_test_split 的 random_state=42 是种子。不写的话每次划分都不一样。 不写种子,分数就忽高忽低,两个模型根本没法比。

三、系数怎么读

截距 43.3143,面积系数 1.0489,房龄系数 -2.2789。 面积每多一平米,价格多 1.05 万;房龄每多一年,价格少 2.28 万。 正号同向、负号反向。房龄系数是负的,符合常识。

但两个系数不能直接比大小:一个以平米计、一个以年计,量纲差太远。

四、分数怎么读:R 方和 RMSE

训练集 R 方 0.9962,测试集 0.9830。 R 方是「解释了多少波动」,1 是完美,0 是跟猜平均值一样。 测试集 RMSE 是 3.93 万元,意思是「平均每次预测差三万多」。

两个指标要一起报:R 方是相对值好看,RMSE 是绝对值好懂。 只报 R 方 0.98,读者不知道是差 3 万还是差 30 万。

五、训练分比测试分高,正常吗

这次训练 0.9962,测试 0.9830,差了 0.013。 训练集通常比测试集好看,这不算问题。模型见过训练集,当然考得好。 判断标准不是「差没差」,而是「差多少」。差 0.01 到 0.05 很正常。

差 0.3 就得回头看:要么特征不够,要么样本太少,要么模型太复杂。

六、动手 Demo:最小二乘回归:预测房价

十八套房,面积和房龄两个特征,价格是目标。 先划分训练测试集,再训练、看系数、算 R 方和 RMSE。

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split

AREA = [62, 75, 88, 95, 105, 118, 128, 70, 82, 100, 112, 92,
        66, 79, 91, 108, 122, 86]
AGE = [15, 12, 8, 5, 3, 2, 1, 18, 10, 6, 4, 9,
       14, 11, 7, 5, 2, 9]
PRICE = [78, 92, 118, 128, 146, 163, 172, 76, 100, 134, 154, 118,
         82, 98, 124, 148, 168, 112]

X = np.array([[AREA[i], AGE[i]] for i in range(18)], dtype=float)
y = np.array(PRICE, dtype=float)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=42)
print("训练 %d 条,测试 %d 条" % (len(Xtr), len(Xte)))

m = LinearRegression().fit(Xtr, ytr)
print("截距 %.4f,面积 %.4f,房龄 %.4f"
      % (m.intercept_, m.coef_[0], m.coef_[1]))

print("训练 R 方 %.4f,测试 R 方 %.4f"
      % (r2_score(ytr, m.predict(Xtr)), r2_score(yte, m.predict(Xte))))
print("测试 RMSE %.2f 万元"
      % (mean_squared_error(yte, m.predict(Xte)) ** 0.5))

print("一套 100 平米、5 年房龄的预测价:%.2f 万元"
      % m.predict([ [100, 5]])[0])

实跑输出:

--------------------------------------------------------------------
最小二乘回归:预测房价
--------------------------------------------------------------------

  ① 数据长什么样
  --------------------------------------------------------------------
  十八套房,两个特征:面积(平米)和房龄(年),目标是价格(万元)。

| 面积 | 房龄 | 价格 |
|---:|---:|---:|
| 62 | 15 | 78 |
| 75 | 12 | 92 |
| 88 | 8 | 118 |
| 95 | 5 | 128 |
| 105 | 3 | 146 |
| 118 | 2 | 163 |
| 128 | 1 | 172 |
| 70 | 18 | 76 |

  面积从 62 到 128 平米,房龄从 1 到 18 年,价格从 76 到 172 万。
  ! 样本只有十八个,结论只能当练习用。真做房价模型,几百上千条才算起步。

  ② 留一部分做考试
  --------------------------------------------------------------------
  总共 18 条,训练集 13 条,测试集 5 条。
  训练集学规律,测试集考成绩。拿训练集考自己,等于把答案提前给了学生。
  ! random_state=42 是写死的种子。不写的话每次划分都不一样,分数忽高忽低没法比。

  ③ 训练与系数
  --------------------------------------------------------------------
  截距 43.3143,面积系数 1.0489,房龄系数 -2.2789。
  读法:面积每多一平米,价格多 1.0489 万;房龄每多一年,价格少 2.2789 万。
  系数为正说明同向,为负说明反向。房龄系数是负的,符合常识。
  ! 系数的大小不能直接比重要性——面积以平米计、房龄以年计,量纲不同,得先标准化。

  ④ 打分:R 方和 RMSE
  --------------------------------------------------------------------
  训练集 R 方 0.9962,测试集 R 方 0.9830。
  测试集 RMSE 3.93 万元。
  R 方是「解释了多少波动」,越接近 1 越好;RMSE 是「平均差多少万」,越小越好。
  两个指标一起报:R 方好看不代表误差小,单位不一样,读者感受也不一样。
  ! R 方 0.9 的意思是「价格的波动里有九成能被面积和房龄解释」,剩下一成是别的因素。

  ⑤ 训练集比测试集好,正常吗
  --------------------------------------------------------------------
  这次训练集 R 方 0.9962,测试集 0.9830。
  训练集通常比测试集好看,这不算问题。差得太多才是问题——那叫过拟合。
  判断标准不是「差没差」,而是「差多少」。差个 0.05 无妨,差 0.3 就得回头看。
  ! 样本只有 5 条测试数据,R 方的波动会很大。小样本上的分数,看趋势别看小数位。

test_size=0.25 是「四分之一拿去考试」。样本少时常用 0.2 到 0.3。 random_state 一定要写。同一份数据换一次划分,R 方可能差零点几。 predict 的入参形状要和训练时一致:两个特征就写两个数,[ [100, 5]]。

30 秒实验

  1. 把 random_state 改成 7,再跑一次,看测试 R 方差多少。
  2. 只留面积一个特征,去掉房龄,看 R 方掉多少。
  3. 想一想:如果 R 方 0.98 但 RMSE 30 万,这个模型能用吗?

常见误区

  1. 不划分测试集:训练分再高,也不知道模型在新数据上行不行。
  2. 不写 random_state:每次划分不同,前后两次结果没法比。
  3. 只报 R 方不报 RMSE:读者感受不到「差多少钱」。
  4. 直接比系数大小:量纲不同,得先标准化才能比重要性。
自测三问(点开对答案) 1. 为什么必须留测试集? —— 训练集只能说明「背得下来」,测试集才能说明「会不会做新题」。 2. R 方 0.9830 是什么意思? —— 价格波动里有 98.3% 能被面积和房龄解释,剩下 1.7% 是别的因素。 3. 训练分比测试分高,什么时候该担心? —— 差得少很正常;差很多(比如 0.3)才说明过拟合。

系数看着还行,可一旦特征变多,最小二乘就不稳了。下一篇:岭回归。

相关笔记