当前位置: 首页 > news >正文

分类与回归算法(二) - 线性回归

文章目录

  • 一、什么是线性回归
  • 二、线性回归的核心原理
    • 1. 损失函数
    • 2. 优化算法
      • 2.1 正规方程
      • 2.2 梯度下降
  • 三、线性回归的应用场景
  • 四、线性回归实现步骤
    • 1. 数据收集与加载
      • 1.1 数据集介绍
        • 1.1.1 数据集基本信息
        • 1.1.2 数据集背景与用途
        • 1.1.3 特征说明(13 个自变量)
      • 1.2 数据加载
        • 1.2.1 数据加载相关方法
          • (1) fetch_openml(name, version, as_frame)
          • (2).values
          • (3)pd.DataFrame(data, columns)
          • (4)pd.Series(data, name)
        • 1.2.2 数据加载代码
    • 2. 数据探索与可视化(EDA)
      • 2.1 EDA相关方法介绍
      • 2.2 EDA实现步骤及代码
        • 2.2.1 查看前5行数据
        • 2.2.2 查看数据摘要信息
        • 2.2.3 描述性统计分析
        • 2.2.4 目标变量分布分析
        • 2.2.5 目标变量与各个特征变量的相关性分析
        • 2.2.6 验证变量间的真实关系
        • 2.2.7 特征间的相关性分析
      • 2.3 EDA 完整代码
    • 3. 数据预处理
      • 3.1 处理缺失值
      • 3.2 特征选择
        • 3.2.1 特征选择相关方法
        • 3.2.2 特征选择:基于相关性与多重共线性分析的优化筛选
      • 3.3 数据标准化(归一化)
        • 3.3.1 数据标准化相关方法
        • 3.3.2 数据标准化
      • 3.4 划分训练集与测试集
        • 3.4.1 相关方法说明
        • 3.4.2 划分训练集与测试集代码实现
      • 3.5 预处理总结
    • 4. 构建线性回归模型
      • 4.1 相关方法说明
        • 4.1.1 `LinearRegression`构造方法简介
        • 4.1.2 `LinearRegression`构造方法参数说明
        • 4.1.3 `LinearRegression`的核心属性(模型训练后可用)
        • 4.1.4 `LinearRegression`对象的核心方法
      • 4.2 构建线性回归模型代码实现
    • 5. 模型预测
      • 5.1 模型预测相关方法
      • 5.2 模型预测代码实现
      • 6. 模型评估
        • 6.1 常用评估指标说明
        • 6.2 评估代码实现与结果分析
    • 7. 结果可视化
      • 7.1 真实房价 vs 预测房价(散点图)
      • 7.2 预测误差分布(直方图)
      • 7.3 特征重要性(基于回归系数绝对值)
      • 7.4 结果解读
    • 8. 模型解释
      • 8.1 回归系数的业务含义
      • 8.2 特征重要性与决策支持
      • 8.3 模型的实际应用价值
      • 8.4 局限性与改进方向
  • 五、完整代码
    • 1. 完整代码
    • 2. 优化后完整代码


一、什么是线性回归

线性回归的本质是构建特征与目标值之间的线性关系模型,通过学习数据中的规律,实现对连续数值的预测。

举个生活中的例子:假设我们想预测“房屋售价”(目标值),影响售价的因素可能有“房屋面积”“卧室数量”“楼层”(特征)。线性回归会假设这些特征与售价呈线性关系,最终得到一个类似这样的公式:
房屋售价 = 0.8×面积 + 0.3×卧室数量 + 0.1×楼层 + 50
其中,“0.8、0.3、0.1”是特征的“权重”(表示该特征对目标值的影响程度),“50”是“截距”(基础价格)。通过这个公式,输入新房屋的特征,就能预测出它的售价。

从数学角度定义:若有(n)个特征((x1,x2,...,xnx_1, x_2, ..., x_nx1,x2,...,xn)),目标值为(y),线性回归模型可表示为:
y=w1x1+w2x2+...+wnxn+by = w_1x_1 + w_2x_2 + ... + w_nx_n + by=w1x1+w2x2+...+wnxn+b 其中:

  • (w1,w2,...,wnw_1, w_2, ..., w_nw1,w2,...,wn):特征权重(也称“回归系数”),决定每个特征对(y)的影响方向和大小;
  • (bbb):截距(也称“偏置项”),表示所有特征为0时,目标值的基础水平;
  • (yyy):模型预测的目标值(连续数值)。

二、线性回归的核心原理

线性回归的关键是求解最优的权重(www)和截距(bbb),使得模型的预测值与真实值的偏差最小。这一过程需要通过“损失函数”定义偏差,再通过“优化算法”最小化损失函数。

1. 损失函数

损失函数用于衡量模型的“偏差大小”,用“残差”表示单个样本的预测偏差:残差 = 真实值 - 预测值,即(yi−y^iy_i - \hat{y}_iyiy^i),其中(y^i\hat{y}_iy^i)是第(iii)个样本的预测值。

线性回归常用均方误差(MSE) 作为损失函数,它是所有样本残差的平方和的平均值,公式为:
Loss=MSE=1m∑i=1m(yi−y^i)2Loss = MSE = \frac{1}{m} \sum_{i=1}^m (y_i - \hat{y}_i)^2Loss=MSE=m1i=1m(yiy^i)2 其中(mmm)是样本数量。

为什么选择MSE?

  • 平方项能放大“大偏差”的影响,强制模型优先降低极端错误(如预测房价偏差100万,平方后会远大于偏差10万的样本);
  • MSE是光滑可导的函数,便于后续用“梯度下降”等优化算法求解最小值。

2. 优化算法

优化算法用于找到最小损失对应的(www)和(bbb),求解(www)和(bbb)有两种经典方法:“正规方程”和“梯度下降”,适用于不同的样本规模。

2.1 正规方程

正规方程可用于直接计算最优解,对于简单的线性回归(如单特征),可通过数学推导直接求出(www)和(bbb)的解。

单特征线性回归(仅1个特征xxx)为例:

  • 截距 bbb 的计算公式:(b=yˉ−wxˉb = \bar{y} - w\bar{x}b=yˉwxˉ)(其中 xˉ\bar{x}xˉ 是特征的平均值,yˉ\bar{y}yˉ 是目标值的平均值);
  • 权重 www 的计算公式:(w=∑i=1m(xi−xˉ)(yi−yˉ)∑i=1m(xi−xˉ)2w = \frac{\sum_{i=1}^m (x_i - \bar{x})(y_i - \bar{y})}{\sum_{i=1}^m (x_i - \bar{x})^2}w=i=1m(xixˉ)2i=1m(xixˉ)(yiyˉ))。

适用场景:样本量小(如 m<10000m < 10000m<10000)、特征少的场景,计算速度快;但当样本量或特征数过大时,矩阵求逆运算会非常耗时(时间复杂度 O(n3)O(n^3)O(n3)nnn 为特征数)。

2.2 梯度下降

梯度下降用于迭代逼近最优解,当样本量或特征数较大时,梯度下降是更高效的选择。它的核心思想是:沿着损失函数的梯度方向,逐步调整 wwwbbb,直到损失函数达到最小值。

核心步骤

  1. 初始化 www(如随机赋值)和 bbb(如赋值0);
  2. 计算当前 wwwbbb 对应的损失函数值;
  3. 计算损失函数对 wwwbbb 的“梯度”(即偏导数,反映参数变化对损失的影响方向);
  4. 沿梯度负方向更新 wwwbbb (学习率 α\alphaα 控制每次更新的步长):
    (w=w−α×∂Loss∂ww = w - \alpha \times \frac{\partial Loss}{\partial w}w=wα×wLoss)
    (b=b−α×∂Loss∂bb = b - \alpha \times \frac{\partial Loss}{\partial b}b=bα×bLoss);
  5. 重复步骤2-4,直到损失函数收敛(变化小于阈值)或达到最大迭代次数。

关键参数

  • 学习率 α\alphaα:步长过大会导致损失函数震荡不收敛,步长过小会导致训练速度极慢,通常需要通过交叉验证调优(如取值0.001、0.01、0.1);
  • 迭代次数:需设置合理的最大迭代次数,避免训练时间过长。

适用场景:样本量大(如 m>10000m > 10000m>10000)、特征多的场景,时间复杂度低 O(mn)O(mn)O(mn),是工业界常用的优化方法。


三、线性回归的应用场景

行业领域应用场景输入特征(自变量)输出目标(因变量)是否适用线性回归备注
房地产房价预测面积、房间数、地理位置、房龄、楼层房屋价格(万元)✅ 适用经典应用,解释性强
市场营销销售额预测广告投入(电视/网络/报纸)、促销力度销售额(万元)✅ 适用可分析各渠道贡献度
金融信用额度评估收入、工作年限、信用记录、负债比授信额度(元)✅ 适用(初步模型)常与其他模型结合使用
医疗健康血糖水平预测年龄、体重、饮食热量、运动时间血糖值(mmol/L)✅ 适用(简化模型)用于趋势分析,非精确诊断
教育学生成绩预测学习时长、出勤率、作业完成度考试成绩(分)✅ 适用可帮助教师识别影响因素
气象气温趋势预测历史温度、季节、湿度、风速未来气温(℃)✅ 适用(短期)长期预测需更复杂模型
农业农作物产量预测降雨量、施肥量、光照时间、土壤肥力亩产量(公斤)✅ 适用辅助农业决策
交通出行时间预测距离、路况、时间段、天气行驶时间(分钟)✅ 适用导航系统常用基础模型
能源电力消耗预测气温、人口、工业活动指数日用电量(千瓦时)✅ 适用用于电网调度规划
保险理赔金额预测年龄、保额、健康状况、事故类型理赔金额(元)✅ 适用控制赔付风险
电子商务用户消费预测浏览时长、购买频率、优惠券使用年消费金额(元)✅ 适用用于个性化推荐
环境空气质量指数(AQI)预测PM2.5、PM10、NO₂、湿度、风速AQI 数值✅ 适用(短期)需结合时间序列方法
制造业设备故障时间预测使用时长、维护次数、温度、振动频率剩余使用寿命(小时)⚠️ 有限适用若关系非线性需改用其他模型
股票市场股价走势预测历史价格、交易量、市盈率明日收盘价(元)❌ 不推荐股市高度非线性、噪声大
社交媒体用户活跃度预测发帖数、点赞数、关注数活跃分数(0–100)✅ 适用(简化)可作为用户分层依据

四、线性回归实现步骤

如图所示,线性回归模型的构建与应用遵循一个系统化、结构化的流程。整个过程可分为八个关键阶段,形成从数据输入到模型输出的完整闭环,涵盖数据处理、建模、评估与部署等核心环节。
在这里插入图片描述

1. 数据收集与加载

此处以“波士顿房价预测”数据集(经典回归任务,目标是根据房屋特征预测房价)为例,用Python的scikit-learn库实现线性回归,同时用matplotlib可视化结果。

1.1 数据集介绍

1.1.1 数据集基本信息
属性内容
名称Boston House Prices Dataset
来源UCI 机器学习仓库(通过 OpenML 平台提供)
获取方式sklearn.datasets.fetch_openml(name="boston", version=1)
任务类型回归(Regression)
样本数量506 条记录
特征数量13 个数值型/类别型特征
目标变量MEDV:房屋中位数价格(单位:千美元)
发布时间20 世纪 70 年代初(基于 1978 年数据)
1.1.2 数据集背景与用途

该数据集最初由美国统计学家 Harrison 和 Rubinfeld 在 1978 年研究波士顿地区住房价格影响因素时收集。它广泛用于机器学习入门教学(线性回归、决策树等)、特征工程练习、模型评估基准测试。

1.1.3 特征说明(13 个自变量)

所有特征均为连续值或离散比例值,具体如下:

字段名称含义与房价关系
CRIMCrime Rate城镇人均犯罪率负相关
ZNResidential Zoning占地超过 25,000 平方英尺的住宅用地比例正相关
INDUSNon-Retail Business非零售商业用地占比(英亩/城镇)负相关
CHASCharles River Dummy是否临查尔斯河(1=是,0=否)正相关
NOXNitric Oxides Concentration一氧化氮浓度(ppm)负相关
RMAverage Rooms per Dwelling每栋住宅平均房间数强正相关
AGEProportion of Old Units1940 年前建造的自住单位比例负相关
DISWeighted Distances to Employment Centers到五个就业中心的加权距离正相关
RADAccessibility to Highways高速公路可达指数(越小越难达)复杂关系
TAXProperty Tax Rate每万美元的全额房产税率负相关
PTRATIOPupil-Teacher Ratio城镇师生比负相关
B1000(Bk−0.63)21000(Bk - 0.63)^21000(Bk0.63)2黑人比例相关指标(有争议)——
LSTATLower Status Population %低收入人群百分比强负相关

🔍 目标变量

  • MEDV:自有住房的中位数价值(Median value of owner-occupied homes in $1000s),即我们要预测的目标。

1.2 数据加载

1.2.1 数据加载相关方法
(1) fetch_openml(name, version, as_frame)

这是 scikit-learn 提供的用于从 OpenML(开放机器学习平台)下载标准数据集的核心函数,替代已被弃用的 load_boston()

参数类型默认值说明
namestr必填指定要加载的数据集名称,例如 "boston""iris"
versionint 或 strNone指定数据集版本号,如 1;若存在多个版本需明确指定
as_frameboolFalse是否将特征和目标返回为 pandas.DataFrameSeries
True:便于数据分析
False:返回 NumPy 数组(传统格式)
parserstr'auto'解析器类型,推荐设置为 'pandas' 以确保兼容性(尤其在新版本 sklearn 中)
return_X_yboolFalse若为 True,则只返回 (data, target) 元组,不返回完整 Bunch 对象

🔍 返回值:一个 Bunch 对象,包含:

  • .data:特征矩阵(DataFrame 或 array)
  • .target:目标向量(Series 或 array)
  • .feature_names:特征名称列表
  • .DESCR:数据集描述(部分数据集提供)
(2).values

这是 pandas.DataFramepandas.Series 提供的属性,用于将数据转换为 NumPy 数组。

属性来源返回类型说明
.valuespandas.DataFrame, pandas.Seriesnumpy.ndarray将 DataFrame 转为二维数组,Series 转为一维数组
(3)pd.DataFrame(data, columns)

用于创建 pandas 的二维数据结构,适合处理表格型数据。

参数类型是否必需说明
dataarray-like, dict, DataFrame 等输入数据,此处为 boston.data.values(二维数组)
columnslist of str否(建议使用)指定列名,提升可读性;使用 boston.feature_names 可保留原始命名
(4)pd.Series(data, name)

用于创建一维标签数组,常用于表示目标变量(标签或连续值)。

参数类型是否必需说明
dataarray-like目标值数组,如 boston.target.values
namestr否(强烈建议)给 Series 命名,便于识别含义(如 "MEDV" 表示房价中位数)
1.2.2 数据加载代码
# 1. 导入库
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_openml
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split# 设置matplotlib的中文字体为SimHei(黑体),以确保中文标签可以正常显示。
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号'-'显示为方块的问题,通过设置'axes.unicode_minus'为False来实现。
plt.rcParams['axes.unicode_minus'] = False# 设置全局选项
pd.set_option('display.max_columns', None)  # 显示所有列
pd.set_option('display.width', None)  # 自动检测宽度
pd.set_option('display.max_colwidth', 50)  # 列内容最多显示50字符
pd.set_option('display.expand_frame_repr', False)  # 禁用多行表示(可选)# 2. 加载并查看数据(波士顿房价数据集)# 使用 sklearn 的 fetch_openml 函数从 OpenML 平台下载 "boston" 数据集
# - name="boston": 指定数据集名称
# - version=1: 使用第一个版本
# - as_frame=True: 返回结果包含 pandas DataFrame 和 Series(便于后续分析)
boston = fetch_openml(name="boston", version=1, as_frame=True, parser="pandas")# 将特征数据(boston.data)转换为 NumPy 数组
# 原因:虽然 as_frame=True 返回的是 DataFrame,但某些旧版代码或模型要求输入为数组格式
# .values 属性将 DataFrame 转换为二维 numpy 数组
boston.data = boston.data.values# 将目标变量(boston.target)也转换为 NumPy 数组
# 如果 target 是 DataFrame 或 Series,.values 可确保其变为一维数组
boston.target = boston.target.values# 将特征数据重新构造成 pandas DataFrame,方便查看和操作
# - boston.data: 已转为 numpy 数组的特征矩阵
# - columns=boston.feature_names: 使用原始数据集中定义的特征名称作为列名
X = pd.DataFrame(boston.data, columns=boston.feature_names)# 构造目标变量 y,使用 pd.Series 存储
# - boston.target: 目标值数组(房屋中位价格,单位:千美元)
# - name="MEDV": 给 Series 命名为 MEDV(Median Value),与原始数据集一致
y = pd.Series(boston.target, name="MEDV")

2. 数据探索与可视化(EDA)

2.1 EDA相关方法介绍

数据探索与可视化(Exploratory Data Analysis, EDA)是机器学习流程中的关键步骤,用于理解数据分布、特征关系和异常值等。以下是常用方法:

方法功能适用场景
pd.DataFrame.head(n)查看前n行数据快速了解数据结构和数值格式
pd.DataFrame.info()显示数据类型、非空值数量检查缺失值和数据类型合理性
pd.DataFrame.describe()计算基本统计量(均值、标准差等)分析数值特征的分布范围
pd.DataFrame.corr()计算特征间的相关系数发现特征与目标变量的线性关系
plt.scatter(x, y)绘制散点图分析两个变量的相关性(如特征与目标)
sns.histplot(data, kde=True)绘制直方图+核密度曲线查看单变量分布(如目标变量分布)
sns.boxplot(x, y)绘制箱线图检测异常值和类别特征的分布差异
sns.heatmap(data)绘制热力图可视化相关系数矩阵,快速定位强相关特征

2.2 EDA实现步骤及代码

2.2.1 查看前5行数据

在数据分析过程中,首先需要了解数据的基本结构和内容。为了快速掌握数据集的特征,通常会查看数据集的前几行数据。

代码如下所示:

# 3.1 数据基本信息查看
print("\n=== 数据集前5行 ===")
print(X.head())
print("\n=== 目标变量前5行 ===")
print(y.head())

特征变量和目标变量数据前5行如下图所示:

在这里插入图片描述

2.2.2 查看数据摘要信息

在数据分析过程中,了解数据集的整体结构和基本统计特征至关重要。通过查看数据的摘要信息,可以快速评估数据的质量并为后续的数据预处理和建模工作提供依据。

代码如下所示:

print("\n=== 数据类型与缺失值 ===")
print(X.info())

数据摘要信息如下图所示,该数据集共包含506条记录和13个特征变量,数据类型主要由11个连续型数值变量(float64)和2个分类变量(category)组成,所有变量均无缺失值,数据完整性良好。整体内存占用仅为45.1 KB,结构清晰、质量较高,无需进行缺失值处理,适合直接用于建模分析。其中分类变量CHAS和RAD在后续建模中需进行适当的编码转换,而丰富的数值型特征则有利于回归类模型的训练与分析。

在这里插入图片描述

2.2.3 描述性统计分析

在完成数据的基本查看和结构检查后,下一步是对数据进行描述性统计分析,以全面了解各变量的分布特征、集中趋势与离散程度。

代码如下所示:

print("\n=== 数值特征统计描述 ===")
print(X.describe())
print("\n=== 目标变量统计描述 ===")
print(y.describe())

描述性统计分析结果如下图所示:

在这里插入图片描述
特征变量描述性统计分析结果:
波士顿房价数据集的13个特征变量在数值分布上表现出多样性。多数变量如RM(平均房间数)、NOX(一氧化氮浓度)和PTRATIO(师生比)分布较为集中,标准差较小,说明数据相对稳定;而CRIM(犯罪率)和LSTAT(低收入人群比例)的最大值明显高于均值与75%分位数,可能存在极端值或右偏分布;ZN(住宅用地比例)中位数为0,表明大部分区域几乎没有大型住宅区;AGE(房龄)均值达68.57,显示多数房屋建于较早时期;DIS(距就业中心距离)和TAX(房产税)等变量则呈现出适中的离散程度。整体来看,特征变量涵盖了连续型与分类型数据,量纲差异较大,建议后续进行标准化处理以提升模型性能。

目标变量描述性统计分析结果:
目标变量MEDV(房价中位数)的均值为22.53千美元,中位数为21.2千美元,均值略高于中位数,表明其分布可能轻微右偏;最小值为5千美元,最大值为50千美元,四分位距集中在17.03至25千美元之间,说明大部分区域房价处于中等水平,但存在一定的高房价异常点(上限被截断于50万美元)。标准差约为9.2,反映出不同区域房价差异较为显著。总体来看,MEDV具备合理的变异性,适合作为回归模型的预测目标,但在建模前建议结合可视化手段进一步识别潜在异常值并考虑是否进行变换(如对数转换)以改善分布形态。

2.2.4 目标变量分布分析

代码如下所示:

# 3.2 目标变量分布分析
plt.figure(figsize=(10, 6))
# 绘制目标变量(房价)的直方图和核密度曲线
plt.hist(y, bins=30, density=True, alpha=0.7, color='skyblue', edgecolor='black')
y.plot(kind='kde', color='red', linewidth=2)  # 核密度估计曲线
plt.title('Distribution of Boston Housing Prices (MEDV)', fontsize=14)
plt.xlabel('Median Value ($1000s)', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.grid(alpha=0.3)
plt.show()

在进行线性回归分析之前,首先对目标变量 MEDV(房价中位数)的分布进行了可视化分析。通过绘制密度直方图和核密度估计曲线,如下图所示,发现 MEDV 的分布呈现出右偏特性,数据集中在15到30千美元之间,且存在少量高价位的异常值,表明大多数住宅价格位于这一区间内,而高价住宅则较少。此外,在40千美元以上出现了一个次峰,可能代表了高端住宅区的存在。

鉴于目标变量 MEDV 的非正态分布特征及存在的偏态和潜在异常值情况,在进行线性回归分析时需采取适当的预处理措施。建议考虑对 MEDV 进行对数变换以改善其分布形态,使其更接近正态分布,从而更好地满足线性回归模型的基本假设。同时,考虑到模型对异常值的敏感性,可以采用鲁棒性更强的回归算法或结合残差诊断来验证模型的拟合效果,确保模型的有效性和可靠性。如果选择继续使用普通线性回归模型,则应特别注意检查和处理这些偏离的数据点,以减少它们对模型预测性能的影响。

在这里插入图片描述

2.2.5 目标变量与各个特征变量的相关性分析

为了探究各特征变量对房价中位数(MEDV)的影响程度,本节进行了相关性分析,计算了目标变量 MEDV 与13个特征变量之间的皮尔逊相关系数。相关系数的取值范围为 [-1, 1],其绝对值越大表示线性关系越强,正负号表示方向:正值代表正相关,负值代表负相关。实现代码如下所示:

# 3.3 特征与目标变量的相关性分析
# 计算所有特征与目标变量的相关系数
df_X = X.copy()
df_X['CHAS'] = df_X['CHAS'].astype(float)
df_X['RAD'] = df_X['RAD'].astype(float)
correlations = df_X.corrwith(y).sort_values(ascending=False)
print("\n=== 特征与目标变量(MEDV)的相关系数 ===")
print(correlations)# 可视化相关性(条形图)
plt.figure(figsize=(12, 6))
correlations.plot(kind='bar', color=['green' if x > 0 else 'red' for x in correlations])
plt.title('Correlation Between Features and Housing Prices (MEDV)', fontsize=14)
plt.axhline(y=0, color='black', linestyle='--', alpha=0.3)  # 添加水平线(y=0)
plt.xlabel('Features', fontsize=12)
plt.ylabel('Correlation Coefficient', fontsize=12)
plt.grid(axis='y', alpha=0.3)
plt.xticks(rotation=45, ha='right')  # 旋转x轴标签,避免重叠
plt.show()

目标变量与各个特征变量的相关性如下图所示:

在这里插入图片描述

为了更直观地展示目标变量 MEDV(房价中位数)与各特征变量之间的线性关系强度和方向,对相关系数进行了可视化分析,绘制了柱状图以呈现每个特征变量与 MEDV 的皮尔逊相关系数。目标变量与各个特征变量的相关性可视化结果如下图所示,通过相关性可视化可以直观看出,RM 和 LSTAT 是影响房价最显著的两个变量,分别具有最强的正向和负向线性关系。其他变量如 PTRATIO、TAX、NOX 等也具有较强的解释能力,而部分变量如 ZN、CHAS 虽有一定相关性但较弱。这为后续建模提供了重要指导:可优先选择高相关性变量作为核心预测因子,并考虑剔除相关性极低的变量以简化模型。同时需注意,相关性不代表因果关系,且仅反映线性关联,建议结合散点图等方法进一步验证变量间的真实关系。

在这里插入图片描述

2.2.6 验证变量间的真实关系

在完成相关性分析后,仅依赖相关系数可能无法全面反映变量之间的实际关系。为了更深入地理解目标变量 MEDV(房价中位数)与关键特征变量之间的真实关联模式,可通过绘制散点图并叠加线性趋势线,对相关性最强的两个正相关和两个负相关特征进行可视化验证。实现代码如下所示:

# 3.4 强相关特征与目标变量的散点图
# 选择与目标变量相关性最强的2个正相关和2个负相关特征
top_positive = correlations.index[:2]  # 前2个正相关特征
top_negative = correlations.index[-2:]  # 最后2个负相关特征
selected_features = list(top_positive) + list(top_negative)plt.figure(figsize=(15, 10))
for i, feature in enumerate(selected_features, 1):plt.subplot(2, 2, i)plt.scatter(X[feature], y, alpha=0.6, color='purple', edgecolor='white', s=30)# 添加趋势线(线性拟合)z = np.polyfit(X[feature], y, 1)p = np.poly1d(z)plt.plot(X[feature], p(X[feature]), "r--")plt.title(f'{feature} vs MEDV (Corr: {correlations[feature]:.2f})', fontsize=12)plt.xlabel(feature, fontsize=10)plt.ylabel('MEDV ($1000s)', fontsize=10)plt.grid(alpha=0.3)plt.tight_layout()  # 调整子图间距
plt.show()

特征变量与目标变量相关性最强的2个正相关和2个负相关可视化结果如下图所示,从图中可以看出 RM 和 LSTAT 不仅在统计上具有强相关性,在图形上也表现出清晰的线性关系,适合作为线性回归模型的核心输入变量;ZN 和 PTRATIO 虽相关性较低或中等,但仍存在可识别的趋势,可用于辅助建模;所有变量均未显示出明显的非线性结构(如曲线、分段等),说明使用线性模型进行初步建模是合理的;数据中存在少量离群点(如 RM 较高但 MEDV 较低的情况),建议在后续建模时考虑鲁棒性方法或异常值处理策略。

在这里插入图片描述

2.2.7 特征间的相关性分析

在构建回归模型时,除了关注特征与目标变量之间的关系外,还需考察特征变量之间的相互关联性。若某些特征之间存在高度相关性(多重共线性),可能导致模型参数估计不稳定、解释能力下降或过拟合等问题。因此,通过绘制特征间相关系数热力图,全面分析各特征变量之间的线性相关关系。实现代码如下所示:

# 3.5 特征间的相关性热力图
plt.figure(figsize=(14, 10))
# 计算所有特征间的相关系数矩阵
corr_matrix = X.corr()
# 绘制热力图
import seaborn as snssns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap='coolwarm',square=True, linewidths=0.5, cbar_kws={"shrink": .8})
plt.title('Correlation Matrix of Features', fontsize=14)
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)
plt.show()

特征间的相关性热力图如下图所示,从图中可以观察到以下关键点:

  • NOX 与 DIS:相关系数为 -0.77,呈强负相关,表明距离就业中心越远(DIS越大),一氧化氮浓度越低(NOX越小),符合环境地理规律;
  • INDUS 与 NOX:相关系数为 0.76,强正相关,说明工业用地比例越高,空气污染程度也越高;
  • RAD 与 TAX:相关系数高达 0.91,属于极强正相关,意味着靠近放射状公路的区域通常税率也较高,可能存在空间集聚效应;
  • DIS 与 AGE:相关系数为 0.73,表明较老的房屋多分布在远离市中心的区域;
  • CRIM 与 RAD:相关系数为 0.63,说明高犯罪率区域往往集中在交通便利但可能管理较差的地区;
  • RM 与 LSTAT:相关系数为 -0.61,负相关较强,即房间越多的住宅区,低收入人群比例越低,反映了居住品质与社会经济水平的关联;
  • 多数其他变量之间的相关性较低(如 |r| < 0.4),说明整体上特征独立性较好。

此外,对角线上的值均为1.00,代表每个变量与自身的完全相关;颜色分布均衡,未出现大量极端值,表明数据结构较为合理。

在这里插入图片描述

通过特征间相关性热力图分析可知:

  • 数据中存在若干强相关变量对,如 RAD-TAXINDUS-NOXNOX-DIS 等,这些组合提示可能存在冗余信息或共同驱动因素;
  • 特别是 RADTAX 的相关系数高达 0.91,已接近多重共线性的警戒线(一般认为 > 0.8 需警惕),在建模时应避免同时使用这两个变量,或采用主成分分析(PCA)、岭回归等方法缓解共线性问题;
  • 其他变量之间的相关性普遍较弱,说明大多数特征提供了相对独立的信息,有利于模型的稳定性和泛化能力;
  • 建议在后续建模过程中结合方差膨胀因子(VIF) 进一步量化多重共线性影响,并根据业务逻辑选择最具代表性的变量进行建模。

2.3 EDA 完整代码

# 3. 数据探索与可视化(EDA)# 3.1 数据基本信息查看
print("\n=== 数据集前5行 ===")
print(X.head())  # 查看特征数据前5行
print("\n=== 目标变量前5行 ===")
print(y.head())  # 查看目标变量前5行print("\n=== 数据类型与缺失值 ===")
print(X.info())  # 检查特征数据类型和非空值数量print("\n=== 数值特征统计描述 ===")
print(X.describe())  # 计算特征的均值、标准差、分位数等
print("\n=== 目标变量统计描述 ===")
print(y.describe())  # 目标变量的统计信息# 3.2 目标变量分布分析
plt.figure(figsize=(10, 6))
# 绘制目标变量(房价)的直方图和核密度曲线
plt.hist(y, bins=30, density=True, alpha=0.7, color='skyblue', edgecolor='black')
y.plot(kind='kde', color='red', linewidth=2)  # 核密度估计曲线
plt.title('Distribution of Boston Housing Prices (MEDV)', fontsize=14)
plt.xlabel('Median Value ($1000s)', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.grid(alpha=0.3)
plt.show()# 3.3 特征与目标变量的相关性分析
# 计算所有特征与目标变量的相关系数
df_X = X.copy()
df_X['CHAS'] = df_X['CHAS'].astype(float)
df_X['RAD'] = df_X['RAD'].astype(float)
correlations = df_X.corrwith(y).sort_values(ascending=False)
print("\n=== 特征与目标变量(MEDV)的相关系数 ===")
print(correlations)# 可视化相关性(条形图)
plt.figure(figsize=(12, 6))
correlations.plot(kind='bar', color=['green' if x > 0 else 'red' for x in correlations])
plt.title('Correlation Between Features and Housing Prices (MEDV)', fontsize=14)
plt.axhline(y=0, color='black', linestyle='--', alpha=0.3)  # 添加水平线(y=0)
plt.xlabel('Features', fontsize=12)
plt.ylabel('Correlation Coefficient', fontsize=12)
plt.grid(axis='y', alpha=0.3)
plt.xticks(rotation=45, ha='right')  # 旋转x轴标签,避免重叠
plt.show()# 3.4 强相关特征与目标变量的散点图
# 选择与目标变量相关性最强的2个正相关和2个负相关特征
top_positive = correlations.index[:2]  # 前2个正相关特征
top_negative = correlations.index[-2:]  # 最后2个负相关特征
selected_features = list(top_positive) + list(top_negative)plt.figure(figsize=(15, 10))
for i, feature in enumerate(selected_features, 1):plt.subplot(2, 2, i)plt.scatter(X[feature], y, alpha=0.6, color='purple', edgecolor='white', s=30)# 添加趋势线(线性拟合)z = np.polyfit(X[feature], y, 1)p = np.poly1d(z)plt.plot(X[feature], p(X[feature]), "r--")plt.title(f'{feature} vs MEDV (Corr: {correlations[feature]:.2f})', fontsize=12)plt.xlabel(feature, fontsize=10)plt.ylabel('MEDV ($1000s)', fontsize=10)plt.grid(alpha=0.3)plt.tight_layout()  # 调整子图间距
plt.show()# 3.5 特征间的相关性热力图
plt.figure(figsize=(14, 10))
# 计算所有特征间的相关系数矩阵
corr_matrix = X.corr()
# 绘制热力图
import seaborn as snssns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap='coolwarm',square=True, linewidths=0.5, cbar_kws={"shrink": .8})
plt.title('Correlation Matrix of Features', fontsize=14)
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)
plt.show()

代码说明:

  1. 基本信息查看:通过head()info()describe()快速掌握数据结构、缺失值和统计分布。
  2. 目标变量分布:直方图+核密度曲线展示房价(MEDV)的分布形态,判断是否近似正态分布。
  3. 单特征相关性:通过相关系数和条形图,定位对房价影响最强的特征(如LSTAT负相关、RM正相关)。
  4. 散点图分析:对强相关特征绘制散点图并添加趋势线,直观展示线性关系强度。
  5. 特征间相关性:热力图用于检测多重共线性(如TAXRAD强相关),为特征选择提供依据。

通过以上分析,可初步确定关键特征(如RMLSTAT)对房价的影响,为后续建模提供方向。

3. 数据预处理

数据预处理是建模前的关键步骤,直接影响模型性能。

3.1 处理缺失值

波士顿房价数据集通常无缺失值,但实际场景中需常规检查和处理。

3.2 特征选择

3.2.1 特征选择相关方法

(1)variance_inflation_factor 方法介绍
variance_inflation_factorstatsmodels 库中用于检测多重共线性的核心函数,其作用是计算每个特征的方差膨胀因子(VIF)

多重共线性:指特征之间存在强线性相关关系(例如“房屋面积”和“房间数”高度相关),会导致回归模型系数不稳定、解释性下降。

VIF值含义:衡量某个特征被其他特征线性解释的程度,VIF值越大,说明该特征与其他特征的共线性越强。

通常认为 VIF < 5 表示共线性较弱;5 ≤ VIF ≤ 10 表示存在中等共线性;VIF > 10 表示存在强共线性(需要剔除)。

(2)variance_inflation_factor 参数说明

参数名称数据类型作用说明示例值
exog二维数组/矩阵输入的特征矩阵(包含多个特征),要求特征已转换为数值型,且无缺失值。X.values(假设 X 是包含筛选后特征的DataFrame)
exog_idx整数指定需要计算VIF值的特征索引(即特征在 exog 矩阵中的列位置)。0(计算第1列特征的VIF)、2(计算第3列特征的VIF)
3.2.2 特征选择:基于相关性与多重共线性分析的优化筛选

在构建线性回归模型前,合理的特征选择不仅能提升模型性能,还能增强其可解释性和稳定性。结合相关性分析方差膨胀因子(VIF) 方法,对原始特征进行两阶段筛选:首先根据与目标变量的相关系数选取强相关特征,再通过 VIF 检测并剔除存在严重多重共线性的变量,从而获得一组既具有预测能力又相互独立的最优特征子集。

  1. 第一阶段:基于相关系数筛选
    设定阈值 |corr| > 0.5,从所有特征中选出与目标变量 MEDV 相关性较强的变量。结果显示:

    • RM(平均房间数):相关系数为 0.695,正向影响显著;
    • PTRATIO(师生比):相关系数为 -0.508,负向影响较强;
    • LSTAT(低收入人群比例):相关系数为 -0.738,是影响最强的负相关变量。

    因此,初步筛选出三个特征:['RM', 'PTRATIO', 'LSTAT']

  2. 第二阶段:VIF 分析剔除多重共线性
    使用 statsmodels 计算各特征的 VIF 值,用于衡量多重共线性程度。初始 VIF 结果如下:

    • PTRATIO: VIF = 51.797 → 极高,表明其与其他变量高度相关;
    • RM: VIF = 36.068 → 也远高于警戒值(通常认为 VIF > 10 即存在严重共线性);
    • LSTAT: VIF = 5.855 → 在合理范围内。

    由于 PTRATIORM 的 VIF 值均远超 10,说明它们之间或与其它变量存在强线性依赖关系。按照策略,优先剔除 VIF 最大的特征——PTRATIO

    剔除后重新计算 VIF:

    • RM: VIF = 3.253
    • LSTAT: VIF = 3.253
      两者均降至安全范围(< 10),表明剩余特征间已无显著多重共线性问题。

实现代码如下所示:

# 方法1:基于相关系数手动筛选(选择绝对值>0.5的特征)
corr_threshold = 0.5
selected_features = correlations[abs(correlations) > corr_threshold].index.tolist()
print(f"\n基于相关系数筛选的特征(|corr| > {corr_threshold}):{selected_features}")# 方法2:计算VIF剔除多重共线性特征(可选)
from statsmodels.stats.outliers_influence import variance_inflation_factordef calculate_vif(X):vif_data = pd.DataFrame()vif_data["特征"] = X.columnsvif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]return vif_data.sort_values("VIF", ascending=False)# 初始VIF计算
vif_df = calculate_vif(X[selected_features])
print("\n初始VIF值:")
print(vif_df)# 剔除VIF>10的特征(通常认为VIF>10存在强共线性)
while vif_df["VIF"].max() > 10:# 删除VIF最大的特征drop_feature = vif_df.iloc[0]["特征"]selected_features.remove(drop_feature)vif_df = calculate_vif(X[selected_features])print(f"\n剔除特征 {drop_feature} 后VIF值:")print(vif_df)# 更新特征矩阵
X_selected = X[selected_features]
print(f"\n最终筛选后的特征:{selected_features}")

打印结果如下图所示:

在这里插入图片描述

经过两步筛选流程,最终保留的特征为:['RM', 'LSTAT']。这两个变量不仅与房价有很强的线性关系(分别对应正负方向),而且彼此之间的共线性较低,能够有效避免模型参数估计不稳定的问题。

3.3 数据标准化(归一化)

3.3.1 数据标准化相关方法

(1) 常用数据标准化方法

方法类名称功能说明适用场景
StandardScaler标准化为均值=0,标准差=1(Z-score标准化):
x' = (x - μ) / σ,其中μ为均值,σ为标准差
适用于特征值近似正态分布的场景,保留异常值的影响(如线性回归、SVM等),能有效消除量纲影响
MinMaxScaler归一化为 [0, 1]区间
x' = (x - x_min) / (x_max - x_min)
适用于特征值分布未知或有边界的场景(如神经网络输入),但对异常值敏感
RobustScaler基于中位数和四分位距标准化,抗异常值:
x' = (x - median) / (Q3 - Q1)
适用于存在较多异常值的场景,减少极端值对标准化结果的影响
Normalizer样本进行归一化(L1/L2范数),使每个样本的特征向量模长为1适用于关注样本间距离的场景(如文本分类、KNN),强调样本内部特征的相对占比

(2)fit_transform方法(核心预处理方法)
所有标准化类都继承了TransformerMixin,因此都包含fit_transform方法,其作用是先拟合数据(计算标准化所需参数,如均值、标准差),再对数据进行转换,是fittransform方法的合并操作,效率更高。

fit_transform方法参数说明(以StandardScaler为例,其他类参数类似)

参数名称数据类型默认值作用说明
X数组/矩阵(2D)输入的特征数据(形状为[n_samples, n_features]),需为数值型
y数组/NoneNone目标变量(大多数标准化方法不需要,仅为兼容sklearn的API接口保留)
sample_weight数组/NoneNone样本权重(可选),用于加权计算均值/标准差(仅部分类支持,如StandardScaler

(3)fittransform的区别

  • fit(X):仅计算标准化所需的参数(如StandardScaler会计算X的均值μ和标准差σ),不改变输入数据。
  • transform(X):使用fit计算的参数对X进行标准化转换(如应用(x - μ) / σ),但需先调用fit或直接使用fit_transform
3.3.2 数据标准化

在构建线性回归模型时,由于不同特征的量纲和数值范围差异较大(如 RM 的取值在 4~9 之间,而 LSTAT 在 1~38 之间),若不进行处理,模型会偏向于数值较大的变量,导致权重分配失衡。因此,数据标准化是必要的预处理步骤,旨在将各特征缩放到统一尺度,消除量纲的影响,使它们在模型训练中具有可比性和公平性。

本案例选择使用 StandardScaler 进行标准化,因为它更适合处理连续型数值变量且能较好地保持数据的统计特性。

实现代码如下所示:

from sklearn.preprocessing import StandardScaler# 初始化标准化器
scaler = StandardScaler()# 对筛选后的特征进行标准化
X_scaled = scaler.fit_transform(X_selected)# 转换为DataFrame便于查看
X_scaled_df = pd.DataFrame(X_scaled, columns=selected_features)
print("\n标准化后的特征前5行:")
print(X_scaled_df.head())
print("\n标准化后特征的均值和标准差:")
print(pd.DataFrame({"均值": X_scaled_df.mean().round(4),"标准差": X_scaled_df.std().round(4)
}))

标准化后的特征前5行数据和标准化后特征的均值和标准差为如下图所示,从图中可以看出经过 StandardScaler 处理后,两个特征 RMLSTAT 的均值均接近于 0,标准差均约为 1,满足标准化要求;数值范围已调整至以 0 为中心、单位方差的分布,消除了原始量纲差异的影响;每个样本的特征值现在可以公平地参与模型参数学习,避免因尺度问题导致的偏差。

在这里插入图片描述

通过数据标准化处理,成功将 RMLSTAT 两个特征转换为同一尺度下的标准化变量,显著提升了后续线性回归模型的稳定性和收敛效率。

在实际建模中,应始终在训练集上拟合标准化器(即调用 .fit_transform()),并在测试集或新数据上仅使用相同的变换规则(即调用 .transform()),以保证数据一致性,避免数据泄露。

3.4 划分训练集与测试集

3.4.1 相关方法说明
方法功能参数说明
train_test_split()随机划分数据集test_size:测试集比例(通常为0.2~0.3)
random_state:设置随机种子以保证结果可复现
shuffle:是否打乱原始数据顺序(默认为True)
3.4.2 划分训练集与测试集代码实现

在机器学习建模流程中,将数据划分为训练集测试集是评估模型泛化能力的关键步骤。训练集用于拟合模型参数,而测试集则用于独立验证模型在未见数据上的表现,避免过拟合问题。合理的划分方式能有效反映模型的真实性能。本案例使用 sklearn.model_selection.train_test_split() 函数进行划分,选择 20% 的数据作为测试集,其余 80% 用于训练,并设定 random_state=42 确保实验结果可重复。

实现代码如下所示:

# 划分训练集和测试集(测试集占20%)
X_train, X_test, y_train, y_test = train_test_split(X_scaled,  # 标准化后的特征y.values,  # 目标变量(转为数组)test_size=0.2,  # 测试集比例random_state=42  # 随机种子,保证结果可复现
)# 查看划分后的数据形状
print(f"\n训练集特征形状:{X_train.shape},测试集特征形状:{X_test.shape}")
print(f"训练集目标形状:{y_train.shape},测试集目标形状:{y_test.shape}")

运行结果如下图所示,原始数据共 506 条样本,按 8:2 比例划分后,训练集包含 404 个样本,测试集包含 102 个样本;特征维度为 2(即 RMLSTAT),因此训练集和测试集的特征矩阵均为 (n_samples, 2);目标变量为一维数组,形状分别为 (404,)(102,),符合回归任务要求;数据已通过 shuffle=True 打乱顺序,确保划分过程无偏,提升模型评估的可靠性。

在这里插入图片描述

本次数据划分合理且具有代表性,既保证了足够的训练样本用于模型学习,又保留了足够数量的测试样本用于性能评估。通过设定固定的随机种子,实现了实验结果的可复现性,便于后续对比不同模型或参数调整的效果。

3.5 预处理总结

  1. 缺失值处理:波士顿数据集无缺失值,实际场景可采用均值/中位数填充;
  2. 特征选择:结合相关系数和VIF剔除弱相关和高共线性特征,保留核心变量;
  3. 标准化:使用StandardScaler消除量纲影响,使模型更稳定;
  4. 数据集划分:按8:2比例拆分训练集和测试集,确保模型评估的客观性。

预处理后的数据集可直接用于线性回归模型训练。

4. 构建线性回归模型

线性回归是一种经典且易于解释的监督学习算法,适用于预测连续型目标变量。其核心思想是通过拟合一个线性方程来建立特征与目标之间的关系,数学表达式为:

y^=w0+w1x1+w2x2+⋯+wnxn\hat{y} = w_0 + w_1x_1 + w_2x_2 + \cdots + w_nx_n y^=w0+w1x1+w2x2++wnxn

其中,y^\hat{y}y^ 是预测的房价中位数(MEDV),w0w_0w0 为截距项,w1,w2,…,wnw_1, w_2, \ldots, w_nw1,w2,,wn 为各特征对应的回归系数,反映每个特征对目标变量的影响强度和方向。

4.1 相关方法说明

在scikit-learn(sklearn)库中,LinearRegression是用于实现普通最小二乘线性回归的类,通过拟合数据找到最佳线性关系(y=w0+w1x1+w2x2+...+wnxny = w₀ + w₁x₁ + w₂x₂ + ... + wₙxₙy=w0+w1x1+w2x2+...+wnxn),使预测值与真实值的平方误差最小。以下是其构造方法、参数及属性的详细介绍:

4.1.1 LinearRegression构造方法简介

LinearRegression的核心是通过最小化残差平方和求解回归系数,适用于连续型目标变量的线性预测问题(如房价预测、销售额预测等)。其构造方法用于初始化模型参数,语法如下:

from sklearn.linear_model import LinearRegressionmodel = LinearRegression(fit_intercept=True, normalize=False, copy_X=True, n_jobs=None, positive=False)
4.1.2 LinearRegression构造方法参数说明
参数名称数据类型默认值作用说明
fit_interceptboolTrue是否计算模型的截距项(w0w₀w0)。
- True:模型包含截距项(默认);
- False:假设数据已中心化(截距项为0)。
copy_XboolTrue是否复制输入特征数据(X)。
- True:不修改原始数据(默认);
- False:可能修改原始数据以节省内存。
n_jobsint/NoneNone用于计算的CPU核心数(仅在fit时有效)。
- None:使用1个核心(默认);
- -1:使用所有可用核心。
positiveboolFalse是否强制回归系数(w1,w2,...,wnw₁, w₂, ..., wₙw1,w2,...,wn)为非负数。
- True:系数只能≥0(适用于物理意义上非负的场景,如销量、价格);
- False:系数可正可负(默认)。
4.1.3 LinearRegression的核心属性(模型训练后可用)
属性名称数据类型含义说明
coef_数组(1D)模型的回归系数(w1,w2,...,wnw₁, w₂, ..., wₙw1,w2,...,wn),顺序与输入特征的列顺序一致。
intercept_浮点数模型的截距项(w0w₀w0),仅当fit_intercept=True时有效。
rank_int特征矩阵X的秩(反映特征的线性独立性)。
singular_数组(1D)特征矩阵X的奇异值(用于评估矩阵的稳定性)。
n_features_in_int训练时输入的特征数量。
feature_names_in_数组(1D)训练时输入的特征名称(仅当输入X为DataFrame时可用)。

在scikit-learn中,LinearRegression构造方法返回的是一个线性回归模型对象(LinearRegression实例),该对象包含模型训练、预测、评估等核心方法,以及训练后可访问的模型参数属性。以下是其方法、参数及属性的详细介绍:

4.1.4 LinearRegression对象的核心方法

这些方法用于模型训练、预测及其他操作,是使用线性回归模型的核心接口。

方法名称功能说明参数列表及说明返回值
fit(X, y)训练模型:根据输入特征X和目标变量y,求解回归系数(最小化残差平方和),残差 = 实际值 - 预测值(ei=yi−y^ie_i = y_i - \hat{y}_iei=yiy^i,绝对误差是残差的绝对值。- X:特征数据(数组/矩阵,形状为[n_samples, n_features],必须为数值型)
- y:目标变量(数组,形状为[n_samples][n_samples, n_targets]
- sample_weight(可选):样本权重数组(形状为[n_samples]),用于加权最小二乘
模型对象本身(self),支持链式调用
predict(X)预测:使用训练好的模型对新特征数据X进行预测。- X:待预测的特征数据(形状需与训练时的X一致,即[n_samples, n_features]预测结果数组(形状为[n_samples][n_samples, n_targets]
score(X, y)评估:计算模型在Xy上的决定系数(R²),衡量模型拟合优度。- X:特征数据(同predict
- y:真实目标变量(同fit
- sample_weight(可选):样本权重数组
R²值(浮点数,范围通常为(-∞, 1],越接近1表示拟合越好)
get_params(deep=True)获取模型当前的参数配置(如fit_interceptpositive等)。- deep:是否递归获取嵌套参数(默认True参数字典(键为参数名,值为对应参数值)
set_params(**params)修改模型参数(需在训练前调用)。- ** params:关键字参数,如fit_intercept=Falsepositive=True模型对象本身(更新参数后)

4.2 构建线性回归模型代码实现

实现代码如下所示:

from sklearn.linear_model import LinearRegression# 初始化线性回归模型
lr_model = LinearRegression(fit_intercept=True)# 使用训练集训练模型
lr_model.fit(X_train, y_train)# 输出模型参数
print("=== 线性回归模型参数 ===")
print(f"截距项(w0):{lr_model.intercept_:.4f}")
print("特征系数(w1...wn):")
for feature, coef in zip(selected_features, lr_model.coef_):print(f"  {feature}: {coef:.4f}")

运行结果如下图所示,截距项(w0w₀w0)= 22.5019:表示当 RM = 0LSTAT = 0 时,模型预测的房价为约 22.5 万美元。虽然现实中不可能存在房间数为零的情况,但该值是数学上的基准点。RM 的系数(w1w₁w1)= 3.8361:为正值,说明平均房间数每增加一个单位(标准化后),房价中位数将上升约 3.84 千美元(在原始尺度下需结合标准化逆变换理解)。这表明房屋规模越大,价格越高,符合经济逻辑。LSTAT 的系数(w2w₂w2)= -4.5122:为负值,说明低收入人群比例每上升一个单位(标准化后),房价下降约 4.51 千美元。这反映出社区社会经济水平对房价有显著抑制作用。

在这里插入图片描述

本模型成功建立了基于 RMLSTAT 的线性预测关系,两个特征均表现出强而明确的统计意义。模型结构简洁、可解释性强,能够清晰地揭示出房屋品质(RM)和社区社会经济状况(LSTAT)对房价的核心驱动作用。下一步将利用测试集评估模型的泛化能力,并进一步优化性能。

5. 模型预测

5.1 模型预测相关方法

方法功能输出格式
model.predict(X)对输入特征矩阵X生成预测值与X行数相同的一维数组

5.2 模型预测代码实现

在完成模型训练后,下一步是使用训练好的线性回归模型对测试集进行预测,以评估其在未见过的数据上的泛化能力。通过比较预测值与真实值之间的差异,可以直观地了解模型的预测精度和稳定性。

实现代码如下所示:

# 对训练集和测试集进行预测
y_train_pred = lr_model.predict(X_train)  # 训练集预测值
y_test_pred = lr_model.predict(X_test)    # 测试集预测值# 查看部分预测结果
print("\n=== 预测结果示例(前5条) ===")
comparison = pd.DataFrame({"真实值": y_test,"预测值": y_test_pred,"误差": (y_test_pred - y_test).round(2)
})
comparison.to_csv("线性回归预测结果.csv", index=False)
print(comparison)

运行结果的部分数据如下图所示,从误差分布来看,多数预测值接近真实值,但存在一定的系统性偏差,这可能与数据分布或模型假设有关。

在这里插入图片描述

该线性回归模型在测试集上具备一定的预测能力,能够较为准确地捕捉房价的主要影响因素。尽管个别样本存在较大误差,但总体趋势良好,说明模型具有较好的泛化性能。后续可通过计算均方误差(MSE)、决定系数(R²)等指标进一步量化评估模型表现,并考虑引入非线性项或更复杂的模型来提升精度。

6. 模型评估

6.1 常用评估指标说明

(1)评估指标说明

指标计算公式含义理想值
均方误差(MSE)1n∑i=1n(yi−y^i)2\frac{1}{n}\sum_{i=1}^n(y_i-\hat{y}_i)^2n1i=1n(yiy^i)2预测值与真实值之间平方误差的平均值,反映整体偏差大小越小越好
均方根误差(RMSE)MSE\sqrt{MSE}MSEMSE 的平方根,单位与目标变量一致,便于直观理解误差水平越小越好
决定系数(R2R^2R21−∑(yi−y^i)2∑(yi−yˉ)21-\frac{\sum(y_i-\hat{y}_i)^2}{\sum(y_i-\bar{y})^2}1(yiyˉ)2(yiy^i)2表示模型解释目标变量变异的比例,取值范围为 [0,1]越接近1越好

补充说明

  • RMSE 是最常用的误差度量,因其与原始数据单位相同(千美元),易于解释;
  • 可用于比较不同模型的拟合优度,但需注意其受样本数量影响,不能单独作为最终评判标准。

(2)sklearn.metrics中的常用评估方法
除了score方法,还可使用sklearn.metrics模块中的函数计算其他指标,适用于LinearRegression等回归模型。

评估方法功能说明参数列表及说明返回值
mean_squared_error(y_true, y_pred)计算均方误差(MSE):残差平方的均值,衡量误差的平方和- y_true:真实目标变量(数组,[n_samples][n_samples, n_targets]
- y_pred:模型预测值(与y_true形状一致)
- sample_weight(可选):样本权重
- multioutput(可选):多目标时的计算方式(默认'uniform_average',平均所有目标的MSE)
MSE值(浮点数,≥0,值越小越好)
mean_absolute_error(y_true, y_pred)计算平均绝对误差(MAE):绝对误差的均值,衡量误差的平均大小参数同mean_squared_errorMAE值(浮点数,≥0,值越小越好)
root_mean_squared_error(y_true, y_pred)(sklearn 1.2+)计算均方根误差(RMSE):MSE的平方根,单位与目标变量一致参数同mean_squared_errorRMSE值(浮点数,≥0,值越小越好)
r2_score(y_true, y_pred)计算决定系数(R²),与LinearRegression.score结果一致参数同mean_squared_errorR²值(浮点数,越接近1越好)
6.2 评估代码实现与结果分析

在完成模型训练与预测后,必须通过科学的评估指标对模型性能进行全面衡量。此处采用回归任务中常用的三大评价指标——均方误差(MSE)均方根误差(RMSE)决定系数(R²),分别计算训练集和测试集上的表现,并对比两者差异以判断是否存在过拟合现象。

实现代码如下所示:

# 计算评估指标
def evaluate(y_true, y_pred, dataset_name):mse = mean_squared_error(y_true, y_pred)rmse = np.sqrt(mse)r2 = r2_score(y_true, y_pred)print(f"\n=== {dataset_name} 评估指标 ===")print(f"均方误差(MSE):{mse:.4f}")print(f"均方根误差(RMSE):{rmse:.4f}(千美元)")print(f"决定系数(R²):{r2:.4f}")return mse, rmse, r2# 评估训练集
train_mse, train_rmse, train_r2 = evaluate(y_train, y_train_pred, "训练集")# 评估测试集
test_mse, test_rmse, test_r2 = evaluate(y_test, y_test_pred, "测试集")# 分析过拟合情况
if abs(train_r2 - test_r2) < 0.1:print("\n模型未出现明显过拟合(训练集与测试集R²差异较小)")
else:print("\n警告:模型可能存在过拟合(训练集与测试集R²差异较大)")

运行结果如下图所示,训练集的 MSE 为 30.39、RMSE 约 5.51 千美元、R² 达到 0.65,表明模型在训练数据上能较好地拟合房价变化趋势;测试集的 MSE 为 31.24,RMSE 略升至 5.59 千美元,R² 为 0.57,虽略有下降,但仍保持较高解释力;两者的 R² 差异仅为 0.0762,小于 0.1 的阈值,说明模型在测试集上的表现与训练集接近,未表现出明显的过拟合;RMSE 在两个集合间仅相差约 0.08 千美元,进一步验证了模型具有良好的泛化能力。

在这里插入图片描述

该线性回归模型在训练集和测试集上均取得了较为稳定的性能表现,具备较强的泛化能力。尽管 R² 值未达到理想水平(如 > 0.8),但在仅使用两个特征的情况下已取得不错的结果,体现了 RMLSTAT 对房价的强大解释力。模型误差控制在合理范围内(约 ±5.5 千美元),适用于初步房价预测场景。

7. 结果可视化

为了更直观地理解模型的预测性能、误差分布以及特征对房价的影响程度,此处通过三幅关键图表进行可视化分析:真实值 vs 预测值散点图预测误差分布直方图特征重要性条形图。这些图形不仅有助于评估模型表现,还能揭示潜在的问题与改进方向。

7.1 真实房价 vs 预测房价(散点图)

实现代码如下所示:

# 7.1 真实值 vs 预测值散点图
plt.figure(figsize=(10, 6))
# 绘制测试集真实值与预测值
plt.scatter(y_test, y_test_pred, alpha=0.7, color='blue', edgecolor='white', label='测试集')
# 绘制理想预测线(y=x)
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--', label='理想预测线')
plt.title(f'真实房价 vs 预测房价 (R^2={test_r2:.4f})', fontsize=14)
plt.xlabel('真实房价(千美元)', fontsize=12)
plt.ylabel('预测房价(千美元)', fontsize=12)
plt.legend()
plt.grid(alpha=0.3)
plt.show()

运行结果如下图所示,该图展示了测试集中每个样本的真实房价模型预测房价之间的关系。理想情况下,所有点应落在红色虚线(即 y=xy = xy=x)附近,表示预测值完全等于真实值。从图中可以看出大部分数据点集中在理想预测线周围,说明模型整体具有较好的拟合能力;散点呈正相关趋势,表明模型能够捕捉房价的基本变化规律;少数点偏离较远,尤其在高房价区域存在明显偏差,可能由于极端值或非线性关系未被充分建模;图标题标注了决定系数 R2=0.5740R^2 = 0.5740R2=0.5740,进一步量化了模型解释力;尽管存在一定误差,但整体趋势良好,验证了模型具备一定的泛化能力。
在这里插入图片描述

7.2 预测误差分布(直方图)

实现代码如下所示:

# 7.2 预测误差分布直方图
plt.figure(figsize=(10, 6))
errors = y_test - y_test_pred  # 计算误差(真实值-预测值)
plt.hist(errors, bins=20, alpha=0.7, color='orange', edgecolor='black')
plt.axvline(x=0, color='red', linestyle='--', label='零误差线')
plt.title(f'预测误差分布 (RMSE={test_rmse:.4f})', fontsize=14)
plt.xlabel('误差(千美元)', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.legend()
plt.grid(alpha=0.3)
plt.show()

运行结果如下图所示,该图显示了测试集上每个样本的预测误差(真实值 - 预测值)的分布情况。误差以“千美元”为单位,横轴代表误差大小,纵轴为频数。从图中可以看出,分布大致呈现近似对称的钟形曲线,中心位于零误差线(红色虚线)附近,说明大多数预测误差较小且无系统性偏移;误差主要集中在 [−10,10][-10, 10][10,10] 千美元区间内,峰值出现在接近 0 的位置,表明模型多数情况下能较为准确地估计房价;少量极端误差超过 ±15 千美元,可能是异常样本或模型未能捕捉到的复杂因素所致;RMSE 值为 5.5896 千美元,对应于误差分布的标准差水平,进一步印证了模型误差可控。误差分布合理,无明显偏向性,说明模型没有系统性高估或低估,具备良好的稳定性。

在这里插入图片描述

7.3 特征重要性(基于回归系数绝对值)

实现代码如下所示:

# 7.3 特征重要性条形图(基于系数绝对值)
plt.figure(figsize=(12, 6))
# 计算特征重要性(系数绝对值)
feature_importance = np.abs(lr_model.coef_)
# 按重要性排序
sorted_idx = np.argsort(feature_importance)[::-1]plt.bar([selected_features[i] for i in sorted_idx],[feature_importance[i] for i in sorted_idx],color=['green' if lr_model.coef_[i] > 0 else 'red' for i in sorted_idx])
plt.title('特征重要性(系数绝对值)', fontsize=14)
plt.xlabel('特征', fontsize=12)
plt.ylabel('系数绝对值(重要性)', fontsize=12)
plt.xticks(rotation=45, ha='right')
plt.grid(axis='y', alpha=0.3)
# 添加正负标记
for i in sorted_idx:plt.text(i, feature_importance[i] + 0.1,'+' if lr_model.coef_[i] > 0 else '-',ha='center', fontweight='bold')
plt.show()

运行结果如下图所示,该条形图展示了两个特征在模型中的相对重要性,其依据是线性回归系数的绝对值。颜色编码用于区分影响方向:红色柱状图LSTAT(低收入人群比例),系数为 -4.5122,绝对值最大,说明它是影响房价最强的变量,且呈负向作用——社区中低收入人口越多,房价越低;绿色柱状图RM(平均房间数),系数为 +3.8361,虽略低于 LSTAT,但依然显著,表示房屋规模越大,价格越高。LSTAT 是模型中最关键的驱动因子,而 RM 也发挥了重要作用。两者共同构建了一个简洁而有意义的预测框架,符合现实经济逻辑。
在这里插入图片描述

7.4 结果解读

  1. 真实值vs预测值:点越接近红色虚线(y=x),预测效果越好;
  2. 误差分布:若误差近似正态分布且均值接近0,说明模型无系统性偏差;
  3. 特征重要性:系数绝对值越大,特征对房价影响越强(红色为负相关,绿色为正相关)。

8. 模型解释

模型的价值不仅体现在预测精度上,更在于其能否转化为可理解的业务洞察可操作的决策依据。线性回归因其结构透明、参数可解释性强,特别适合用于解释变量与目标之间的因果关系,从而支持房地产评估、政策制定、投资分析等实际应用场景。

8.1 回归系数的业务含义

在本模型中,最终保留了两个关键特征:RM(平均房间数)和 LSTAT(低收入人群比例)。它们的回归系数如下:

  • RM 系数 ≈ +3.8361
    表示在其他条件不变的情况下,房屋平均房间数每增加 1 个单位(标准化后),房价中位数预计上升约 3.84 千美元。这反映了房屋“规模”对价格的正向驱动作用——更大的居住空间通常意味着更高的市场价值。

  • LSTAT 系数 ≈ -4.5122
    表示社区中低收入人口比例每上升 1 个单位(标准化后),房价中位数预计下降约 4.51 千美元。这揭示了社会经济环境对房产价值的显著抑制效应——低收入集中区域往往伴随教育资源薄弱、治安较差等问题,导致房价承压。

注意:由于输入特征经过标准化处理,上述“1 个单位”指的是标准差的变化。若需解释原始尺度下的影响,可通过反标准化换算,或直接使用未缩放数据重新拟合模型以获得更具现实意义的系数。

8.2 特征重要性与决策支持

特征系数符号影响方向业务解读
RM正(+)房价随房间数增加而上升开发商可优先建设大户型住宅以提升溢价能力;购房者可将房间数作为核心估值指标
LSTAT负(–)房价随低收入比例上升而下降政府可通过改善社区就业、教育水平来间接提升区域房产价值;投资者应警惕高 LSTAT 区域的资产贬值风险

8.3 模型的实际应用价值

  1. 自动化估价系统:可将该模型集成到在线房产平台,为用户提供快速、透明的房价估算;
  2. 政策效果模拟:政府可通过调整 LSTAT 相关的社会指标(如最低工资、保障房供给),预测其对区域房价的潜在影响;
  3. 投资组合优化:投资者可利用模型识别被低估或高估的区域,辅助资产配置决策;
  4. 特征监控预警:若未来某区域 LSTAT 显著上升,模型可发出房价下行预警,帮助业主或金融机构提前应对。

8.4 局限性与改进方向

尽管该模型具备良好的可解释性,但仍存在一定局限性。首先,仅基于两个特征(RM 和 LSTAT),忽略了地理位置、学区质量、交通便利性等可能显著影响房价的重要因素;其次,模型假设特征与房价之间存在线性关系,难以捕捉潜在的非线性效应,例如房间数过多可能导致单价边际递减;此外,由于输入特征经过标准化处理,回归系数反映的是标准差单位下的变化,难以直观转化为公众易于理解的实际房价变动,限制了其在面向非技术用户的场景中的直接应用。


五、完整代码

1. 完整代码

# 1. 导入库
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_openml
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split# 设置matplotlib的中文字体为SimHei(黑体),以确保中文标签可以正常显示。
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号'-'显示为方块的问题,通过设置'axes.unicode_minus'为False来实现。
plt.rcParams['axes.unicode_minus'] = False# 设置全局选项
pd.set_option('display.max_columns', None)  # 显示所有列
pd.set_option('display.width', None)  # 自动检测宽度
pd.set_option('display.max_colwidth', 50)  # 列内容最多显示50字符
pd.set_option('display.expand_frame_repr', False)  # 禁用多行表示(可选)# 2. 加载并查看数据(波士顿房价数据集)
boston = fetch_openml(name="boston", version=1, as_frame=True, parser="pandas")# 数据转换为DataFrame,便于查看
X = pd.DataFrame(boston.data, columns=boston.feature_names)
y = pd.Series(boston.target, name="MEDV")##################################################
# 3. 数据探索与可视化(EDA)# 3.1 数据基本信息查看
print("\n=== 数据集前5行 ===")
print(X.head())
print("\n=== 目标变量前5行 ===")
print(y.head())print("\n=== 数据类型与缺失值 ===")
print(X.info())print("\n=== 数值特征统计描述 ===")
print(X.describe())
print("\n=== 目标变量统计描述 ===")
print(y.describe())# 3.2 目标变量分布分析
plt.figure(figsize=(10, 6))
# 绘制目标变量(房价)的直方图和核密度曲线
plt.hist(y, bins=30, density=True, alpha=0.7, color='skyblue', edgecolor='black')
y.plot(kind='kde', color='red', linewidth=2)  # 核密度估计曲线
plt.title('Distribution of Boston Housing Prices (MEDV)', fontsize=14)
plt.xlabel('Median Value ($1000s)', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.grid(alpha=0.3)
# plt.show()# 3.3 特征与目标变量的相关性分析
# 计算所有特征与目标变量的相关系数
df_X = X.copy()
df_X['CHAS'] = df_X['CHAS'].astype(float)
df_X['RAD'] = df_X['RAD'].astype(float)
correlations = df_X.corrwith(y).sort_values(ascending=False)
print("\n=== 特征与目标变量(MEDV)的相关系数 ===")
print(correlations)# 可视化相关性(条形图)
plt.figure(figsize=(12, 6))
correlations.plot(kind='bar', color=['green' if x > 0 else 'red' for x in correlations])
plt.title('Correlation Between Features and Housing Prices (MEDV)', fontsize=14)
plt.axhline(y=0, color='black', linestyle='--', alpha=0.3)  # 添加水平线(y=0)
plt.xlabel('Features', fontsize=12)
plt.ylabel('Correlation Coefficient', fontsize=12)
plt.grid(axis='y', alpha=0.3)
plt.xticks(rotation=45, ha='right')  # 旋转x轴标签,避免重叠
# plt.show()# 3.4 强相关特征与目标变量的散点图
# 选择与目标变量相关性最强的2个正相关和2个负相关特征
top_positive = correlations.index[:2]  # 前2个正相关特征
top_negative = correlations.index[-2:]  # 最后2个负相关特征
selected_features = list(top_positive) + list(top_negative)plt.figure(figsize=(15, 10))
for i, feature in enumerate(selected_features, 1):plt.subplot(2, 2, i)plt.scatter(X[feature], y, alpha=0.6, color='purple', edgecolor='white', s=30)# 添加趋势线(线性拟合)z = np.polyfit(X[feature], y, 1)p = np.poly1d(z)plt.plot(X[feature], p(X[feature]), "r--")plt.title(f'{feature} vs MEDV (Corr: {correlations[feature]:.2f})', fontsize=12)plt.xlabel(feature, fontsize=10)plt.ylabel('MEDV ($1000s)', fontsize=10)plt.grid(alpha=0.3)plt.tight_layout()  # 调整子图间距
# plt.show()# 3.5 特征间的相关性热力图
plt.figure(figsize=(14, 10))
# 计算所有特征间的相关系数矩阵
corr_matrix = X.corr()
# 绘制热力图
import seaborn as snssns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap='coolwarm',square=True, linewidths=0.5, cbar_kws={"shrink": .8})
plt.title('Correlation Matrix of Features', fontsize=14)
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)
# plt.show()
##################################################
# 方法1:基于相关系数手动筛选(选择绝对值>0.5的特征)
corr_threshold = 0.5
selected_features = correlations[abs(correlations) > corr_threshold].index.tolist()
print(f"\n基于相关系数筛选的特征(|corr| > {corr_threshold}):{selected_features}")# 方法2:计算VIF剔除多重共线性特征(可选)
from statsmodels.stats.outliers_influence import variance_inflation_factordef calculate_vif(X):vif_data = pd.DataFrame()vif_data["特征"] = X.columnsvif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]return vif_data.sort_values("VIF", ascending=False)# 初始VIF计算
vif_df = calculate_vif(X[selected_features])
print("\n初始VIF值:")
print(vif_df)# 剔除VIF>10的特征(通常认为VIF>10存在强共线性)
while vif_df["VIF"].max() > 10:# 删除VIF最大的特征drop_feature = vif_df.iloc[0]["特征"]selected_features.remove(drop_feature)vif_df = calculate_vif(X[selected_features])print(f"\n剔除特征 {drop_feature} 后VIF值:")print(vif_df)# 更新特征矩阵
X_selected = X[selected_features]
print(f"\n最终筛选后的特征:{selected_features}")
##################################################
from sklearn.preprocessing import StandardScaler# 初始化标准化器
scaler = StandardScaler()# 对筛选后的特征进行标准化
X_scaled = scaler.fit_transform(X_selected)# 转换为DataFrame便于查看
X_scaled_df = pd.DataFrame(X_scaled, columns=selected_features)
print("\n标准化后的特征前5行:")
print(X_scaled_df.head())
print("\n标准化后特征的均值和标准差:")
print(pd.DataFrame({"均值": X_scaled_df.mean().round(4),"标准差": X_scaled_df.std().round(4)
}))
##################################################
# 划分训练集和测试集(测试集占20%)
X_train, X_test, y_train, y_test = train_test_split(X_scaled,  # 标准化后的特征y.values,  # 目标变量(转为数组)test_size=0.2,  # 测试集比例random_state=42  # 随机种子,保证结果可复现
)# 查看划分后的数据形状
print(f"\n训练集特征形状:{X_train.shape},测试集特征形状:{X_test.shape}")
print(f"训练集目标形状:{y_train.shape},测试集目标形状:{y_test.shape}")
##################################################
# 初始化线性回归模型
lr_model = LinearRegression(fit_intercept=True)# 使用训练集训练模型
lr_model.fit(X_train, y_train)# 查看模型参数
print("=== 线性回归模型参数 ===")
print(f"截距项(w0):{lr_model.intercept_:.4f}")
print("特征系数(w1...wn):")
for feature, coef in zip(selected_features, lr_model.coef_):print(f"  {feature}: {coef:.4f}")
##################################################
# 对训练集和测试集进行预测
y_train_pred = lr_model.predict(X_train)  # 训练集预测值
y_test_pred = lr_model.predict(X_test)  # 测试集预测值# 查看部分预测结果
print("\n=== 预测结果示例(前5条) ===")
comparison = pd.DataFrame({"真实值": y_test,"预测值": y_test_pred,"误差": (y_test_pred - y_test).round(2)
})
comparison.to_csv("线性回归预测结果.csv", index=False)
print(comparison)##################################################
# 计算评估指标
def evaluate(y_true, y_pred, dataset_name):mse = mean_squared_error(y_true, y_pred)rmse = np.sqrt(mse)r2 = r2_score(y_true, y_pred)print(f"\n=== {dataset_name} 评估指标 ===")print(f"均方误差(MSE):{mse:.4f}")print(f"均方根误差(RMSE):{rmse:.4f}(千美元)")print(f"决定系数(R²):{r2:.4f}")return mse, rmse, r2# 评估训练集
train_mse, train_rmse, train_r2 = evaluate(y_train, y_train_pred, "训练集")# 评估测试集
test_mse, test_rmse, test_r2 = evaluate(y_test, y_test_pred, "测试集")# 分析过拟合情况
if abs(train_r2 - test_r2) < 0.1:print("\n模型未出现明显过拟合(训练集与测试集R²差异较小)")
else:print("\n警告:模型可能存在过拟合(训练集与测试集R²差异较大)")
##################################################
# 7.1 真实值 vs 预测值散点图
plt.figure(figsize=(10, 6))
# 绘制测试集真实值与预测值
plt.scatter(y_test, y_test_pred, alpha=0.7, color='blue', edgecolor='white', label='测试集')
# 绘制理想预测线(y=x)
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--', label='理想预测线')
plt.title(f'真实房价 vs 预测房价 (R^2={test_r2:.4f})', fontsize=14)
plt.xlabel('真实房价(千美元)', fontsize=12)
plt.ylabel('预测房价(千美元)', fontsize=12)
plt.legend()
plt.grid(alpha=0.3)
plt.show()# 7.2 预测误差分布直方图
plt.figure(figsize=(10, 6))
errors = y_test - y_test_pred  # 计算误差(真实值-预测值)
plt.hist(errors, bins=20, alpha=0.7, color='orange', edgecolor='black')
plt.axvline(x=0, color='red', linestyle='--', label='零误差线')
plt.title(f'预测误差分布 (RMSE={test_rmse:.4f})', fontsize=14)
plt.xlabel('误差(千美元)', fontsize=12)
plt.ylabel('频数', fontsize=12)
plt.legend()
plt.grid(alpha=0.3)
plt.show()# 7.3 特征重要性条形图(基于系数绝对值)
plt.figure(figsize=(12, 6))
# 计算特征重要性(系数绝对值)
feature_importance = np.abs(lr_model.coef_)
# 按重要性排序
sorted_idx = np.argsort(feature_importance)[::-1]plt.bar([selected_features[i] for i in sorted_idx],[feature_importance[i] for i in sorted_idx],color=['green' if lr_model.coef_[i] > 0 else 'red' for i in sorted_idx])
plt.title('特征重要性(系数绝对值)', fontsize=14)
plt.xlabel('特征', fontsize=12)
plt.ylabel('系数绝对值(重要性)', fontsize=12)
plt.xticks(rotation=45, ha='right')
plt.grid(axis='y', alpha=0.3)plt.show()

2. 优化后完整代码

# 波士顿房价线性回归分析
# 功能:通过线性回归模型分析影响波士顿房价的关键因素并进行预测# ----------------------------
# 1. 导入必要的库
# ----------------------------
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import fetch_openml
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from statsmodels.stats.outliers_influence import variance_inflation_factor# 设置matplotlib的中文字体为SimHei(黑体),以确保中文标签可以正常显示。
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号'-'显示为方块的问题,通过设置'axes.unicode_minus'为False来实现。
plt.rcParams['axes.unicode_minus'] = False# 设置pandas显示参数
pd.set_option('display.max_columns', None)  # 显示所有列
pd.set_option('display.width', None)  # 自动检测宽度
pd.set_option('display.max_colwidth', 50)  # 列内容最多显示50字符
pd.set_option('display.expand_frame_repr', False)  # 禁用多行表示(可选)# ----------------------------
# 2. 数据加载与预处理
# ----------------------------
def load_and_prepare_data():"""加载波士顿房价数据并进行初步处理"""print("正在加载波士顿房价数据集...")# 加载数据集boston = fetch_openml(name="boston", version=1, as_frame=True, parser="pandas")# 提取特征和目标变量X = pd.DataFrame(boston.data, columns=boston.feature_names)y = pd.Series(boston.target, name="MEDV")  # MEDV: 以千美元为单位的房价中位数# 转换分类特征为数值类型X['CHAS'] = X['CHAS'].astype(float)  # 查尔斯河虚拟变量X['RAD'] = X['RAD'].astype(float)  # 径向公路可达性指数print(f"数据集加载完成 - 特征数量: {X.shape[1]}, 样本数量: {X.shape[0]}")return X, y# ----------------------------
# 3. 数据探索与可视化 (EDA)
# ----------------------------
def perform_eda(X, y):"""执行探索性数据分析"""print("\n" + "=" * 50)print("开始探索性数据分析 (EDA)")print("=" * 50)# 3.1 数据基本信息查看print("\n--- 数据集前5行 ---")print(X.head())print("\n--- 目标变量前5行 ---")print(y.head())print("\n--- 数据类型与缺失值 ---")print(X.info())print("\n--- 数值特征统计描述 ---")print(X.describe().round(2))print("\n--- 目标变量统计描述 ---")print(y.describe().round(2))# 3.2 目标变量分布分析plt.figure(figsize=(10, 6))plt.hist(y, bins=30, density=True, alpha=0.7, color='skyblue', edgecolor='black')y.plot(kind='kde', color='red', linewidth=2)plt.title('波士顿房价分布 (MEDV)', fontsize=14)plt.xlabel('房价中位数(千美元)', fontsize=12)plt.ylabel('密度', fontsize=12)plt.grid(alpha=0.3)plt.tight_layout()plt.savefig('房价分布.png', dpi=300)# plt.show()# 3.3 特征与目标变量的相关性分析correlations = X.corrwith(y).sort_values(ascending=False)print("\n--- 特征与房价的相关系数 ---")print(correlations.round(3))# 可视化相关性plt.figure(figsize=(12, 6))correlations.plot(kind='bar', color=['green' if x > 0 else 'red' for x in correlations])plt.title('特征与房价的相关性', fontsize=14)plt.axhline(y=0, color='black', linestyle='--', alpha=0.3)plt.xlabel('特征', fontsize=12)plt.ylabel('相关系数', fontsize=12)plt.grid(axis='y', alpha=0.3)plt.xticks(rotation=45, ha='right')plt.tight_layout()plt.savefig('特征相关性.png', dpi=300)# plt.show()# 3.4 强相关特征与目标变量的散点图top_positive = correlations.index[:2]  # 前2个正相关特征top_negative = correlations.index[-2:]  # 最后2个负相关特征selected_features = list(top_positive) + list(top_negative)plt.figure(figsize=(15, 10))for i, feature in enumerate(selected_features, 1):plt.subplot(2, 2, i)plt.scatter(X[feature], y, alpha=0.6, color='purple', edgecolor='white', s=30)# 添加趋势线z = np.polyfit(X[feature], y, 1)p = np.poly1d(z)plt.plot(X[feature], p(X[feature]), "r--")plt.title(f'{feature} 与房价的关系 (相关系数: {correlations[feature]:.2f})', fontsize=12)plt.xlabel(feature, fontsize=10)plt.ylabel('房价(千美元)', fontsize=10)plt.grid(alpha=0.3)plt.tight_layout()plt.savefig('强相关特征散点图.png', dpi=300)# plt.show()# 3.5 特征间的相关性热力图plt.figure(figsize=(14, 10))corr_matrix = X.corr()sns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap='coolwarm',square=True, linewidths=0.5, cbar_kws={"shrink": .8})plt.title('特征间相关性热力图', fontsize=14)plt.xticks(rotation=45, ha='right')plt.yticks(rotation=0)plt.tight_layout()plt.savefig('特征相关性热力图.png', dpi=300)# plt.show()return correlations# ----------------------------
# 4. 特征选择
# ----------------------------
def select_features(X, correlations):"""基于相关系数和VIF值选择最佳特征集"""print("\n" + "=" * 50)print("开始特征选择")print("=" * 50)# 方法1:基于相关系数筛选(选择绝对值>0.5的特征)corr_threshold = 0.5selected_features = correlations[abs(correlations) > corr_threshold].index.tolist()print(f"基于相关系数筛选的特征(|corr| > {corr_threshold}):{selected_features}")# 方法2:计算VIF剔除多重共线性特征def calculate_vif(X_df):"""计算特征的方差膨胀因子"""vif_data = pd.DataFrame()vif_data["特征"] = X_df.columnsvif_data["VIF"] = [variance_inflation_factor(X_df.values, i)for i in range(X_df.shape[1])]return vif_data.sort_values("VIF", ascending=False)# 初始VIF计算vif_df = calculate_vif(X[selected_features])print("\n初始VIF值:")print(vif_df.round(2))# 剔除VIF>10的特征(通常认为VIF>10存在强共线性)while vif_df["VIF"].max() > 10:# 删除VIF最大的特征drop_feature = vif_df.iloc[0]["特征"]selected_features.remove(drop_feature)vif_df = calculate_vif(X[selected_features])print(f"\n剔除特征 {drop_feature} 后VIF值:")print(vif_df.round(2))# 更新特征矩阵X_selected = X[selected_features]print(f"\n最终筛选后的特征:{selected_features}")return X_selected, selected_features# ----------------------------
# 5. 特征标准化与数据集划分
# ----------------------------
def preprocess_and_split(X_selected, y):"""标准化特征并划分训练集和测试集"""print("\n" + "=" * 50)print("开始特征标准化与数据集划分")print("=" * 50)# 特征标准化scaler = StandardScaler()X_scaled = scaler.fit_transform(X_selected)# 转换为DataFrame便于查看X_scaled_df = pd.DataFrame(X_scaled, columns=X_selected.columns)print("\n标准化后的特征前5行:")print(X_scaled_df.head().round(4))print("\n标准化后特征的均值和标准差:")print(pd.DataFrame({"均值": X_scaled_df.mean().round(4),"标准差": X_scaled_df.std().round(4)}))# 划分训练集和测试集(测试集占20%)X_train, X_test, y_train, y_test = train_test_split(X_scaled,y.values,test_size=0.2,random_state=42  # 固定随机种子,保证结果可复现)# 查看划分后的数据形状print(f"\n训练集特征形状:{X_train.shape},测试集特征形状:{X_test.shape}")print(f"训练集目标形状:{y_train.shape},测试集目标形状:{y_test.shape}")return X_train, X_test, y_train, y_test, scaler# ----------------------------
# 6. 模型训练与预测
# ----------------------------
def train_and_predict(X_train, X_test, y_train, selected_features):"""训练线性回归模型并进行预测"""print("\n" + "=" * 50)print("开始模型训练与预测")print("=" * 50)# 初始化并训练线性回归模型lr_model = LinearRegression(fit_intercept=True)lr_model.fit(X_train, y_train)# 查看模型参数print("\n--- 线性回归模型参数 ---")print(f"截距项(w0):{lr_model.intercept_:.4f}")print("特征系数(w1...wn):")for feature, coef in zip(selected_features, lr_model.coef_):print(f"  {feature}: {coef:.4f} ({'正相关' if coef > 0 else '负相关'})")# 进行预测y_train_pred = lr_model.predict(X_train)y_test_pred = lr_model.predict(X_test)# 保存并查看部分预测结果print("\n--- 预测结果示例(前5条) ---")comparison = pd.DataFrame({"真实值": y_test[:5].round(2),"预测值": y_test_pred[:5].round(2),"误差": (y_test_pred[:5] - y_test[:5]).round(2)})comparison.to_csv("线性回归预测结果.csv", index=False)print(comparison)return lr_model, y_train_pred, y_test_pred# ----------------------------
# 7. 模型评估
# ----------------------------
def evaluate_model(y_train, y_train_pred, y_test, y_test_pred):"""评估模型性能并可视化结果"""print("\n" + "=" * 50)print("开始模型评估")print("=" * 50)# 评估指标计算函数def evaluate(y_true, y_pred, dataset_name):mse = mean_squared_error(y_true, y_pred)rmse = np.sqrt(mse)r2 = r2_score(y_true, y_pred)print(f"\n--- {dataset_name} 评估指标 ---")print(f"均方误差(MSE):{mse:.4f}")print(f"均方根误差(RMSE):{rmse:.4f}(千美元)")print(f"决定系数(R²):{r2:.4f}")return mse, rmse, r2# 评估训练集和测试集train_mse, train_rmse, train_r2 = evaluate(y_train, y_train_pred, "训练集")test_mse, test_rmse, test_r2 = evaluate(y_test, y_test_pred, "测试集")# 分析过拟合情况if abs(train_r2 - test_r2) < 0.1:print("\n模型未出现明显过拟合(训练集与测试集R²差异较小)")else:print("\n警告:模型可能存在过拟合(训练集与测试集R²差异较大)")return train_r2, test_r2, test_rmse# ----------------------------
# 8. 结果可视化
# ----------------------------
def visualize_results(y_test, y_test_pred, test_r2, test_rmse, lr_model, selected_features):"""可视化模型结果"""print("\n" + "=" * 50)print("开始结果可视化")print("=" * 50)# 8.1 真实值 vs 预测值散点图plt.figure(figsize=(10, 6))plt.scatter(y_test, y_test_pred, alpha=0.7, color='blue', edgecolor='white', label='测试集')plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', label='理想预测线')plt.title(f'真实房价 vs 预测房价 (R^2={test_r2:.4f})', fontsize=14)plt.xlabel('真实房价(千美元)', fontsize=12)plt.ylabel('预测房价(千美元)', fontsize=12)plt.legend()plt.grid(alpha=0.3)plt.tight_layout()plt.savefig('真实值vs预测值.png', dpi=300)# plt.show()# 8.2 预测误差分布直方图plt.figure(figsize=(10, 6))errors = y_test - y_test_pred  # 计算误差(真实值-预测值)plt.hist(errors, bins=20, alpha=0.7, color='orange', edgecolor='black')plt.axvline(x=0, color='red', linestyle='--', label='零误差线')plt.title(f'预测误差分布 (RMSE={test_rmse:.4f})', fontsize=14)plt.xlabel('误差(千美元)', fontsize=12)plt.ylabel('频数', fontsize=12)plt.legend()plt.grid(alpha=0.3)plt.tight_layout()plt.savefig('预测误差分布.png', dpi=300)# plt.show()# 8.3 特征重要性条形图(基于系数绝对值)plt.figure(figsize=(12, 6))feature_importance = np.abs(lr_model.coef_)sorted_idx = np.argsort(feature_importance)[::-1]plt.bar([selected_features[i] for i in sorted_idx],[feature_importance[i] for i in sorted_idx],color=['green' if lr_model.coef_[i] > 0 else 'red' for i in sorted_idx])plt.title('特征重要性(系数绝对值)', fontsize=14)plt.xlabel('特征', fontsize=12)plt.ylabel('系数绝对值(重要性)', fontsize=12)plt.xticks(rotation=45, ha='right')plt.grid(axis='y', alpha=0.3)plt.tight_layout()plt.savefig('特征重要性.png', dpi=300)# plt.show()# 程序入口
if __name__ == "__main__":"""主函数:执行波士顿房价分析的完整流程"""print("=" * 70)print("          波士顿房价线性回归分析          ")print("=" * 70)# 执行完整分析流程X, y = load_and_prepare_data()correlations = perform_eda(X, y)X_selected, selected_features = select_features(X, correlations)X_train, X_test, y_train, y_test, scaler = preprocess_and_split(X_selected, y)lr_model, y_train_pred, y_test_pred = train_and_predict(X_train, X_test, y_train, selected_features)train_r2, test_r2, test_rmse = evaluate_model(y_train, y_train_pred, y_test, y_test_pred)visualize_results(y_test, y_test_pred, test_r2, test_rmse, lr_model, selected_features)print("\n" + "=" * 70)print("          分析完成!所有结果已保存          ")print("=" * 70)
http://www.dtcms.com/a/569647.html

相关文章:

  • 中国建设银行官网站企业企业信息网查询
  • [创业之路-709]:管理与经营的异同
  • 网站的数据库在哪里专业上海网站建设
  • 使用IOT-Tree Server通过S7 Eth协议连接西门子PLC S7-1200
  • 59网一起做网站如何把字体安装在wordpress
  • PostgreSQL 之上的开源时序数据库 TimescaleDB 详解
  • wordpress网站投放广告网站后台管理图片
  • 查询域名网站软文写作是什么意思
  • TCN-Transformer-GRU时间卷积神经网络结合编码器组合门控循环单元多特征分类预测Matlab实现
  • 类和对象(中):深入理解 C++ 类与对象:6 个默认成员函数核心解析
  • 中山哪里有做微网站的中国经济网
  • win11蓝屏笑脸提示重启怎么回事 蓝屏重启解决方法
  • 佰力博检测与你探讨压电薄膜介电/阻抗-频谱的应用领域有哪些
  • 长沙教育类网站建设好兄弟资源网
  • C++:哈希表的实现
  • 本地化部署后定制解决方案
  • Java中的WebSocket与实时通信!
  • SQL server创建数据表
  • MacOS-Terminal直接command解压缩文件文件夹
  • GIM 模型转 GLB 模型:从格式适配到前端渲染的完整方案
  • 什么是网站平台开发wordpress链接优化
  • 软件测试——自动化测试概念
  • 大模型-详解 Vision Transformer (ViT)
  • 建站公司互橙知乎郑州seo哪家专业
  • 09-ubuntu20.04 执行 apt update时报错,是因为官网已停止维护不再更新的缘故吗?
  • 南通做网站找谁求网站懂的说下开车
  • ps做网站宽度重庆公司团建推荐
  • uniapp中的uni_modules分包
  • 算法笔记 09
  • 【VLAs篇】08:以实时速度运行VLA