资讯动态

波士顿房价预测:线性回归原理、Scikit-learn实现与毕业设计避坑

发布时间:2026/10/8 16:56:14 来源:尧图企业网站定制
简介资源定位为基于线性回归的波士顿房价预测毕业设计项目面向计算机、人工智能等专业学生与开发者解决机器学习入门及课设毕设代码落地难题。项目采用批量梯度下降BGD优化线性回归模型完整流程包括boston.csv数据导入、训练集与测试集划分、数据归一化、参数初始化与模型训练代码均测试通过答辩评审平均分达96分。压缩包共6个文件以BGD_4.py、LinearRegression_1.py两个Python脚本为核心配合README说明文档、LICENSE许可、示意图PNG及gitignore配置整体仅133KB结构精简便于阅读。目前已有665人学习下载资源支持下载后私聊远程教学适合逐步跟练与二次扩展也可作为课设、毕设或入门实战参考。1. 波士顿房价预测的毕业设计跑通容易讲清楚难第一次跑波士顿房价预测很多人以为最难的环节是理解线性回归算法结果直接卡在了数据加载上新版 scikit-learn 删掉了load_boston()网上教程的代码复制过来就报错。这个被叫做“高分毕业设计”的题目核心就是把这类坑填平——一份能跑的 Python 源码、一份把实验过程讲清楚的文档说明、一份别人照着能复现的实验说明。它解决的是很具体的问题13 个特征怎么读入、模型怎么训练、R² 和残差怎么解读、毕业设计文档怎么组织才算完整。适合答辩选了回归类题目或者想从线性回归切入机器学习的读者。目标是让你从“能跑通”走到“能讲清楚”而不只是抄一个模型交差。2. 波士顿房价数据集与线性回归13 个特征到底在预测什么这个数据集最早由 Harrison 和 Rubinfeld 在 1978 年整理后来进入 UCI 机器学习库再后来被 scikit-learn 内置为教学数据集。它记录的是波士顿周边不同街区的房价中位数一共 506 条样本输入是 13 个与房屋、社区、区位有关的特征输出是目标值MEDV单位是千美元。放到今天这个数据本身已经没有时效性但它的规模、特征维度和线性关系都很适合做回归入门所以历届毕业设计里一直有它的身影。2.1 数据集结构506 条记录、13 个特征和 MEDV 目标值拿到源码后第一件事不是跑模型而是先把数据字段看清楚。13 个特征里有连续数值、有比例、还有一个 0/1 分类变量如果一股脑塞进模型而不看含义后面写文档和答辩都会吃亏。下面是我常用的特征速查表也是文档说明里“数据字典”这一节的素材字段含义备注CRIM城镇人均犯罪率连续值数值普遍较小ZN占地超过 2.5 万平方英尺的住宅用地比例部分值为 0INDUS非零售商业用地占比连续值CHAS是否邻近查尔斯河0/1 分类变量不是连续值NOX一氧化氮浓度浓度越高环境质量越差RM平均房间数通常与房价正相关AGE1940 年以前建成的自住房比例数值越大房屋越老DIS到波士顿五大就业中心的加权距离距离越远通常房价越低RAD到径向公路的便利指数取值离散不是连续变量TAX每万美元房产的税率与 RAD 相关性偏高PTRATIO城镇师生比师生比越高教育资源越紧张B城镇人口结构复合指标历史数据字段仅作特征使用LSTAT低收入人口比例与房价呈明显负相关MEDV自有住房中位数价格目标值单位千美元我一般会先跑一句df.info()和df.describe()确认有没有缺失值、量纲差异有多大。这里要特别留意CHAS是分类变量不要把它当连续值做标准化RAD的取值也比较特殊在后续做特征解释时要小心。2.2 线性回归原理与选型理由为什么这个模型够用线性回归假设目标值 (y) 和特征 (x_1, x_2, \dots, x_{13}) 之间存在线性关系[ \hat{y} \beta_0 \beta_1 x_1 \beta_2 x_2 \cdots \beta_{13} x_{13} ]训练的目标是找一组系数 (\beta)让预测值和真实值的均方误差MSE最小。最小二乘法有闭式解[ \beta (X^T X)^{-1} X^T y ]理论上可以直接算出最优系数但实际工程里我不会让代码去显式求逆矩阵。scikit-learn 的LinearRegression默认走最小二乘的 SVD 分解数值稳定性更好速度也够快506 条样本的规模连“计算量”都谈不上。选这个模型做毕业设计最核心的理由是“可解释”。决策树能给你 feature importance神经网络能给你高一点的 R²但只有线性回归能直接把每个特征的系数拿出来说清楚“房间数每多一间房价中位数预计变化多少”。答辩老师最喜欢问的就是这种问题系数表一摆比扯一堆黑匣子模型实在得多。它的短板也很明确线性假设太强。真实房价和特征之间往往存在非线性关系比如低收入比例LSTAT对房价的影响不是单调直线预测值偶尔会算出负数。这些不是 bug而是模型假设带来的边界文档说明里把这个写清楚反而显得你有理解。3. 把源码跑起来Python 环境、数据加载与训练评估流程这一章解决的是“照着做”的问题。先给环境建议和目录结构再给三块代码数据加载、模型训练、结果可视化。整套流程跑完你应该能看到 R²、MAE、RMSE 和残差图这个完整度已经能放进毕业设计的实验章节了。3.1 环境准备与项目结构先把目录和依赖摆清楚我一般会先用 Python 3.8 或更高版本配上 numpy、pandas、matplotlib、scikit-learn 这几个包。新版 scikit-learn 装起来很简单pip install scikit-learn就行。如果机器上没有 pip 或者装不动通常要先解决 Python 安装本身再装 numpy 和 pandas顺序别搞反。依赖文件我习惯写成这样numpy1.21 pandas1.3 matplotlib3.5 scikit-learn1.1 statsmodels0.13这些版本号只是基线不是硬性要求。statsmodels 是后面做统计显著性用的如果暂时不想装可以先把前四个跑通。项目目录我会分成四块这也是文档说明里开场就能交代的结构data/放boston_housing.csv或任意来源的波士顿房价数据文件src/数据加载、训练、评估的 Python 脚本figures/训练后生成的残差图、预测对比图docs/文档说明和实验说明也就是答辩要交的部分这样组织的好处是答辩时老师说“你的数据在哪、代码在哪、结果在哪”你能三句话指完不用在乱七八糟的文件里现找。3.2 数据加载与切分兼容新版 scikit-learn 的写法数据加载是整个项目最容易翻车的地方。老教程写的是sklearn.datasets.load_boston()但这个接口已经在新版 scikit-learn 中被移除了。我现在的习惯是优先用fetch_openml同时保留本地 CSV 的兜底路径这样不管评审老师机器上是什么版本代码都能跑。# 数据加载优先 fetch_openml失败则回退到本地 CSV import pandas as pd from sklearn.datasets import fetch_openml from sklearn.model_selection import train_test_split def load_boston_data(csv_pathNone): try: # fetch_openml 返回 DataFrame目标列名固定为 MEDV data fetch_openml(nameboston, version1, as_frameTrue) X data.data.astype(float) y data.target.astype(float) except Exception: # 兜底方案从本地 CSV 读取 df pd.read_csv(csv_path) X df.drop(columns[MEDV]) y df[MEDV] return X, y X, y load_boston_data(data/boston_housing.csv) # 切分训练集和测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 )test_size0.2表示留 20% 的样本做测试剩下 80% 训练这个比例对这个数据量很常见。random_state42固定随机种子保证每次运行切分结果一致答辩时你两次跑出来的数字是一样的不会被质疑结果不可复现。代码里的astype(float)是为了把 openml 返回的整型列统一转成浮点避免后面矩阵运算报类型错误。这里还有个细节本地 CSV 如果列名和MEDV不一致drop(columns[MEDV])会直接报错。所以拿到别人给的源码时先打开 CSV 看一眼表头不要假设字段名一定对得上。3.3 训练与评估回归系数、R²、MAE、RMSE 一起看数据切好之后训练代码其实只有几行。但评估部分我建议把 R²、MAE、RMSE 三个指标都打出来不要只贴一个 R²。原因放到下一章细说这里先给能跑的代码from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score # 训练线性回归模型 model LinearRegression(fit_interceptTrue) model.fit(X_train, y_train) # 在测试集上预测 y_pred model.predict(X_test) # 三个评估指标一起输出 r2 r2_score(y_test, y_pred) mae mean_absolute_error(y_test, y_pred) rmse mean_squared_error(y_test, y_pred) ** 0.5 print(fR2: {r2:.4f}) print(fMAE: {mae:.4f}) print(fRMSE: {rmse:.4f}) print(f回归系数: {model.coef_}) print(f截距: {model.intercept_:.4f})fit_interceptTrue让模型学习截距项也就是数学表达式里的 (\beta_0)这个参数默认就是 True写出来是提醒你它在起作用。model.coef_是 13 个特征的系数model.intercept_是截距。RMSE 我这里直接用mean_squared_error()的结果开根号而不是依赖某些版本里已经调整的squared参数这样代码在 sklearn 1.0 到 1.5 的各种版本下都不会出问题。训练完之后强烈建议画一张残差图。残差是真实值减预测值理想情况下应该随机散布在 0 附近如果出现明显的喇叭形或曲线形说明线性假设有问题。画图代码很短import matplotlib.pyplot as plt plt.figure(figsize(6, 4)) plt.scatter(y_pred, y_pred - y_test, alpha0.6) plt.axhline(0, colorred, linestyle--) plt.xlabel(预测房价) plt.ylabel(残差) plt.title(残差图) plt.tight_layout() plt.savefig(figures/residual.png, dpi150)这张图是实验说明里最有说服力的附件。答辩时老师问“模型好不好”你不仅能说指标还能指着图说“残差基本围绕零线随机分布没有明显模式”这一句话的得分远比报三个数字高。4. 必调参数与指标解读别只盯着 R² 一个数字线性回归的调参空间不像 XGBoost 那么大但也不是完全没有。真正拉开差距的是对参数含义和评估指标的理解。这一章把LinearRegression的关键参数、特征预处理方式以及三个指标怎么配合使用讲透。4.1 LinearRegression 的三个关键参数与特征预处理LinearRegression()在 sklearn 里有几个参数值得注意。第一个是fit_intercept前面已经提过控制是否拟合截距第二个是positive设为 True 时会用非负最小二乘强制所有系数不小于 0这在某些业务场景有意义但对波士顿房价来说不一定合适因为有些特征本身就与房价负相关第三个是normalize这个参数在新版里已经废弃了看到旧代码传它时可以直接删掉替代方案是用StandardScaler做标准化。我一般这样处理特征预处理from sklearn.linear_model import LinearRegression from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler pipe Pipeline([ (scaler, StandardScaler()), (reg, LinearRegression()) ]) pipe.fit(X_train, y_train)用 Pipeline 把标准化和模型训练串起来能避免一个经典错误先对整个数据集做标准化再切分训练测试集。那样做会把测试集的均值方差信息泄漏到训练过程里属于数据泄漏后面专门有一章讲。普通线性回归对标准化不是强需求因为系数本身有含义但如果你打算对比 Ridge、Lasso标准化就是必须的所以从一开始就用 Pipeline 最省事。4.2 R²、MAE、RMSE 和残差图怎么配合使用R² 是最常被贴出来的指标取值范围通常在 0 到 1 之间越接近 1 说明模型解释的方差比例越高。但 R² 有它的问题它只说“拟合得好不好”不说“误差到底有多大”。比如 R² 是 0.7你很难直接告诉老师房价预测平均偏几千美元。这时候要看 MAE 和 RMSE。MAE 是平均绝对误差单位跟目标值一致直观好解释波士顿房价以千美元计如果 MAE 是 3.0代表平均预测偏差约 3000 美元。RMSE 因为先平方再开方对大误差更敏感如果 RMSE 明显大于 MAE说明预测中存在个别偏差很大的样本把整体误差拉高了。两者差距越大越要回头查是不是有离群点。标准做法是把三者组合起来看先看 R² 判断整体拟合水平再看 MAE 给一个“平均错多少”的直观感受最后用 R² 与 MAE 的差距判断误差是否集中加上残差图基本把“模型怎么样”这个问题回答完整了。这里有个血泪经验很多初学者只看 R²看到 0.7 就觉得不错结果答辩老师问“误差到底多少”答不上来。把 MAE 和 RMSE 放进实验说明这关就稳了。4.3 回归系数解读一句话说清每个特征的边际影响线性回归系数解读是答辩的高频考点。公式很简单在其他特征不变的情况下某个特征每增加一个单位房价预计变化多少。我拿到系数表后一般只看几个方向明确的特征RM系数通常为正房间数越多房价越高这在直觉上说得通LSTAT系数通常为负低收入人口比例越高房价越低NOX系数通常为负空气污染越严重房价越低这三个特征和生活经验能对上写在文档里最容易让非技术的评委听明白。那些方向不明确、或者绝对值异常的系数往往是因为特征之间存在相关性也就是下一章要说的多重共线性。这里要提醒一句不要给系数编造精确数值。不同数据来源、不同切分方式跑出来的系数会有差异文档里写“方向为负、数值约多少”就够了重要的是解释逻辑而不是背一个数字。5. 常见问题与避坑线性回归毕设最容易翻车的五个地方这一章是踩坑记录每一条都是做这个项目时真实会遇到的问题按照“现象、原因、解决”讲清楚。5.1 load_boston() 消失新版 scikit-learn 的兼容性报错现象代码跑到from sklearn.datasets import load_boston直接报ImportError或者调用时提示找不到该模块。原因scikit-learn 出于数据伦理方面的考量在较新版本中移除了内置的波士顿房价数据集。网上大量旧教程还在用这个接口照抄必然翻车。解决换成fetch_openml(nameboston, version1)它在网络可用时会从 openml 公共数据源拉取同一份数据。如果评审机器没网就把数据提前下载成 CSV用 pandas 读取。这就是前面 3.2 节那段兼容代码存在的意义。5.2 数据泄漏先标准化还是先切分现象训练时 R² 很高测试集表现也不错但换了一台机器、换了一份数据效果明显变差。或者自信地写完代码被老师一句“你的标准化是不是用了全量数据”问住。原因很多人习惯先对整个 X 做StandardScaler再train_test_split。这样标准化时用到了测试集的均值和方差相当于测试集信息提前进入了训练流程。这不是玄学是实打实的数据泄漏。解决先切分再对训练集做fit_transform对测试集只做transform。最省心的做法是全部塞进 Pipeline像 4.1 节那样训练时只对训练数据拟合标准化参数预测时自动复用完全不会踩这个坑。5.3 预测出负房价线性假设的天然缺陷现象model.predict(X_test)出来的结果里有负数或者接近 0 的离谱数值。看着像 bug实际是模型在正常输出。原因线性回归的预测边界是直线没有上下限约束。当特征组合出现在训练样本覆盖范围之外时直线外推就会算出负值。房价不可能是负数这是模型假设和现实约束之间的冲突。解决首先在文档里如实写“线性模型在边界外推时可能出现不合理预测”这属于模型局限性分析不丢人。其次可以检查预测值和真实值的分布图如果只有个别负值说明模型整体还好如果大面积负值就要考虑特征变换或换用带约束的模型。答辩话术是模型适用于样本分布范围内的预测超出范围需要依赖特征约束或非线性模型。5.4 多重共线性系数符号和数值为什么会漂移现象单独做单特征分析时某个特征和房价正相关放进线性回归后系数反而变成负的。或者稍微改动一条样本某个系数就大幅跳动。原因波士顿房价数据里多个特征高度相关典型的是TAX和RAD、NOX和DIS。特征之间互相“抢功劳”最小二乘解变得不稳定系数不再代表干净的边际影响。解决先看相关性矩阵把相关系数超过 0.7 的特征对列出来。想保留解释性就删掉其中一个想提升稳定性用 Ridge 或 Lasso 做正则化。这个坑我会在进阶章补充代码。需要强调系数不稳定的问题不是代码 bug是数据本身的属性早点发现、主动处理反而能在文档里多写一节“特征共线性分析与处理”。5.5 文档说明与实验说明怎么写才算完整现象源码能跑但交上去的是空文档或者实验说明只有三行“运行 main.py得到结果”答辩老师当场皱眉头。原因毕业设计是“工程文字”的综合考核代码只占一半。文档说明讲不清实验背景、数据来源和模型选择实验说明没法复现结果都会被扣分。解决我一般会按这套结构组织直接照抄都行项目说明这个项目做什么用了什么模型目标是什么环境说明Python 版本、依赖包及版本号、安装步骤数据说明数据来源、字段字典、缺失值处理实验步骤数据切分比例、随机种子、标准化方式、训练流程结果分析R²、MAE、RMSE 三个指标加残差图结论与不足模型效果、共线性问题、线性假设的局限实验说明部分要把“怎么复现”写细命令是什么、预期输出是什么、关键指标范围大概多少。做到别人照着文档能在半小时内跑通这份说明就是合格的。这块是给你自己加分的不是应付差事。6. 进阶验证技巧正则化对照与统计显著性让答辩更稳到这个阶段基础版已经能跑通了。想再往上走一点就从“会调包”变成“懂统计”。6.1 对照组实验Ridge 与 Lasso 对比普通线性回归常见做法是加一组正则化对照用 Ridge 和 Lasso 跟普通线性回归比顺便解决上一章说的多重共线性问题from sklearn.linear_model import Ridge, Lasso for name, model in [ (Ridge, Ridge(alpha1.0)), (Lasso, Lasso(alpha0.1)), ]: pipe Pipeline([ (scaler, StandardScaler()), (reg, model) ]) pipe.fit(X_train, y_train) r2 r2_score(y_test, pipe.predict(X_test)) print(f{name}: R2{r2:.4f})alpha是正则化强度越大系数被压缩得越狠。Ridge 适合保留全部特征但让系数变稳Lasso 能把一部分系数压到 0起到特征选择作用。对比结果写进文档就是一组完整的对照实验比只有一个模型显得充实得多。6.2 statsmodels 输出 p 值与置信区间从调包到讲统计sklearn 的LinearRegression不输出 p 值和置信区间但答辩老师很可能问“哪些特征显著”。这时候补一段 statsmodels 的输出import statsmodels.api as sm X_const sm.add_constant(X_train) # 手动加截距列 ols sm.OLS(y_train, X_const).fit() print(ols.summary())sm.add_constant()给 X 加一列常数项对应截距。ols.summary()会输出每个系数的 p 值、置信区间和整体 F 统计量。p 值小于 0.05 的特征可以解释为“统计显著”这比单纯说“系数是正的”有力得多。我早年做这个项目时只调了 sklearn 一行 fit答辩被问“你凭什么说这个特征对房价有影响”的时候答不上来后来补了 statsmodels 的输出才把故事讲圆。现在我做任何回归项目都会先把普通最小二乘跑一遍、再加正则化对照、最后画残差图这套流程已经成了习惯。先把基础线性回归吃透再谈复杂模型这条路对毕业设计来说是最稳的。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑