【学习笔记】 陈强-机器学习-Python-Ch4 线性回归

文章目录

说明

本学习笔记 仅为以防自己忘记了,顺便分享给一起学习的网友们参考。如有不同意见/建议,可以友好讨论。

本学习笔记 所有的代码和数据都可以从 陈强老师的个人主页 上下载

参考书目:陈强.机器学习及Python应用. 北京:高等教育出版社, 2021.

数学原理等 详见陈强老师的 PPT


书上的线性回归Python案例(参考网友阡之尘埃Python机器学习02——线性回归 )

但,原书所用数据被移除

原书所用数据 load_boston 函数 自从 scikit-learn 版本 1.2 起,已经被移除了(因为波士顿房价数据中创建了一个基于种族自我隔离影响房价的不可逆变量 “B”,这引发了伦理上的担忧。) 该死的zz正确……

scikit-learn 官方给出的解决方法:
1. 从原始来源获取波士顿房价数据集并处理的示例代码,使用了 pandas 和 numpy
import pandas as pd
import numpy as np

data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep="\s+", skiprows=22, header=None)
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]
2. 使用其他替代数据集,例如加利福尼亚房价数据集或艾姆斯房价数据集。
1.)加载加利福尼亚房价数据集(the California housing dataset):
from sklearn.datasets import fetch_california_housing
housing = fetch_california_housing( )
2.)加载艾姆斯房价数据集(the Ames housing dataset):
from sklearn.datasets import fetch_openml
housing = fetch_openml(name="house_prices", as_frame=True)

前期准备:安装库(pandas,numpy,matplotlib,scikit-learn,SciPy)

一、原 波士顿房价数据集

1. 导入数据集,并参看基本信息

import pandas as pd
import numpy as np

# 从原始来源加载数据
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)

# 处理数据
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 创建DataFrame
columns = [
    "CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX", 
    "PTRATIO", "B", "LSTAT"
]
df = pd.DataFrame(data, columns=columns)
df['MEDV'] = target

# 查看数据集的基本信息
print("\n数据集的信息:")
print(df.info())

print("数据集的前几行:")
print(df.head())

print("\n数据集的描述性统计:")
print(df.describe())
逐行解释代码:
  • 使用Pandas库的read_csv函数从data_url读取数据。
  • sep=r"\s+" 表示指定了数据之间的分隔符是一个或多个空白字符。
  • skiprows=22 跳过前22行数据,因为波士顿数据集的前几行是描述性文本,不是数据本身。
  • header=None 表示数据集没有列名,所有数据被当做内容加载。
  • raw_df.valuespandas DataFrame 转换为 NumPy 数组。
  • raw_df.values[::2, :] 取出 raw_df 数组的偶数行(0, 2, 4, …)→包含了特征数据。
  • raw_df.values[1::2, :2] 取出 raw_df 数组的奇数行(1, 3, 5, …)的前两列→包含了特征数据。
  • np.hstack([...]) 将上述取出的两个 NumPy 数组水平堆叠在一起,形成一个新的 NumPy 数组 data
  • raw_df.values[1::2, 2] 取出 原始数据 raw_df 数组的奇数行的第三列(房价),并将其赋值给target变量。
  • columns = [ ... ]:定义一个列表columns,包含特征的名称,按顺序排列。
  • df['MEDV'] = target:将目标值target添加到DataFrame中,列名为MEDV
输出结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2. 房间中位数(MEDV)对房间数(RM)的一元线性回归分析

import statsmodels.api as sm
import matplotlib.pyplot as plt

# 提取特征和目标值
X = df['RM']
y = df['MEDV']

# 添加常数项以进行截距项估计
X = sm.add_constant(X)

# 使用statsmodels进行线性回归
model = sm.OLS(y, X).fit()

# 输出回归结果的总结
print(model.summary())

# 数据可视化:绘制散点图和回归线
plt.figure(figsize=(10, 6)) #创建一个新的图形对象,并设置图形大小为10英寸宽、6英寸高。
plt.scatter(df['RM'], df['MEDV'], color='blue', alpha=0.5, label='Data points') #横轴为RM,纵轴为MEDV。数据点颜色为蓝色,透明度为0.5,标签为"Data points"。
plt.plot(df['RM'], model.fittedvalues, color='red', linewidth=2, label='Regression line') #回归线颜色为红色,线宽为2,标签为"Regression line"。
plt.xlabel("Number of rooms per dwelling (RM)") #设置横轴标签
plt.ylabel("Median Value of owner-occupied homes (MEDV)") #设置纵轴标签
plt.title("Linear Regression: RM vs MEDV") #设置图形标题
plt.legend() #显示图例,以便区分数据点和回归线。
plt.show()  #显示绘制好的图形。
逐行解释代码:
  • 导入Statsmodels库,并将其命名为sm,用于统计建模和回归分析。
  • 导入Matplotlib库中的pyplot模块,并将其命名为plt,用于数据可视化。
  • X = df['RM']:提取DataFrame中的RM列作为特征变量X
  • y = df['MEDV']:提取DataFrame中的MEDV列作为目标变量y
  • X = sm.add_constant(X):使用Statsmodels库的add_constant函数在特征矩阵X中添加一个常数项(列),以便进行截距项的估计。
  • model = sm.OLS(y, X).fit():使用StatsmodelsOLS(普通最小二乘法)函数创建线性回归模型,并拟合数据Xyfit方法返回拟合好的回归模型对象。
输出结果:

在这里插入图片描述
在这里插入图片描述

3.MEDVRMAGE的二元线性回归分析

1)普通二元线性回归

# 提取特征和目标值
X = df[['RM', 'AGE']] #在回归中加入变量AGE
y = df['MEDV']

# 添加常数项以进行截距项估计
X = sm.add_constant(X)

# 使用statsmodels进行线性回归
model = sm.OLS(y, X).fit()

# 输出回归结果的总结
print(model.summary())

# 可视化残差图:识别模型是否适合数据,是否存在模式、偏差或其他问题。
plt.figure(figsize=(10, 6))
plt.scatter(model.fittedvalues, model.resid, color='blue', alpha=0.5)
plt.axhline(y=0, color='red', linestyle='--')
plt.xlabel('Fitted values')
plt.ylabel('Residuals')
plt.title('Residual plot')
plt.show()

# 可视化房间数对房价的回归效果(平面图)
plt.figure(figsize=(10, 6))
plt.scatter(df['RM'], df['MEDV'], color='blue', alpha=0.5, label='Data points')
predicted_values = model.predict(X)
plt.plot(df['RM'], predicted_values, color='red', linewidth=2, label='Regression line')
plt.xlabel("Number of rooms per dwelling (RM)")
plt.ylabel("Median Value of owner-occupied homes (MEDV)")
plt.title("Linear Regression: RM, AGE vs MEDV")
plt.legend()
plt.show()
输出结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三维图(3D图)

由于二维图(平面图)不能直观反应两个特征变量与响应变量之间的关系,遂绘制3D图。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D #导入 mpl_toolkits.mplot3d 库中的 Axes3D 模块。

# 可视化房间数和年龄对房价的回归效果(3D图)
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')  #在图形对象中添加一个3D子图(projection='3d')

# 散点图
ax.scatter(df['RM'], df['AGE'], df['MEDV'], color='blue', alpha=0.5, label='Data points')

# 创建网格以绘制回归平面
rm_surf, age_surf = np.meshgrid(
    np.linspace(df['RM'].min(), df['RM'].max(), 100),
    np.linspace(df['AGE'].min(), df['AGE'].max(), 100)
) #使用np.meshgrid创建一个二维网格,rm_surf和age_surf分别表示RM和AGE的网格坐标。
exog = pd.DataFrame({'const': 1, 'RM': rm_surf.ravel(), 'AGE': age_surf.ravel()}) #创建一个新的DataFrame exog,包含常数项(const=1)、RM和AGE
medv_surf = model.predict(exog).values.reshape(rm_surf.shape) #reshape(rm_surf.shape)将预测值重新整形为与网格相同的形状,以便绘制三维表面图。

# 绘制回归平面
ax.plot_surface(rm_surf, age_surf, medv_surf, color='red', alpha=0.5, label='Regression plane')

# 设置视角:elev参数为俯仰角度(相对于xy平面的角度),azim参数为方位角度(绕z轴的旋转角度)
ax.view_init(elev=30, azim=45) 

ax.set_xlabel('Number of rooms per dwelling (RM)') #设置x轴标签
ax.set_ylabel('Age of house (AGE)') #设置y轴标签
ax.set_zlabel('Median Value of owner-occupied homes (MEDV)') #设置z轴标签
ax.set_title('Linear Regression: RM, AGE vs MEDV')

plt.legend() #显示图例,以区分数据点和回归平面
plt.show()
输出结果:

在这里插入图片描述

2)RMAGE的交互项

交互项考虑了自变量之间的相互作用效应。在统计学和回归分析中,交互项指的是两个或多个自变量之间的乘积,它们的乘积作为一个新的自变量被加入到回归模型中。

# 提取特征和目标值,添加交互项
df['RM*AGE'] = df['RM'] * df['AGE'] #RM与AGE的交互项
X = df[['RM', 'AGE', 'RM*AGE']]
y = df['MEDV']

# 添加常数项以进行截距项估计
X = sm.add_constant(X)

# 使用statsmodels进行线性回归
model = sm.OLS(y, X).fit()

# 输出回归结果的总结
print(model.summary())

# 可视化房间数和年龄对房价的回归效果(3D图)
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

# 散点图
ax.scatter(df['RM'], df['AGE'], df['MEDV'], color='blue', alpha=0.5, label='Data points')

# 创建网格以绘制回归平面
rm_surf, age_surf = np.meshgrid(
    np.linspace(df['RM'].min(), df['RM'].max(), 100),
    np.linspace(df['AGE'].min(), df['AGE'].max(), 100)
)
exog = pd.DataFrame({
    'const': 1,
    'RM': rm_surf.ravel(),
    'AGE': age_surf.ravel(),
    'RM*AGE': (rm_surf.ravel() * age_surf.ravel())
})
medv_surf = model.predict(exog).values.reshape(rm_surf.shape)

# 绘制回归平面
ax.plot_surface(rm_surf, age_surf, medv_surf, color='red', alpha=0.5)

# 设置视角:elev参数为俯仰角度,azim参数为方位角度
ax.view_init(elev=15, azim=60)

ax.set_xlabel('Number of rooms per dwelling (RM)')
ax.set_ylabel('Age of house (AGE)')
ax.set_zlabel('Median Value of owner-occupied homes (MEDV)')
ax.set_title('Linear Regression with Interaction: RM, AGE vs MEDV')

plt.show()
输出结果:

在这里插入图片描述
在这里插入图片描述

3)加入RMAGE的平方项

在多元线性回归模型中加入平方项可以:1)捕捉特征和目标变量之间的非线性关系;2)提高模型的拟合度,从而提高模型的解释能力和预测准确性;3)可以帮助捕捉数据中存在曲率(如U形或倒U形关系)。

# 提取特征和目标值,添加交互项和平方项
df['RM*AGE'] = df['RM'] * df['AGE']
df['RM^2'] = df['RM'] ** 2
df['AGE^2'] = df['AGE'] ** 2
X = df[['RM', 'AGE', 'RM*AGE', 'RM^2', 'AGE^2']]
y = df['MEDV']

# 添加常数项以进行截距项估计
X = sm.add_constant(X)

# 使用statsmodels进行线性回归
model = sm.OLS(y, X).fit()

# 输出回归结果的总结
print(model.summary())

# 可视化房间数和年龄对房价的回归效果(3D图)
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

# 散点图
ax.scatter(df['RM'], df['AGE'], df['MEDV'], color='blue', alpha=0.5, label='Data points')

# 创建网格以绘制回归平面
rm_surf, age_surf = np.meshgrid(
    np.linspace(df['RM'].min(), df['RM'].max(), 100),
    np.linspace(df['AGE'].min(), df['AGE'].max(), 100)
)
exog = pd.DataFrame({
    'const': 1,
    'RM': rm_surf.ravel(),
    'AGE': age_surf.ravel(),
    'RM*AGE': rm_surf.ravel() * age_surf.ravel(),
    'RM^2': rm_surf.ravel() ** 2,
    'AGE^2': age_surf.ravel() ** 2
})
medv_surf = model.predict(exog).values.reshape(rm_surf.shape)

# 绘制回归平面
ax.plot_surface(rm_surf, age_surf, medv_surf, color='red', alpha=0.5)

# 设置视角
ax.view_init(elev=15, azim=75)

ax.set_xlabel('Number of rooms per dwelling (RM)')
ax.set_ylabel('Age of house (AGE)')
ax.set_zlabel('Median Value of owner-occupied homes (MEDV)')
ax.set_title('Linear Regression with Interaction and Polynomial Terms: RM, AGE vs MEDV')

plt.show()
输出结果:

在这里插入图片描述
在这里插入图片描述

4. 所有变量 的线性回归(选变量)

# 提取所有特征变量和目标值
X = df.drop(columns='MEDV')  #选择所有特征变量(即除了MEDV以外的所有列)
y = df['MEDV']

# 添加常数项以进行截距项估计
X = sm.add_constant(X)

# 使用statsmodels进行线性回归
model = sm.OLS(y, X).fit()

# 输出回归结果的总结
print(model.summary())
输出结果:

在这里插入图片描述

去除不显著变量

以上结果中,AGE(房屋年龄)高度不显著(P值高达0.958>>>0.05),其对因变量的影响可能是随机的或者可以忽略不计的。可以去除

# 提取所有特征变量和目标值,去掉AGE
X = df.drop(columns=['MEDV', 'AGE'])
y = df['MEDV']

# 添加常数项以进行截距项估计
X = sm.add_constant(X)

# 使用statsmodels进行线性回归
model = sm.OLS(y, X).fit()

# 输出回归结果的总结
print(model.summary())

在这里插入图片描述

去掉AGE特征后,如果R-squared (R²)和调整后的R-squared没有任何变化,这可能意味着AGE特征对目标变量(MEDV)的贡献非常小或者没有贡献。因此,移除这个特征对模型的解释力几乎没有影响。

5.使用statsmodels的公式接口(smf)进行回归分析

以上回归都是用statsmodels模块中基于数组``array-based的接口(sm),也可以使用基于公式formula-based的接口(statsmodels.formula.api,简称smf`)更方便地进行回归分析(特别是当需要处理交互项和多项式项时)。

#使用公式接口进行包含所有特征变量(去掉AGE)的回归分析

import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
import matplotlib.pyplot as plt

# 从原始来源加载数据
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)

# 处理数据
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 创建DataFrame
columns = [
    "CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX", 
    "PTRATIO", "B", "LSTAT"
]
df = pd.DataFrame(data, columns=columns)
df['MEDV'] = target

# 去掉AGE特征
df = df.drop(columns=['AGE'])

# 使用公式接口进行线性回归
model = smf.ols(formula='MEDV ~ ' + ' + '.join(df.columns.difference(['MEDV'])), data=df).fit()

# 输出回归结果的总结
print(model.summary())

输出结果:与sm是等价的

使用公式接口(交互项以及平方项)
# 添加交互项和平方项
df['RM_AGE'] = df['RM'] * df['AGE']
df['RM2'] = df['RM'] ** 2
df['AGE2'] = df['AGE'] ** 2

# 使用公式接口进行线性回归
formula = 'MEDV ~ RM + AGE + RM_AGE + RM2 + AGE2'
model = smf.ols(formula=formula, data=df).fit()

# 输出回归结果的总结
print(model.summary())

输出结果:与sm是等价的

6. 集法与交叉验证法考察模型的测试误差

以下使用sklearn模块,以验证集法与交叉验证法考察模型的测试误差。

sklearn模块(全称:SciPy Toolkit for Machine Learning, 安装:pip install scikit-learn。

sklearn v.s. statsmodelssklearn不进行统计推断(不提供标准差、p值、置信区间等),但机器学习方面更全面。

1)将样本随机分割为训练集(70%)和测试集(30%)

import pandas as pd
import numpy as np

from sklearn.model_selection import train_test_split #从sklearn.model_selection模块中导入了函数:train_test_split (用于将数据集分割成训练集和测试集,常用于模型训练和评估。)

# 从原始来源加载数据
data_url = "http://lib.stat.cmu.edu/datasets/boston"
raw_df = pd.read_csv(data_url, sep=r"\s+", skiprows=22, header=None)

# 处理数据
data = np.hstack([raw_df.values[::2, :], raw_df.values[1::2, :2]])
target = raw_df.values[1::2, 2]

# 创建DataFrame
columns = [
    "CRIM", "ZN", "INDUS", "CHAS", "NOX", "RM", "AGE", "DIS", "RAD", "TAX", 
    "PTRATIO", "B", "LSTAT"
]
df = pd.DataFrame(data, columns=columns)
df['MEDV'] = target

# 确定特征
X = df.drop(columns=['MEDV'])
y = df['MEDV']

# 将数据分割为训练集(70%)和测试集(30%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0) #函数的返回值依次分配给四个变量:X_train、X_test、y_train、y_test。 test_size=0.3 表示将数据集拆分成 70% 的训练集和 30% 的测试集。random_state=0 是一个随机种子,确保每次运行代码时都能得到相同的随机结果。

X_train.shape, X_test.shape, y_train.shape, y_test.shape #显示了特征矩阵和目标向量的形状。

输出结果:((354, 13), (152, 13), (354,), (152,))

  • X_train.shape(354, 13),表示训练集 X_train 包含 354 个样本和 13 个特征 (原始数据集 X 中有 13 个特征(自变量))。
  • X_test.shape(152, 13),表示测试集 X_test 包含 152 个样本(30%)和 13 个特征。
  • y_train.shape(354,),表示训练集 y_train 包含 354 个目标变量值。
  • y_test.shape(152,),表示测试集 y_test 包含 152 个目标变量值(30%)。

2)建立线性回归模型

from sklearn.linear_model import LinearRegression #从sklearn.linear_model模块中导入了LinearRegression类,用于执行线性回归(拟合线性模型,进行预测和评估模型等操作)。

# 建立线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)

# 输出回归系数
model.coef_

输出结果:

array([-1.21310401e-01,  4.44664254e-02,  1.13416945e-02,  2.51124642e+00,
       -1.62312529e+01,  3.85906801e+00, -9.98516565e-03, -1.50026956e+00,
        2.42143466e-01, -1.10716124e-02, -1.01775264e+00,  6.81446545e-03,
       -4.86738066e-01])
  • 在sklearn中,所有估计所得的属性,都已下划线“_”结尾。
  • 回归系数 model.coef_ 是一个数组,每个元素对应于模型中每个特征(变量)的回归系数。

3)回归模型在测试集中的拟合优度

#测试集中的拟合优度
model.score(X_test, y_test) #score()方法输出是R^2

输出结果:0.673382550640016

  • 使用 score() 方法计算线性回归模型在测试集上的拟合优度(R²)
  • R²范围通常从0到1,越接近1,表示模型对目标变量的解释能力越强,模型的拟合效果越好。
  • 0.673382550640016:意味着模型能够解释测试集中约67.34%的因变量的方差(变动幅度)。(≈ 模型能够比较好地预测因变量在测试数据中的变化。)

4)在测试集中进行预测

# 预测
pred = model.predict(X_test) #使用训练好的线性回归模型 model 对测试集 X_test 进行预测,得到预测结果存储在变量 pred 中。
pred.shape

输出结果:(152,)

  • (152,) 表示响应变量在测试集的测试结果为 152*1的向量。
from sklearn.metrics import mean_squared_error, r2_score

mean_squared_error(y_test, pred)
r2_score(y_test, pred)

输出结果:

27.19596576688351
0.673382550640016
  • sklearn.metrics模块中导入了两个函数:mean_squared_error(用于计算预测值与真实值之间的均方误差 MSE)和r2_score(R²)。
  • 均方误差 (MSE):它提供了关于模型预测误差的信息。较低的 MSE 值表示模型的预测结果与实际观测值更接近,模型的预测效果更好。
  • 27.19596576688351:模型的均方误差较高,可能意味着预测值与真实值之间存在较大的差异
  • 决定系数 R² 与score()一致

5)考察验证 集法的稳定性 (随机数种子验证稳定性)

# 将数据分割为训练集(70%)和测试集(30%),随机数种子12345
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=12345)

model = LinearRegression().fit(X_train, y_train)

pred = model.predict(X_test)

mean_squared_error(y_test, pred)

输出结果:21.767979165646647

  • MSE差异较大

6)K折交叉验证

在机器学习中,交叉验证(Cross-Validation)是一种评估模型性能和泛化能力的重要技术。

使用KFold方法进行交叉验证
#导入所需类(class)/函数
from sklearn.model_selection import KFold #将样本随机分组
from sklearn.model_selection import LeaveOneOut #进行留一交叉验证
from sklearn.model_selection import RepeatedKFold #重复进行K折交叉验证
from sklearn.model_selection import cross_val_score #计算交叉验证的得分

model = LinearRegression()

kfold = KFold(n_splits=10,shuffle=True, random_state=1) #使用KFold方法设置交叉验证对象。n_splits=10 表示将数据分成10份进行交叉验证。shuffle=True表示在进行数据分割之前会随机地将数据的顺序打乱,然后再分成指定数量的折数。random_state=1 是为了保证结果的可重复性。

scores = cross_val_score(model, X, y, cv=kfold)
scores
  • KFold 方法:
    • n_splits=10 表示将数据分成10份进行交叉验证。
    • shuffle
      • =True表示在进行数据分割之前会随机地将数据的顺序打乱,然后再分成指定数量的折数;避免模型在某些特定顺序下学习到的偏差,增加模型评估的客观性和可靠性。适用于数据没有特定顺序要求或者需要增加模型评估的多样性和稳健性的场景。
      • =False 表示不会对数据进行打乱。适用于需要保留数据原始顺序,或者数据已经是随机排列的情况下,为了保持数据分割的一致性和可重复性。
    • random_state参数在很多情况下用于控制随机性,以确保实验结果的可重复性。
      • random_state=1 是一种惯用的设定,用于确保在相同的实验条件下,得到相同的随机结果,从而方便结果的比较和验证。
      • 如果需要改变随机种子,可以尝试不同的整数值,如 random_state=2random_state=100,以产生不同的随机实验结果,但要保证在相同的实验中保持一致。

输出结果:

array([0.77863866, 0.76632537, 0.8729179 , 0.44002779, 0.84715141, 0.71692423, 0.72093063, 0.59299064, 0.69816152, 0.75603868]) #有结果可知,10个子样本的R²波动较大
计算子样本的平均值与标准差 得出模型的整体性能评估
#计算10个子样本的平均值与标准差 得出模型的整体性能评估
scores.mean()
scores.std()

输出结果:0.7190106820189478 ;0.11892348692223169

交叉验证评估模型性能
#交叉验证评估模型性能 (通常使用不同的评分指标)
#负均方误差(Negative Mean Squared Error(即MSE的负值),neg_mean_squared_error)作为评分指标来评估模型 --由“最小化均分误差”等价于“最大化MSE的负值”
scores_mse = -cross_val_score(model, X, y, cv=rkfold, scoring='neg_mean_squared_error') 

输出结果:

array([20.54427466, 24.47650033,  9.49619045, 48.63290854, 12.11906454,18.14673907, 17.53359386, 38.67822303, 34.22829546, 13.73556966]) #每个子样本的MSE波动较大
计算子样本的平均值
scores_mse.mean()

输出结果:23.96235668171335

  • 结果显示:MSE值:约为 23.96(实际上是负数,所以模型的均方误差是 -23.96
不同的随机种子进行交叉验证
#不同的随机种子进行交叉验证
kfold = KFold(n_splits=10,shuffle=True, random_state=123)
scores_mse = -cross_val_score(model, X, y, cv=rkfold, scoring='neg_mean_squared_error') 
scores_mse.mean()

输出结果:23.96235668171335

  • 结果显示:随机种子对于交叉验证误差的影响不大。
重复进行K折交叉验证
#重复进行K折交叉验证
rkfold = RepeatedKFold(n_splits=10, n_repeats=10, random_state=1)

scores_mse = -cross_val_score(model, X, y, cv=rkfold, scoring='neg_mean_squared_error') 

scores_mse.shape
scores_mse.mean()

输出结果:

(100,) #100✖1的向量。10折交叉验证,重复10次,因此总共有 10 * 10 = 100 个子样本。
23.96235668171335 #MSE没有变化
画出10折交叉验证MSE的直方图和核密度图
#画出这100个子样本MSE的直方图和核密度图
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# 使用histplot绘制MSE分布
sns.histplot(pd.DataFrame(scores_mse), kde=True) #启用核密度估计(kde=True)
plt.xlabel('MSE')
plt.title('10-fold CV Repeated 10 Times')
plt.show()

输出结果:

在这里插入图片描述

进行留一交叉验证
#进行留一交叉验证
loo = LeaveOneOut()
scores_mse = -cross_val_score(model, X, y, cv=loo, scoring='neg_mean_squared_error')
scores_mse.mean()  
  • LeaveOneOut() 等价于 “KFold(n_splits=n)” (即,n折的KFold类)

输出结果:23.725745519476153

  • 结果显示:LOOCV(留一交叉)所估计的交叉验证误差也十分接近。

二、加利福尼亚房价数据集

这是我自己当做作业写得代码,不知道对不对。

import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split, cross_val_score, KFold, RepeatedKFold
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt

# 加载加州房价数据集
data = fetch_california_housing()
X = data.data
y = data.target

# 将数据分割为训练集(70%)和测试集(30%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# 建立线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)

# 打印回归系数和拟合优度
print("回归系数:", model.coef_)
print("截距:", model.intercept_)
print("拟合优度:", model.score(X_test, y_test))

# 预测
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)

# 计算训练误差和测试误差
train_mse = mean_squared_error(y_train, y_train_pred)
test_mse = mean_squared_error(y_test, y_test_pred)
train_r2 = r2_score(y_train, y_train_pred)
test_r2 = r2_score(y_test, y_test_pred)

print("训练集均方误差 (MSE):", train_mse)
print("测试集均方误差 (MSE):", test_mse)
print("训练集R平方 (R^2):", train_r2)
print("测试集R平方 (R^2):", test_r2)

# 使用KFold进行交叉验证评估模型性能
kfold = KFold(n_splits=10, shuffle=True, random_state=1)
scores_mse = -cross_val_score(model, X, y, cv=kfold, scoring='neg_mean_squared_error')
print("KFold 交叉验证均方误差 (MSE):", scores_mse)
print("KFold 交叉验证均方误差 (MSE) 平均值:", scores_mse.mean())
print("KFold 交叉验证均方误差 (MSE) 标准差:", scores_mse.std())

# 使用RepeatedKFold进行交叉验证评估模型性能
rkfold = RepeatedKFold(n_splits=10, n_repeats=5, random_state=1)
scores_rkfold_mse = -cross_val_score(model, X, y, cv=rkfold, scoring='neg_mean_squared_error')
print("重复K折交叉验证均方误差 (MSE):", scores_rkfold_mse)
print("重复K折交叉验证均方误差 (MSE) 平均值:", scores_rkfold_mse.mean())
print("重复K折交叉验证均方误差 (MSE) 标准差:", scores_rkfold_mse.std())

# 使用histplot绘制MSE分布
import seaborn as sns

sns.histplot(pd.DataFrame(scores_mse), kde=True)
plt.xlabel('MSE')
plt.title('10-fold CV Repeated 10 Times')
plt.show()

输出结果:

回归系数: [ 4.46773975e-01  9.18409990e-03 -1.18116775e-01  6.42290879e-01 -9.37026507e-06 -4.08535934e-03 -4.09023312e-01 -4.23419564e-01]
截距: -36.012228887652384
拟合优度: 0.5926087785518777
训练集均方误差 (MSE): 0.5173003362697665
测试集均方误差 (MSE): 0.543148967003724
训练集R平方 (R^2): 0.6112941337977223
测试集R平方 (R^2): 0.5926087785518777
KFold 交叉验证均方误差 (MSE): [0.53684797 0.52071965 0.52875513 0.49601516 0.54291573 0.53637433 0.50023284 0.51324893 0.53039931 0.57689184]
KFold 交叉验证均方误差 (MSE) 平均值: 0.528240089176261
KFold 交叉验证均方误差 (MSE) 标准差: 0.021981130310654018
重复K折交叉验证均方误差 (MSE): [0.53684797 0.52071965 0.52875513 0.49601516 0.54291573 0.53637433 0.50023284 0.51324893 0.53039931 0.57689184 0.49745799 0.49661918  0.5570885  0.58189853 0.53926041 0.58207253 0.50208433 0.51470742 0.51801812 0.48920829 0.54854349 0.53260114 0.53545147 0.51180857 0.51464129 0.51980227 0.49039059 0.56102021 0.53320332 0.53277193 0.5516802  0.52911446 0.50193851 0.51639016 0.53991329 0.52938127 0.50719802 0.52158904 0.51207916 0.58018524 0.51133768 0.55411549 0.55073469 0.53996994 0.49762255 0.50685958 0.54146286 0.51292171 0.59362882 0.52008519]
重复K折交叉验证均方误差 (MSE) 平均值: 0.5291851666822569
重复K折交叉验证均方误差 (MSE) 标准差: 0.02539043031146571

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值