资讯动态

线性回归实现波士顿房价预测:Python机器学习大作业完整指南

发布时间:2026/10/14 14:01:17 来源:尧图企业网站定制
简介这是一份基于线性回归实现波士顿房价预测的Python源码大作业面向机器学习初学者与期末课程设计场景适合直接提交或二次学习。项目原创完成且已获导师指导并通过评分为97分包含梯度下降法BGD与小批量梯度下降算法MBGD两种实现覆盖数据导入、训练集测试集划分、归一化、参数初始化、损失函数迭代、测试预测与可视化等完整流程。压缩包共5个文件主要为2个Python脚本核心训练与MBGD对比实现、1张拟合效果图、1份说明文档及1个gitignore配置文件整体仅122KB结构精简、运行便捷。已有1455人学习下载说明该选题具备较高的参考价值。读者可拿到可直接运行的完整代码、损失变化曲线与预测效果可视化既能理解线性回归的梯度推导也能借鉴大作业的项目组织方式适用于课程设计、期末作业或机器学习入门实践。1. 波士顿房价预测为什么线性回归是入门大作业的首选如果你正在找一份能啃得动、又能在答辩时讲明白的Python大作业基于线性回归实现波士顿房价预测基本是机器学习入门里最稳妥的选题之一。它不需要GPU、不需要海量数据一个自带的数据集、几十行Python代码就能完成从数据清洗到模型评估的完整闭环哪怕你只是刚看完Python语法也能在两天内跑通。这个题目的价值在于它把线性回归模型、特征工程、训练集测试集划分、回归评估指标这些机器学习的核心概念全部串在了一起而且结果可解释、可视化好做、答辩不容易被问倒。本文会从原理到代码、从调参到踩坑把这个大作业完整拆给你可直接照着写进你的实验报告。2. 线性回归与波士顿房价最小二乘原理与3个必调的基础假设2.1 线性回归不是简单画一条线最小二乘损失函数的由来很多教程会把线性回归说成“找一条直线去拟合数据点”这句话在只有一个特征的二维平面上成立但在波士顿房价这种13个特征的多维场景里你拟合的是一个13维空间里的超平面。模型写出来是这个样子price w0 w1*CRIM w2*ZN w3*INDUS ... w12*LSTAT其中w0是偏置项w1到w12是每个特征的权重。训练过程就是找到一组w让模型预测的房价和真实房价之间的误差最小。这个误差的度量方式就是损失函数线性回归最常用的是均方误差MSEMSE (1/n) * Σ (y_i - y_pred_i)²最小二乘这个名字的由来就是因为我们要让误差的平方和最小。注意这里用了平方而不是绝对值不是说平方更“公平”而是平方函数是凸的、处处可导可以直接用偏导数为0求出解析解也可以用梯度下降一步步逼近。对大作业来说你不需要会手推整个矩阵求导但至少要能在报告里写出上面这个公式并说明为什么用平方而不是绝对值。2.2 波士顿数据集的数据设计逻辑与特征含义波士顿房价数据集由StatLib库提供采集的是1970年代波士顿地区506个街区的房价中位数每个样本有13个特征加一个目标值。这份数据在大学机器学习课程里用了二十多年虽然因为时代久远存在一些争议但它作为教学数据最大的优点是特征类型丰富、样本量适中、分布有规律适合做线性回归演示。写作业时你在报告里至少要讲清楚这几个关键特征特征名含义对模型的影响倾向CRIM城镇人均犯罪率越高房价越低RM平均房间数越高房价越高AGE自住单位比例老房子多房价偏低LSTAT低收入人口比例越高房价越低MEDV房价中位数目标值以千美元为单位在这13个特征里RM和LSTAT与房价的相关性最明显很多大作业会先画出这两个特征与房价的散点图来“证明”线性关系存在。这是个加分的做法因为答辩老师看到你在建模前做了探索性数据分析EDA印象分会完全不同。2.3 线性回归的3个前提假设与作业里的直观判断方法在项目报告里一定要留一小节写线性回归的假设检验。线性回归模型有几个统计前提虽然不是每一次大作业都会被严格检查但如果老师问起来你答不上来就会比较被动。第一个假设是特征与目标存在线性关系。判断方法很简单把每个特征和房价的散点图画出来看是否存在明显的线性趋势也可以用相关系数矩阵做整体检查。第二个假设是残差独立且同分布。直观判断是画残差图如果残差随机分布在零线附近没有明显趋势就算通过如果出现喇叭形或曲线形说明可能存在异方差或非线性关系。第三个假设是特征之间不存在严重多重共线性。检查方法是计算特征间的相关系数矩阵或者计算方差膨胀因子VIF。波士顿数据里TAX和RAD两个特征相关性很高这在作业里是一个可以拿出来讨论的优化点。提示你不需要用统计学软件去严格验证这三个假设散点图加残差图的组合已经足够撑起一份本科大作业的理论部分。3. 载入与预处理波士顿房价数据从 load_boston 到 DataFrame 的完整流程3.1 从 load_boston 到 DataFrame数据载入的两种姿势波士顿房价数据的载入方式比较特殊早期常用sklearn.datasets.load_boston但新版scikit-learn已经因为数据伦理原因移除了这个接口所以现在项目里更推荐直接读取csv文件。下面这段代码是两种方式都兼容的写法可以直接放进你的源码import pandas as pd import numpy as np from sklearn.datasets import fetch_openml # 方式一通过sklearn的fetch_openml获取 try: boston fetch_openml(nameboston, version1, as_frameTrue) df boston.frame print(fetch_openml 获取成功共 {} 条样本.format(df.shape[0])) except Exception as e: print(ffetch_openml 失败: {e}尝试本地CSV路径) # 方式二本地csv读取 df pd.read_csv(boston_housing.csv)代码说明fetch_openml(nameboston, version1, as_frameTrue)会返回一个DataFrame格式的数据列名是原本的大写形式。这里先尝试在线获取失败时落到本地csv保证在无网络的机房也能运行。如果你本地已经有csv文件直接注释掉fetch_openml那段用read_csv就够了。as_frameTrue这个参数很关键它会返回pandas DataFrame而不是numpy数组方便你用列名操作。拿到数据后第一件事是查看前几行和缺失值# 查看数据基本结构 print(df.head()) print(df.info()) print(df.isnull().sum()) # 拆分特征矩阵X和目标向量y # MEDV列是目标值其余13列是特征 X df.drop(columns[MEDV]) y df[MEDV] print(X.shape, y.shape)逻辑说明df.isnull().sum()是检查每个特征列是否有缺失值波士顿数据本身没有缺失但这一步是规范流程、必须保留因为换任何数据集都得先查这一步。drop(columns[MEDV])是把目标列从特征中移除y单独保存目标值。做完这一步你得确认X是 (506, 13) 的形状如果你打印出来不是这个尺寸说明数据源或切分有问题要回头检查列名差异。3.2 数据切分与样本顺序训练集测试集划分的4个关键参数划分训练集和测试集是实现环节里最容易被马虎处理的一步很多大作业因为乱切数据导致评估结果偏高答辩时一问就露馅。标准做法是用train_test_splitfrom sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, shuffleTrue ) print(f训练集样本数: {X_train.shape[0]}, 测试集样本数: {X_test.shape[0]})参数说明test_size0.2表示留出20%的数据做测试一般作业在0.15到0.3之间选不要太小否则评估结果方差大。random_state42是随机种子锁死它才能保证每次运行得到相同的划分这是作业可复现的基础。shuffleTrue表示切分前先打乱数据如果原始数据按地区有序排列、不打乱训练集和测试集的地域分布会严重失衡。这里有个细节要特别提醒切分的时机必须在任何特征缩放或预处理之前也就是先切分、后标准化。很多人习惯先标准化全量数据再切分这是数据泄露的典型错误后面避坑章节会专门展开。4. 从零实现到调用sklearn线性回归训练的两条路线与5个可调参数4.1 手写梯度下降版线性回归30行代码看清参数的迭代更新要体现大作业的“含金量”建议在项目里同时提供两个版本一个手写梯度下降实现一个调用sklearn的LinearRegression。手写版本能让你在报告里写清楚“模型是怎么学出来的”这在答辩中是很大的加分项。class LinearRegressionGD: def __init__(self, lr0.01, epochs1000): self.lr lr # 学习率 self.epochs epochs # 迭代次数 self.weights None self.bias 0 self.loss_history [] # 记录每次迭代的损失用于画收敛曲线 def fit(self, X, y): n_samples, n_features X.shape self.weights np.zeros(n_features) for epoch in range(self.epochs): # 前向传播计算预测值 y_pred np.dot(X, self.weights) self.bias # 计算误差 error y_pred - y # 梯度计算 dw (1 / n_samples) * np.dot(X.T, error) db (1 / n_samples) * np.sum(error) # 参数更新 self.weights - self.lr * dw self.bias - self.lr * db # 记录损失 loss np.mean(error ** 2) self.loss_history.append(loss) return self def predict(self, X): return np.dot(X, self.weights) self.bias逻辑说明每轮迭代做的就是四件事——前向传播算预测值、计算预测和真实值的误差、由误差反推梯度和偏置的导数、沿负梯度方向更新参数。dw (1/n_samples) * np.dot(X.T, error)这一步是梯度的矩阵写法等价于对每个特征分别求偏导建议你在报告里把对应的数学推导写一遍手推公式和代码形成对照。参数说明lr0.01是学习率控制每一步参数更新的步幅太大会发散太小收敛慢。epochs1000是迭代轮数作业里通常500到2000之间。self.loss_history这个列表很有用训练结束后画一条损失下降曲线如果曲线单调下降并趋于平缓就说明训练过程收敛正常。这个手写版本没有做特征缩放直接跑波士顿原始数据大概率不收敛或收敛极慢。4.2 用 sklearn 一行完成拟合LinearRegression 的5个可调参数sklearn的线性回归实现用的是最小二乘解析解即直接通过矩阵运算求出最优权重不需要迭代。做实验对比时要清楚这一点sklearn版本的结果可以当作“标准答案”手写梯度下降版会逼近这个结果两者差异能体现实现是否正确。from sklearn.linear_model import LinearRegression model LinearRegression( fit_interceptTrue, copy_XTrue, n_jobsNone ) model.fit(X_train, y_train) # 查看模型的系数和截距 print(截距:, model.intercept_) print(各特征系数:, model.coef_)参数说明fit_interceptTrue表示模型需要学习偏置项也就是公式里的w0如果你的数据已经做过中心化处理可以设False但作业里保持默认即可。copy_XTrue表示拟合前复制一份输入数据避免原地修改这是安全选项。n_jobsNone在线性回归里实际上不参与并行计算但写上它可以应对个别平台版本的要求不代表有用。在作业报告里你应该把model.coef_的结果做成一个表列出每个特征对应的权重特别是正的权重和负的权重要分别解读。比如RM的房间数系数是正数表示房间越多房价越高而LSTAT系数是负数表示低收入人口比例越高房价越低这种解读能让老师看到你真的理解了线性回归模型的含义。4.3 用三个指标证明你的模型靠谱RMSE、R²与MAE的组合用法模型训练完不是跑个分数就结束大作业里至少要包含三个回归指标的计算并在结果分析里说明它们各自的视角。from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score y_pred model.predict(X_test) # 计算评估指标 mse mean_squared_error(y_test, y_pred) rmse np.sqrt(mse) mae mean_absolute_error(y_test, y_pred) r2 r2_score(y_test, y_pred) print(fMSE: {mse:.2f}) print(fRMSE: {rmse:.2f}) print(fMAE: {mae:.2f}) print(fR²: {r2:.4f})指标解读RMSE是均方根误差单位直接是房价的单位千美元波士顿数据上合理的结果大约在4到6之间如果这个值超过10说明模型效果很差。MAE是平均绝对误差它比RMSE对异常值更稳健两者一起看能判断预测误差是否被少数极端样本拉高。R²是决定系数表示模型解释了目标变量多少比例的方差对于波士顿数据R²在0.7以上算合格0.8以上算优秀。提示作业最忌讳只放R²不放其他指标R²是相对指标RMSE和MAE是绝对指标。答辩时老师问“你的模型误差到底是多少美元”你如果答不上RMSE就会减分。5. 波士顿房价大作业的5个常见坑与排查从数据泄露到随机种子5.1 标准化翻车对全量数据先 fit 再切分会造成数据泄露现象测试集上的R²异常高但换一个数据集或重新采样后效果骤降老师质疑你“分数是不是有问题”。原因你在切分之前就调用了StandardScaler对全部数据做了拟合并标准化。fit过程会使用测试集的数据计算均值和方法差这些统计量相当于“偷看”了测试集的信息模型评估变得虚高。严格来说这属于数据泄露是机器学习实验里的原则性错误。解决先train_test_split切分再对训练集fit然后只对训练集和测试集分别做transform。标准写法是这样from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)注意测试集只有transform没有fit用的统计量来自训练集。这行代码应该写进你的源码并在报告里专门说明很多大作业就坏在这一个顺序上。5.2 随机种子不固定每次运行结果不一样导致评分不可复现现象同一个脚本连续运行三次每次打印的RMSE和R²都不一样浮动范围还挺大。原因train_test_split在进行随机划分时如果没有指定random_state每次运行都会产生一个新的随机排列训练集和测试集的组成不同评估结果自然不同。此外如果你在项目里用了任何涉及随机初始化的模块同样需要固定种子。解决在所有涉及随机性的位置显式设定随机种子。除了train_test_split(random_state42)之外可以在脚本开头补一段通用固定import numpy as np np.random.seed(42)作业报告里写明“本文所有实验随机种子固定为42”这句话能直接体现你的实验素养。5.3 梯度下降不收敛学习率和特征量纲对迭代的叠加影响现象手写梯度下降版在波士顿数据上训练后loss_history里的数值不降反升或者降到一定程度就停滞在一个很大的值上。原因波士顿房价的13个特征量纲差异巨大比如CRIM是每千人犯罪率数值在0到100之间波动而TAX是房产税率数值在200到700之间。梯度下降沿着误差曲面更新时大数值特征对应的梯度非常大学习率稍大就会震荡发散学习率调小后小数值特征又收敛极慢。这就是为什么手写版本必须配合特征标准化。解决对特征做标准化后再喂给梯度下降。直接在fit方法里加一步标准化处理或者在外面用StandardScaler处理后再传入scaler StandardScaler() X_train_std scaler.fit_transform(X_train) X_test_std scaler.transform(X_test) model_gd LinearRegressionGD(lr0.01, epochs1000) model_gd.fit(X_train_std, y_train)另一个排查点是学习率先把学习率降到0.001观察loss曲线是否变成平滑下降如果下降仍然发散再降到0.0001。判断收敛不能只看最终loss要看整条曲线的形态。5.4 只看R²不看残差图正负残差不平衡时模型等于白做现象R²在0.75以上看起来效果不错但你画出预测值和真实值的散点图后发现预测值在低价区间普遍偏高、在30千美元以上的高价区间普遍偏低。原因线性回归模型对极端值敏感波士顿房价里存在几个被设限的样本实际房价被截断在50千美元这些样本会让模型产生较大的系统性偏差。R²只表示整体方差解释程度无法反映误差在哪个区间聚集必须配合残差分析来发现这种结构性问题。解决画出残差图并叠加一条零线查看是否均匀分布import matplotlib.pyplot as plt residuals y_test - y_pred plt.scatter(y_pred, residuals, alpha0.6) plt.axhline(y0, colorred, linestyle--) plt.xlabel(预测房价) plt.ylabel(残差) plt.title(残差图) plt.show()如果残差点在零线上方和下方数量接近、且随机分布说明模型假设基本成立。如果出现明显的喇叭形分布说明预测误差随房价升高而增大模型对高房价区域的拟合不充分这需要在报告里专门讨论。5.5 特征共线性干扰系数解释TAX和RAD的高相关性问题现象模型训练后某个特征的系数正负方向与常识矛盾例如犯罪率CRIM的系数变成正数或者特征重要性不稳定删掉一个特征后其他特征系数变化很大。原因波士顿数据中TAX和RAD两个特征相关系数超过0.9存在明显多重共线性。当特征之间高度相关时最小二乘解在特征空间里会被扭曲单个特征的系数不再具有清晰的因果含义数值的正负和大小都可能偏离直觉。解决在建模前增加一步相关性检查打印相关系数矩阵并在报告中说明如何处理corr_matrix pd.DataFrame(X_train).corr() high_corr_pairs np.where(np.abs(corr_matrix) 0.8) # 输出相关系数大于0.8的特征对 print(list(zip(high_corr_pairs[0], high_corr_pairs[1])))处理策略有三种直接删除其中一个特征、用PCA降维代替原始特征、或者保留但报告里注明无法单独解释系数。对本科大作业来说选择思路为“保留两个特征但说明它们的共线性由原始数据采集方式决定”通常就能过关关键是让老师看到你知道这个问题存在。6. 让大作业超出预期模型诊断与可视化验证的4个收尾动作第一个收尾动作是画出预测值与真实值的对比散点图把对角线加上。如果点都紧密分布在对角线附近说明模型预测和真实值高度一致如果明显偏离或在某个区间出现弯曲说明还有非线性成分没被捕捉。这张图比任何指标都直观答辩加分效果最好。第二个动作是画出特征的系数条形图。把13个特征的系数从大到小排序后画条形图用不同颜色标出正负。这张图能直观展示哪些变量拉高房价、哪些拖低房价配合报告里的系数表格一起看老师会觉得你的分析有可视化支撑。第三个动作是做一个训练曲线横轴是训练样本数量纵轴是训练集和测试集的R²。如果训练集分数高、测试集分数低说明模型过拟合如果两者都很低说明模型欠拟合。波士顿数据上线性回归通常是轻度欠拟合这是线性模型的正常表现你要在报告里主动说明这一点并给出尝试多项式特征作为改进方向的思路。第四个动作是计算一次交叉验证的完整得分不是单独跑一次train_test_split就结束。用5折交叉验证跑5次输出每次的R²和平均值这个平均分比单次划分得出的分数可信得多。如果5次分数标准差很大说明样本量不足或数据分布不均这也是值得写进报告的分析点。我做完这个项目最大的教训是写代码只用了半天写报告却花了三天其中大部分时间在补画图和文字解释。最后跟朋友交流时也发现大家的模型分数其实都差不多拉开差距的地方全在数据可视化和对误差的分析深度。只要把第5章的5个坑全部避开再把本章的4个收尾动作做完整这份基于线性回归的波士顿房价预测大作业就是一个能拿去答辩的好作品。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑