news 2026/10/27 7:56:34

波士顿房价预测机器学习期末项目:完整源代码与文档说明

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
波士顿房价预测机器学习期末项目:完整源代码与文档说明

简介:这是一份面向高校学生与机器学习初学者的回归分析实战作业包,围绕经典波士顿房价数据集展开,帮助读者完整走通从数据预处理、模型训练到结果评估与可视化分析的全流程。项目样本506个、特征13个,目标变量为房屋中位数价值,实现了批处理梯度下降、随机梯度下降、岭回归与LASSO回归四种算法,并配有模型对比与系数分析结果。压缩包共12个文件,约944KB,包含3个csv数据与结果文件、3个py源码脚本、3个png可视化图表、2个txt说明及1个md文档,覆盖数据、代码、图表与说明各环节。目前已有120人学习。读者可获得可直接运行的完整源码、清晰的目录结构与实验记录,便于对照复现算法差异、理解正则化对回归的影响,并作为课程作业或期末项目的参考模板。

1. 波士顿房价预测作业:一份能跑通全流程的机器学习期末项目

如果你正在为机器学习期末大作业发愁,或者刚学完线性回归、决策树却不知道怎么串成一个完整项目,这份波士顿房价预测作业加源代码加文档说明的资源,大概率能帮你省下不少时间。波士顿房价数据集是机器学习入门最经典的回归任务之一,506 条样本、13 个特征、1 个连续目标值,体量小但五脏俱全,从数据加载、特征工程、模型训练到评估可视化,一个完整项目的骨架它都有。这份资源的核心价值在于:它不是只给你一个模型文件,而是把源代码、文档说明和作业报告打包在一起,你能看到别人是怎么组织代码结构、怎么写实验分析、怎么解释结果的。适合谁?适合正在做机器学习期末大作业的本科生、刚转行想补一个完整项目经验的初学者,以及需要一份可复现基线代码的从业者。下面我从代码结构、运行步骤、参数调优和踩坑记录几个角度,把这份资源拆开讲清楚。

2. 拆解源代码结构:从数据加载到模型持久化

2.1 项目目录与模块划分

拿到一份机器学习作业源代码,第一件事不是急着跑,而是先看目录结构。常见的组织方式是按功能分层:数据层、模型层、评估层、入口脚本。这份波士顿房价预测项目的典型结构大致如下:

boston_housing/ ├── data/ │ └── housing.csv # 原始数据集 ├── src/ │ ├── data_loader.py # 数据加载与预处理 │ ├── feature_engineer.py # 特征工程 │ ├── train.py # 模型训练入口 │ ├── evaluate.py # 评估与可视化 │ └── utils.py # 通用工具函数 ├── models/ │ └── best_model.pkl # 训练好的模型 ├── docs/ │ └── report.md # 文档说明与实验分析 ├── requirements.txt └── README.md

这种划分的好处是职责清晰:data_loader.py只管把 CSV 读进来、处理缺失值、划分训练测试集;feature_engineer.py负责标准化、多项式特征、特征选择;train.py负责调参和训练;evaluate.py负责 MSE、RMSE、R² 等指标计算和残差图绘制。你拿到手之后,如果只想快速验证,直接跑train.py就行;如果想改模型,只需要动train.py里的模型定义部分,不用碰数据加载逻辑。

提示:不同人打包的目录名可能略有差异,但核心模块的职责划分基本一致。先看 README 里的运行说明,再对照目录理解每个文件的作用。

2.2 数据加载与预处理代码实操

波士顿房价数据集的原始版本可以从 scikit-learn 内置数据集中直接加载,但很多作业会要求用 CSV 文件读取,以体现完整的数据处理流程。下面这段代码是data_loader.py里最常见的写法:

import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler def load_boston_data(csv_path): """加载波士顿房价数据集并进行基础预处理""" # 读取CSV,注意原始数据可能没有表头 df = pd.read_csv(csv_path, header=None) # 波士顿数据集最后一列是目标值MEDV X = df.iloc[:, :-1].values y = df.iloc[:, -1].values # 检查缺失值 if np.isnan(X).any() or np.isnan(y).any(): # 常见做法是用中位数填充特征缺失值 from sklearn.impute import SimpleImputer imputer = SimpleImputer(strategy='median') X = imputer.fit_transform(X) # 划分训练集和测试集,固定random_state保证可复现 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) # 标准化:注意scaler只在训练集上fit scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) return X_train, X_test, y_train, y_test, scaler

这段代码有几个关键点值得注意。第一,header=None是因为原始波士顿数据文件通常不带表头,如果你拿到的 CSV 有表头,需要改成header=0。第二,缺失值处理用中位数填充是回归任务的常见做法,因为均值容易受异常值影响。第三,train_test_split的random_state=42是为了保证每次运行划分结果一致,这在作业提交和实验对比中非常重要。第四,标准化时scaler.fit_transform只用在训练集上,测试集用transform,这是防止数据泄露的基本操作,但很多新手会在这里翻车。

2.3 模型训练与评估的代码骨架

train.py是整份源代码的核心,通常包含模型定义、交叉验证、超参数搜索和最终评估。下面是一个覆盖线性回归、岭回归和随机森林的对比框架:

from sklearn.linear_model import LinearRegression, Ridge from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_val_score from sklearn.metrics import mean_squared_error, r2_score import numpy as np def train_and_evaluate(X_train, X_test, y_train, y_test): """训练多个模型并对比评估""" models = { 'LinearRegression': LinearRegression(), 'Ridge(alpha=1.0)': Ridge(alpha=1.0), 'RandomForest(n=100)': RandomForestRegressor( n_estimators=100, random_state=42 ) } results = {} for name, model in models.items(): # 5折交叉验证评估训练集上的稳定性 cv_scores = cross_val_score( model, X_train, y_train, cv=5, scoring='neg_mean_squared_error' ) cv_rmse = np.sqrt(-cv_scores.mean()) # 全量训练集拟合 model.fit(X_train, y_train) y_pred = model.predict(X_test) mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) r2 = r2_score(y_test, y_pred) results[name] = { 'CV_RMSE': round(cv_rmse, 4), 'Test_RMSE': round(rmse, 4), 'Test_R2': round(r2, 4) } return results

这段代码的逻辑说明:cross_val_score用负均方误差作为评分标准,因为 sklearn 的交叉验证默认是分数越高越好,而 MSE 是越低越好,所以取负值。cv=5表示 5 折交叉验证,这是小数据集上的常用选择。最终输出三个指标:交叉验证 RMSE 反映模型稳定性,测试集 RMSE 反映泛化误差,R² 反映模型解释了多少方差。参数方面,Ridge(alpha=1.0)中的 alpha 是正则化强度,值越大惩罚越强;RandomForestRegressor的n_estimators=100是树的数量,通常 100 到 500 之间比较合理,再往上收益递减。

注意:波士顿数据集的特征量纲差异较大,比如 CRIM 是犯罪率(0 到 89 之间),而 ZN 是住宅用地比例(0 到 100),如果不做标准化,线性回归的系数会非常不稳定。这是这份作业里最容易忽略但影响很大的一个点。

3. 跑通全流程:环境配置、运行步骤与参数调优

3.1 环境依赖与安装

拿到源代码后,第一步是确认环境依赖。这份资源的requirements.txt通常包含以下核心包:

包名版本范围用途
numpy>=1.21数值计算
pandas>=1.3数据读取与处理
scikit-learn>=1.0模型训练与评估
matplotlib>=3.4可视化绘图
seaborn>=0.11统计图表美化

安装命令很简单:

# 创建虚拟环境(推荐,避免污染全局包) python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate # 安装依赖 pip install -r requirements.txt

如果你用的是 Anaconda,也可以直接conda create -n boston python=3.9然后pip install。常见问题是 scikit-learn 版本不兼容,比如旧代码用了sklearn.datasets.load_boston(),但在 1.2 版本之后这个函数因为伦理原因被移除了。如果你遇到ImportError: cannot import name 'load_boston',解决办法是从 CSV 文件读取,或者降级 scikit-learn 到 1.1 以下。我一般会建议直接用 CSV 读取,避免版本依赖问题。

3.2 运行训练脚本与结果解读

环境配好后,运行入口脚本:

# 在项目根目录下执行 python src/train.py --data_path data/housing.csv --output_dir models/

如果你的项目没有用 argparse 传参,直接python src/train.py也行。运行成功后,控制台会输出类似下面的结果:

Model: LinearRegression CV_RMSE: 4.83 Test_RMSE: 4.72 Test_R2: 0.67 Model: Ridge(alpha=1.0) CV_RMSE: 4.79 Test_RMSE: 4.68 Test_R2: 0.68 Model: RandomForest(n=100) CV_RMSE: 3.21 Test_RMSE: 3.05 Test_R2: 0.86

怎么解读这些数字?RMSE 是均方根误差,单位是目标值 MEDV 的千美元。线性回归的 Test_RMSE 约 4.7,意味着预测房价平均偏差约 4700 美元;随机森林降到 3.05,偏差约 3050 美元。R² 从 0.67 提升到 0.86,说明随机森林解释了 86% 的房价方差。但要注意,随机森林在训练集上的表现通常远好于测试集,如果 CV_RMSE 和 Test_RMSE 差距过大,说明可能过拟合了。这份作业的文档说明里一般会包含这些分析,你可以对照着理解。

3.3 超参数调优的实操方法

如果你想让作业分数更高,或者想真正理解参数对模型的影响,可以加一段网格搜索:

from sklearn.model_selection import GridSearchCV def tune_random_forest(X_train, y_train): """对随机森林进行网格搜索调参""" param_grid = { 'n_estimators': [50, 100, 200], 'max_depth': [None, 10, 20, 30], 'min_samples_split': [2, 5, 10], 'min_samples_leaf': [1, 2, 4] } rf = RandomForestRegressor(random_state=42) grid_search = GridSearchCV( estimator=rf, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1, # 并行搜索 verbose=1 ) grid_search.fit(X_train, y_train) print(f"最佳参数: {grid_search.best_params_}") print(f"最佳CV_RMSE: {np.sqrt(-grid_search.best_score_):.4f}") return grid_search.best_estimator_

参数说明:n_estimators是树的数量,越多越稳定但计算越慢;max_depth控制树的最大深度,None表示不限制,容易过拟合;min_samples_split是节点分裂所需的最小样本数,越大越保守;min_samples_leaf是叶节点最小样本数,同样起正则化作用。n_jobs=-1表示用所有 CPU 核心并行搜索,能显著缩短时间。网格搜索的缺点是计算量大,4 个参数各 3 个取值就是 81 种组合,每种 5 折交叉验证,总共 405 次训练。如果时间紧,可以先用随机搜索RandomizedSearchCV快速缩小范围。

提示:调参时不要只盯着测试集 RMSE,交叉验证的均值和方差同样重要。如果某个参数组合的 CV 均值好但方差大,说明模型不稳定,换到新数据上可能翻车。

4. 避坑与排查:波士顿房价预测作业的五个血泪教训

4.1 数据泄露:标准化在划分之前做

现象:测试集 R² 异常高,接近 0.95 甚至更高,但换一组数据后骤降。原因:在train_test_split之前就对全量数据做了标准化,导致测试集的均值和方差信息泄露到了训练过程中。解决:严格先划分再标准化,scaler.fit只在训练集上调用,测试集用transform。这是最隐蔽也最致命的坑,很多作业代码里都有这个问题。

4.2 特征量纲不统一导致线性回归系数爆炸

现象:线性回归的系数出现几千甚至几万的量级,模型预测值偏离实际范围。原因:波士顿数据集中不同特征的量纲差异大,比如 TAX 是税率(几百),而 NOX 是一氧化氮浓度(0 到 1 之间),不标准化的话系数无法比较。解决:对所有特征做 StandardScaler 或 MinMaxScaler,标准化后系数反映的是特征对目标值的相对贡献。如果作业要求解释系数含义,标准化后的系数才有可比性。

4.3 随机森林的 n_jobs 参数在 Windows 上卡死

现象:设置n_jobs=-1后程序卡住不动,CPU 占用率 100% 但没有任何输出。原因:Windows 下 sklearn 的并行计算依赖 joblib 的进程池,在某些 Python 版本和环境下会出现死锁。解决:把n_jobs改成 1 或者 2,或者把训练代码放在if __name__ == '__main__':保护块里。如果还是不行,升级 joblib 到最新版本。

4.4 目标值分布偏态导致回归效果差

现象:模型在低价房上预测还行,但高价房误差特别大。原因:MEDV 的分布是右偏的,大部分房价在 20 左右,少数在 50 附近,线性回归对偏态目标值敏感。解决:对目标值做对数变换np.log1p(y),训练完再np.expm1还原。这样能压缩高价房的影响,让模型更关注整体拟合。很多高分作业的文档里都会提到这个技巧。

4.5 交叉验证的 scoring 参数用错

现象:cross_val_score返回的分数是负数,或者越大反而模型越差。原因:sklearn 的交叉验证默认分数越高越好,而 MSE 是越低越好,所以要用neg_mean_squared_error。如果用了mean_squared_error,得到的负值会让你困惑。解决:统一用neg_mean_squared_error,最后取负再开方得到 RMSE。另外,scoring='r2'也是常用选择,R² 本身就是越高越好,不需要取负。

5. 进阶技巧:用残差分析和学习曲线验证模型是否真的可用

5.1 残差图:比 R² 更直观的诊断工具

R² 和 RMSE 是汇总指标,但汇总指标会掩盖很多问题。我一般会画残差图来检查模型是否存在系统性偏差:

import matplotlib.pyplot as plt def plot_residuals(y_test, y_pred, model_name='Model'): """绘制残差图诊断模型""" residuals = y_test - y_pred fig, axes = plt.subplots(1, 2, figsize=(12, 5)) # 残差 vs 预测值 axes[0].scatter(y_pred, residuals, alpha=0.6, edgecolors='k') axes[0].axhline(y=0, color='r', linestyle='--') axes[0].set_xlabel('Predicted Values') axes[0].set_ylabel('Residuals') axes[0].set_title(f'{model_name}: Residuals vs Predicted') # 残差分布直方图 axes[1].hist(residuals, bins=30, edgecolor='k', alpha=0.7) axes[1].axvline(x=0, color='r', linestyle='--') axes[1].set_xlabel('Residuals') axes[1].set_ylabel('Frequency') axes[1].set_title(f'{model_name}: Residual Distribution') plt.tight_layout() plt.savefig(f'{model_name}_residuals.png', dpi=150) plt.show()

怎么看这张图?如果残差均匀分布在 0 线两侧,没有明显的漏斗形或曲线趋势,说明模型没有系统性偏差。如果残差随预测值增大而扩散,说明存在异方差性,可能需要对数变换目标值。如果残差直方图明显偏离正态分布,说明模型在某些区间预测能力不足。这份作业的文档说明里如果有残差分析,那说明作者确实认真做了实验,而不是随便跑了个模型就交差。

5.2 学习曲线:判断过拟合还是欠拟合

学习曲线能帮你判断模型是过拟合还是欠拟合,以及增加数据是否有帮助:

from sklearn.model_selection import learning_curve def plot_learning_curve(model, X, y, cv=5): """绘制学习曲线""" train_sizes, train_scores, test_scores = learning_curve( model, X, y, cv=cv, n_jobs=1, train_sizes=np.linspace(0.1, 1.0, 10), scoring='neg_mean_squared_error' ) train_rmse = np.sqrt(-train_scores.mean(axis=1)) test_rmse = np.sqrt(-test_scores.mean(axis=1)) plt.figure(figsize=(8, 5)) plt.plot(train_sizes, train_rmse, 'o-', label='Training RMSE') plt.plot(train_sizes, test_rmse, 's-', label='Validation RMSE') plt.xlabel('Training Set Size') plt.ylabel('RMSE') plt.legend() plt.title('Learning Curve') plt.grid(True, alpha=0.3) plt.savefig('learning_curve.png', dpi=150) plt.show()

如果训练 RMSE 和验证 RMSE 都高且接近,说明欠拟合,需要增加模型复杂度或加更多特征。如果训练 RMSE 低但验证 RMSE 高且差距大,说明过拟合,需要加正则化或减少特征。如果两条曲线随着数据量增加逐渐靠拢,说明增加数据可能有帮助。波士顿数据集只有 506 条样本,学习曲线通常会在 300 条左右趋于平缓,这意味着再加数据收益不大,重点应该放在特征工程和模型选择上。

5.3 特征重要性分析:随机森林的额外收获

随机森林除了预测,还能输出特征重要性,这对写作业报告很有帮助:

def plot_feature_importance(model, feature_names): """绘制随机森林特征重要性""" importances = model.feature_importances_ indices = np.argsort(importances)[::-1] plt.figure(figsize=(10, 6)) plt.bar(range(len(importances)), importances[indices], edgecolor='k') plt.xticks(range(len(importances)), [feature_names[i] for i in indices], rotation=45, ha='right') plt.xlabel('Features') plt.ylabel('Importance') plt.title('Random Forest Feature Importance') plt.tight_layout() plt.savefig('feature_importance.png', dpi=150) plt.show()

波士顿数据集里,通常 LSTAT(低收入人群比例)、RM(平均房间数)、PTRATIO(师生比)是最重要的特征,而 CHAS(是否临河)和 ZN(住宅用地比例)重要性较低。这个结果和领域常识一致:低收入比例越高、房间数越少、师生比越高的区域,房价越低。如果你在作业报告里能结合领域知识解释特征重要性,分数通常会更高。

5.4 模型持久化与复现验证

训练完模型后,用 joblib 保存,方便后续加载和验证:

import joblib # 保存模型和scaler joblib.dump(model, 'models/best_model.pkl') joblib.dump(scaler, 'models/scaler.pkl') # 加载验证 loaded_model = joblib.load('models/best_model.pkl') loaded_scaler = joblib.load('models/scaler.pkl') # 用加载的模型预测新样本 new_sample = X_test[:5] new_sample_scaled = loaded_scaler.transform(new_sample) predictions = loaded_model.predict(new_sample_scaled) print(f"预测值: {predictions}") print(f"真实值: {y_test[:5]}")

这一步看起来简单,但很多人会忘记保存 scaler,导致加载模型后无法正确处理新数据。我一般会把模型和 scaler 一起保存,并在 README 里写清楚加载顺序。从那以后我每次交作业前都会强制走一遍「保存-加载-预测」的流程,确认模型能完整复现,才敢提交。希望这份拆解能帮你顺利跑通波士顿房价预测作业,少走一些弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 7:56:04

从零构建游戏AI:基于强化学习的《星际争霸2》智能体开发

1. 项目概述:AI自动打游戏的完整实现路径"让AI自己打游戏"这个想法在2013年DeepMind用Atari游戏演示深度强化学习时就开始流行。如今随着大语言模型和智能体(Agent)技术的发展,普通开发者也能搭建自己的游戏AI系统。不同于简单的脚本外挂&…

作者头像 李华
网站建设 2026/10/27 7:55:45

Evd.rar_EVD取证数据解析:从文件识别到时间线提取的完整流程

简介:这份资源围绕EVD(增强型视频光盘)技术展开,面向对高清视频格式、编解码原理及播放器实现感兴趣的学习者与开发者。压缩包共26个文件,约40KB,以C源码(cpp、h)为主体,…

作者头像 李华
网站建设 2026/10/27 7:54:40

AI编程三年进化史:从自动补全玩具到超越中高级程序员的Agent

这三年只要你的工作跟代码沾边,应该都逃不开AI编程这个话题。从最初被当成“自动补全玩具”,到如今不少团队直接让AI Agent独立接需求、开PR、修bug,甚至连“超越中高级程序员”这种话都开始有人在认真讨论。我自己是从GitHub Copilot刚出预览…

作者头像 李华
网站建设 2026/10/27 7:54:00

开源组件组装本地语音工作室:声音克隆与工作流引擎实战

前阵子我在搭一套自己的语音生产链路时,遇到一个很现实的麻烦:声音克隆模型、TTS合成器、音频后处理工具,GitHub上全是好东西,但每一样都是一座孤岛。导出一次成品,要在三四个脚本之间来回倒腾,改一次参数又…

作者头像 李华
网站建设 2026/10/27 7:53:52

Redis哨兵系统:高可用原理与生产环境部署指南

1. Redis哨兵系统概述Redis Sentinel(哨兵)是Redis官方提供的高可用性解决方案,它通过监控、通知和自动故障转移三大核心功能,确保Redis服务在出现故障时能够持续可用。我在实际生产环境中部署过数十套Sentinel系统,发…

作者头像 李华
网站建设 2026/10/27 7:53:06

VS Code开发SpringBoot项目全流程指南

1. 为什么选择VS Code开发SpringBoot项目作为2026年Java开发者最主流的轻量级IDE,VS Code凭借其强大的扩展生态和流畅的性能表现,已经成为SpringBoot项目开发的首选工具。相比传统重型IDE,VS Code启动速度快3-5倍,内存占用减少60%…

作者头像 李华