{ "cells": [ { "cell_type": "markdown", "id": "b598592c", "metadata": {}, "source": [ "# 线性回归示例:运动时间与行进距离\n", "输入是运动时间(秒),输出是距离(厘米)。\n", "本例依次完成:观察数据 → 建立直线模型 → 训练 → 预测 → 用新记录检验。" ] }, { "cell_type": "markdown", "id": "02175c08-b697-44e9-87d1-2faa7506d0d4", "metadata": {}, "source": [ "=> 我们要安装的第三方库有 `matplotlib` 、 `scikit-learn`(机器学习库)" ] }, { "cell_type": "markdown", "id": "4db4f3eb", "metadata": {}, "source": [ "## 1. 数据与散点图\n", "两个列表按位置一一对应。先看趋势,再决定是否尝试直线模型。" ] }, { "cell_type": "code", "execution_count": null, "id": "5642ec21", "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "times = [1, 2, 3, 4, 5, 6]\n", "distances = [12, 19, 31, 39, 52, 58]\n", "\n", "## 绘制图表" ] }, { "cell_type": "markdown", "id": "f7443183", "metadata": {}, "source": [ "## 2. 模型与最小二乘\n", "模型为 $\\hat y=wx+b$。用训练均方误差衡量拟合:$MSE=\\frac1n\\sum(y_i-\\hat y_i)^2$。\n", "一个特征且x不全相同时,可以直接求:\n", "$w=\\frac{\\sum(x_i-\\bar x)(y_i-\\bar y)}{\\sum(x_i-\\bar x)^2}$,$b=\\bar y-w\\bar x$。\n", "下面把公式翻译成列表、循环和函数调用。先看参数怎样由数据得到。" ] }, { "cell_type": "code", "execution_count": null, "id": "063f5f24", "metadata": {}, "outputs": [], "source": [ "x_mean = sum(times) / len(times)\n", "y_mean = sum(distances) / len(distances)\n", "numerator = 0.0\n", "denominator = 0.0\n", "for x, y in zip(times, distances):\n", " numerator += (x - x_mean) * (y - y_mean)\n", " denominator += (x - x_mean) ** 2\n", "assert denominator > 0, \"时间不能全部相同\"\n", "w_manual = numerator / denominator\n", "b_manual = y_mean - w_manual * x_mean\n", "\n", "def training_mse(w, b):\n", " squared_errors = []\n", " for x, y in zip(times, distances):\n", " squared_errors.append((y - (w * x + b)) ** 2)\n", " return sum(squared_errors) / len(squared_errors)\n", "\n", "print(f\"x均值={x_mean:.4f}, y均值={y_mean:.4f}\")\n", "print(f\"w={w_manual:.6f}, b={b_manual:.6f}\")\n", "for w, b in [(8, 5), (10, 0), (w_manual, b_manual)]:\n", " print(f\"w={w:.4f}, b={b:.4f}, MSE={training_mse(w, b):.6f}\")" ] }, { "cell_type": "markdown", "id": "e1610d16", "metadata": {}, "source": [ "## 3. 用scikit-learn拟合\n", "X的形状是“样本数×特征数”。本例6条训练记录,每条只有时间1个特征。" ] }, { "cell_type": "code", "execution_count": null, "id": "70e90897", "metadata": {}, "outputs": [], "source": [ "from sklearn.linear_model import LinearRegression\n", "\n", "# 用代码实现一个自己的线性回归模型" ] }, { "cell_type": "markdown", "id": "0cbc17aa", "metadata": {}, "source": [ "## 4. 在未参与训练的数据上检验\n", "以下两条测试记录没有传入fit。MAE是绝对误差的平均值,单位为厘米。" ] }, { "cell_type": "code", "execution_count": null, "id": "b4db8ed8", "metadata": {}, "outputs": [], "source": [ "from sklearn.metrics import mean_absolute_error\n", "\n", "X_test = [[2.5], [5.5]]\n", "y_test = [26, 54]\n", "\n", "# 预测一下其他数据?" ] }, { "cell_type": "code", "execution_count": null, "id": "19bb2d57-f843-405b-ac04-f6e19ca5cf3d", "metadata": {}, "outputs": [], "source": [ "mae = mean_absolute_error(y_test, y_pred)\n", "for x, actual, pred in zip(X_test, y_test, y_pred):\n", " print(f\"时间{x[0]}s:记录{actual:.3f}cm,预测{pred:.3f}cm\")\n", "print(f\"测试MAE = {mae:.6f} cm\")\n", "manual_mae = sum(abs(a - p) for a, p in zip(y_test, y_pred)) / len(y_test)" ] }, { "cell_type": "markdown", "id": "b38b38f2", "metadata": {}, "source": [ "## 5. 画出拟合直线与测试记录" ] }, { "cell_type": "code", "execution_count": null, "id": "a093a96b", "metadata": {}, "outputs": [], "source": [ "line_x = [[0], [7]]\n", "line_y = model.predict(line_x)\n", "\n", "# 画出拟合曲线" ] }, { "cell_type": "markdown", "id": "fb53fa5f", "metadata": {}, "source": [ "## 6. 改变一条记录,观察结果\n", "把第一格中训练距离的58改为90,然后重新运行数据、拟合和测试单元格。\n", "比较斜率、截距和测试MAE。不要让测试记录参与拟合,也不要继续引用改变前的误差。\n", "实验后把数据恢复成原值,再重启内核并全部运行。\n", "\n", "思考:为什么不能直接把时间扩大到100秒?如果只有两条测试记录,能否说明模型在所有情况下都准确?\n", "\n", "参考:https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.14" } }, "nbformat": 4, "nbformat_minor": 5 }