为新数据集开发神经网络预测模型可能具有挑战性。
一种方法是首先检查数据集并构思可能适用的模型,然后探索简单模型在数据集上的学习动态,最后使用健壮的测试框架开发和调整模型以适应数据集。
这个过程可以用于开发有效的神经网络模型,用于分类和回归预测建模问题。
在本教程中,您将了解如何为瑞典汽车保险回归数据集开发多层感知器(MLP)神经网络模型。
完成本教程后,您将了解:
- 如何加载和总结瑞典汽车保险数据集,并利用结果建议使用的数据准备和模型配置。
- 如何探索简单MLP模型和数据集上的数据转换的学习动态。
- 如何开发稳健的模型性能估计,调整模型性能,并对新数据进行预测。
让我们开始吧。

如何开发用于预测汽车保险赔付的神经网络
照片作者:Dimitry B.,部分权利保留。
教程概述
本教程分为四个部分;它们是
- 汽车保险回归数据集
- 第一个MLP和学习动态
- 评估和调整MLP模型
- 最终模型及预测
汽车保险回归数据集
第一步是定义和探索数据集。
我们将使用“汽车保险”标准回归数据集。
该数据集描述了瑞典的汽车保险。有一个输入变量,即索赔次数,目标变量是索赔总支付金额(以瑞典克朗为单位)。目标是根据索赔次数预测总支付金额。
你可以在此处了解更多关于此数据集的信息:
您可以在下面看到数据集的前几行。
1 2 3 4 5 6 |
108,392.5 19,46.2 13,15.7 124,422.2 40,119.4 ... |
我们可以看到这些值是数值型的,并且可能从几十到几百不等。这表明在用神经网络建模时,对数据进行某种类型的缩放是合适的。
我们可以直接从 URL 将数据集加载为 pandas DataFrame;例如:
1 2 3 4 5 6 7 8 |
# 加载数据集并总结其形状 from pandas import read_csv # 定义数据集位置 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' # 加载数据集 df = read_csv(url, header=None) # 总结形状 print(df.shape) |
运行示例将直接从 URL 加载数据集并报告数据集的形状。
在这种情况下,我们可以确认该数据集有两个变量(一个输入和一个输出),并且数据集包含63行数据。
这对于神经网络来说行数不多,表明应该使用小型网络,可能带有正则化。
鉴于这会比训练/测试分割提供更可靠的模型性能估计,并且单个模型只需要几秒钟即可完成训练,而不是在大型数据集上花费数小时或数天,因此使用k折交叉验证是个好主意。
1 |
(63, 2) |
接下来,我们可以通过查看摘要统计信息和数据图来进一步了解数据集。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 显示数据集的汇总统计和图 from pandas import read_csv from matplotlib import pyplot # 定义数据集位置 url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' # 加载数据集 df = read_csv(url, header=None) # 显示摘要统计信息 print(df.describe()) # plot histograms df.hist() pyplot.show() |
运行示例首先加载数据,然后打印每个变量的汇总统计信息。
我们可以看到每个变量的平均值都在几十,取值范围从0到几百。这证实了对数据进行缩放可能是一个好主意。
1 2 3 4 5 6 7 8 9 |
0 1 count 63.000000 63.000000 mean 22.904762 98.187302 std 23.351946 87.327553 min 0.000000 0.000000 25% 7.500000 38.850000 50% 14.000000 73.400000 75% 29.000000 140.000000 max 124.000000 422.200000 |
然后为每个变量创建直方图。
我们可以看到每个变量的分布相似。它看起来像一个偏态高斯分布或指数分布。
我们可能需要对每个变量使用幂转换,以便使概率分布不那么偏斜,这可能会提高模型性能。

汽车保险回归数据集的直方图
现在我们熟悉了数据集,让我们探索一下如何开发神经网络。
第一个MLP和学习动态
我们将使用 TensorFlow 为数据集开发多层感知机 (MLP) 模型。
我们无法知道什么模型架构或学习超参数最适合这个数据集,因此我们必须进行实验和探索,找出有效的方法。
鉴于数据集较小,使用较小的批量大小可能是个好主意,例如8或16行。对于大多数数据集,使用Adam版本的随机梯度下降是一个不错的选择,因为它会自动调整学习率并且效果很好。
在我们认真评估模型之前,最好回顾学习动态并调整模型架构和学习配置,直到我们获得稳定的学习动态,然后再考虑如何充分利用模型。
我们可以通过使用简单的训练/测试分割数据并查看学习曲线的图来做到这一点。这将帮助我们了解我们是在过拟合还是欠拟合;然后我们可以相应地调整配置。
首先,我们可以将数据集分割为输入和输出变量,然后分割为67/33的训练集和测试集。
1 2 3 4 5 |
... # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) |
接下来,我们可以定义一个最小的MLP模型。在这种情况下,我们将使用一个包含10个节点的隐藏层和一个输出层(任意选择)。我们将在隐藏层中使用ReLU激活函数和“he_normal”权重初始化,因为它们结合起来是很好的实践。
模型的输出是线性激活(无激活),我们将最小化均方误差(MSE)损失。
1 2 3 4 5 6 7 8 9 |
... # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') |
我们将为模型训练100个时期(任意选择),批量大小为8,因为这是一个小型数据集。
我们正在用原始数据训练模型,我们认为这可能是一个坏主意,但这是一个重要的起点。
1 2 3 |
... # 拟合模型 history = model.fit(X_train, y_train, epochs=100, batch_size=8, verbose=0, validation_data=(X_test,y_test)) |
训练结束后,我们将评估模型在测试集上的性能,并将性能报告为平均绝对误差(MAE),我通常更喜欢它而不是MSE或RMSE。
1 2 3 4 5 6 |
... # 预测测试集 yhat = model.predict(X_test) # 评估预测 score = mean_absolute_error(y_test, yhat) print('MAE: %.3f' % score) |
最后,我们将绘制训练期间训练集和测试集上MSE损失的学习曲线。
1 2 3 4 5 6 7 8 9 |
... # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('均方误差') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
将所有这些结合起来,下面列出了在汽车保险数据集上评估我们第一个MLP的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# 拟合一个简单的mlp模型并查看学习曲线 from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 history = model.fit(X_train, y_train, epochs=100, batch_size=8, verbose=0, validation_data=(X_test,y_test)) # 预测测试集 yhat = model.predict(X_test) # 评估预测 score = mean_absolute_error(y_test, yhat) print('MAE: %.3f' % score) # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('均方误差') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
运行示例首先在训练数据集上拟合模型,然后报告测试数据集上的MAE。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型达到了大约33.2的MAE,这是一个不错的性能基准,我们可能会有所改进。
1 |
MAE: 33.233 |
然后绘制训练集和测试集上MSE的学习曲线。
我们可以看到模型拟合良好并且收敛得很好。模型的配置是一个很好的起点。

简单MLP在汽车保险数据集上的学习曲线
到目前为止,学习动态都很好,MAE只是一个粗略的估计,不应依赖。
我们可以稍微增加模型的容量,并期望获得相似的学习动态。例如,我们可以添加一个包含八个节点(任意选择)的第二个隐藏层,并将训练时期数加倍到200。
1 2 3 4 5 6 7 8 9 10 |
... # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 history = model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0, validation_data=(X_test,y_test)) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# 拟合一个更深的mlp模型并查看学习曲线 from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 history = model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0, validation_data=(X_test,y_test)) # 预测测试集 yhat = model.predict(X_test) # 评估预测 score = mean_absolute_error(y_test, yhat) print('MAE: %.3f' % score) # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('均方误差') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
运行示例首先在训练数据集上拟合模型,然后报告测试数据集上的MAE。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到MAE有轻微的改进,达到了约27.9,尽管训练/测试分割的高方差意味着此评估不可靠。
1 |
MAE: 27.939 |
然后绘制了MSE训练集和测试集上的学习曲线。我们可以看到,正如预期的那样,模型实现了良好的拟合,并在合理数量的迭代中收敛。

更深的MLP在汽车保险数据集上的学习曲线
最后,我们可以尝试转换数据,看看这对学习动态有何影响。
在这种情况下,我们将使用幂转换使数据分布不那么偏斜。这还将自动标准化变量,使它们具有零均值和单位标准差——这是使用神经网络建模的好习惯。
首先,我们必须确保目标变量是二维数组。
1 2 3 |
... # 确保目标变量是2D数组 y_train, y_test = y_train.reshape((len(y_train),1)), y_test.reshape((len(y_test),1)) |
接下来,我们可以对输入和目标变量应用PowerTransformer。
这可以通过首先在训练数据上拟合转换,然后转换训练集和测试集来实现。
此过程分别应用于输入和输出变量,以避免数据泄露。
1 2 3 4 5 6 7 8 9 10 11 |
... # 对输入数据进行幂转换 pt1 = PowerTransformer() pt1.fit(X_train) X_train = pt1.transform(X_train) X_test = pt1.transform(X_test) # 对输出数据进行幂转换 pt2 = PowerTransformer() pt2.fit(y_train) y_train = pt2.transform(y_train) y_test = pt2.transform(y_test) |
然后使用这些数据来拟合模型。
然后,可以将转换应用于模型的预测以及测试集中的预期目标值,然后我们可以按之前的正确比例计算MAE。
1 2 3 4 |
... # 对目标变量进行逆转换 y_test = pt2.inverse_transform(y_test) yhat = pt2.inverse_transform(yhat) |
将这些结合起来,下面列出了使用数据转换拟合和评估MLP并创建模型学习曲线的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# 使用数据转换拟合MLP模型并查看学习曲线 from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error from sklearn.preprocessing import PowerTransformer from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 分割为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33) # 确保目标变量是2D数组 y_train, y_test = y_train.reshape((len(y_train),1)), y_test.reshape((len(y_test),1)) # 对输入数据进行幂转换 pt1 = PowerTransformer() pt1.fit(X_train) X_train = pt1.transform(X_train) X_test = pt1.transform(X_test) # 对输出数据进行幂转换 pt2 = PowerTransformer() pt2.fit(y_train) y_train = pt2.transform(y_train) y_test = pt2.transform(y_test) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 history = model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0, validation_data=(X_test,y_test)) # 预测测试集 yhat = model.predict(X_test) # 对目标变量进行逆转换 y_test = pt2.inverse_transform(y_test) yhat = pt2.inverse_transform(yhat) # 评估预测 score = mean_absolute_error(y_test, yhat) print('MAE: %.3f' % score) # 绘制学习曲线 pyplot.title('学习曲线') pyplot.xlabel('Epoch') pyplot.ylabel('均方误差') pyplot.plot(history.history['loss'], label='train') pyplot.plot(history.history['val_loss'], label='val') pyplot.legend() pyplot.show() |
运行示例首先在训练数据集上拟合模型,然后报告测试数据集上的MAE。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,模型实现了合理的MAE分数,尽管比之前报告的性能要差。我们暂时忽略模型性能。
1 |
MAE: 34.320 |
绘制了学习曲线的折线图,显示模型实现了合理的拟合,并且有足够的时间收敛。

在汽车保险数据集上使用更深MLP和数据转换的学习曲线
现在我们对带有和不带有数据转换的简单MLP模型的学习动态有了一定的了解,我们可以着手评估模型的性能并调整模型的配置。
评估和调整MLP模型
k折交叉验证过程可以提供更可靠的MLP性能估计,尽管它可能非常慢。
这是因为必须拟合和评估k个模型。对于像汽车保险数据集这样的小型数据集,这不是问题。
我们可以使用KFold类来创建分割并手动枚举每个折叠,拟合模型,评估它,然后在过程结束时报告评估分数的平均值。
1 2 3 4 5 6 7 8 9 10 |
# 准备交叉验证 kfold = KFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 拟合和评估模型... ... ... # 汇总所有分数 print('Mean MAE: %.3f (%.3f)' % (mean(scores), std(scores))) |
我们可以使用此框架,通过一系列不同的数据准备、模型架构和学习配置,为MLP模型开发可靠的性能估计。
在上次使用k折交叉验证来估计性能之前,首先了解模型在数据集上的学习动态是很重要的。如果我们直接开始调整模型,我们可能会获得好结果,但如果没有,我们可能不知道原因,例如模型过拟合或欠拟合。
如果我们再次对模型进行重大更改,最好确认模型收敛得当。
下面列出了使用此框架评估上一节中基础 MLP 模型的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# 汽车保险回归数据集的基础模型的k折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import KFold from sklearn.metrics import mean_absolute_error from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 准备交叉验证 kfold = KFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit(X_train, y_train, epochs=100, batch_size=8, verbose=0) # 预测测试集 yhat = model.predict(X_test) # 评估预测结果 score = mean_absolute_error(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean MAE: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行示例会报告评估过程的每次迭代的模型性能,并在运行结束时报告MAE的平均值和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到MLP模型达到了大约38.913的MAE。
我们将使用此结果作为基准,看看我们是否能获得更好的性能。
1 2 3 4 5 6 7 8 9 10 11 |
>27.314 >69.577 >20.891 >14.810 >13.412 >69.540 >25.612 >49.508 >35.769 >62.696 Mean MAE: 38.913 (21.056) |
首先,让我们尝试在原始数据集上评估一个更深的模型,看看它是否比基线模型表现更好。
1 2 3 4 5 6 7 8 9 10 |
... # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# 深度模型在汽车保险回归数据集上的k折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import KFold from sklearn.metrics import mean_absolute_error from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 准备交叉验证 kfold = KFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0) # 预测测试集 yhat = model.predict(X_test) # 评估预测结果 score = mean_absolute_error(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean MAE: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行会报告运行结束时MAE的平均值和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到MLP模型达到了大约35.384的MAE,这比基线模型(MAE约为38.913)略好。
1 |
Mean MAE: 35.384 (14.951) |
接下来,让我们尝试使用与上一节相同的模型,并对输入和目标变量进行幂转换。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# 具有数据转换的深度模型的k折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import KFold from sklearn.metrics import mean_absolute_error from sklearn.preprocessing import PowerTransformer from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 准备交叉验证 kfold = KFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确保目标是一个二维数组 y_train, y_test = y_train.reshape((len(y_train),1)), y_test.reshape((len(y_test),1)) # 准备输入数据 pt1 = PowerTransformer() pt1.fit(X_train) X_train = pt1.transform(X_train) X_test = pt1.transform(X_test) # 准备目标 pt2 = PowerTransformer() pt2.fit(y_train) y_train = pt2.transform(y_train) y_test = pt2.transform(y_test) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0) # 预测测试集 yhat = model.predict(X_test) # 反向变换 y_test = pt2.inverse_transform(y_test) yhat = pt2.inverse_transform(yhat) # 评估预测结果 score = mean_absolute_error(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean MAE: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行会报告运行结束时MAE的平均值和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到MLP模型实现了约37.371的MAE,这比基线模型要好,但不如更深层的基线模型。
也许这种变换并没有像我们最初设想的那样有用。
1 |
平均MAE:37.371 (29.326) |
另一种变换方法是标准化输入和目标变量。
这意味着将每个变量的值缩放到[0, 1]的范围。我们可以使用MinMaxScaler来实现这一点;例如
1 2 3 4 5 6 7 8 9 10 11 |
... # 准备输入数据 pt1 = MinMaxScaler() pt1.fit(X_train) X_train = pt1.transform(X_train) X_test = pt1.transform(X_test) # 准备目标 pt2 = MinMaxScaler() pt2.fit(y_train) y_train = pt2.transform(y_train) y_test = pt2.transform(y_test) |
将这些整合在一起,使用数据标准化评估更深层MLP模型的完整示例列于下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# 使用标准化变换对更深层模型进行k折交叉验证 from numpy import mean from numpy import std from pandas import read_csv from sklearn.model_selection import KFold from sklearn.metrics import mean_absolute_error 从 sklearn.预处理 导入 MinMaxScaler from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense from matplotlib import pyplot # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 准备交叉验证 kfold = KFold(10) # 枚举划分 scores = list() for train_ix, test_ix in kfold.split(X, y): # 分割数据 X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix] # 确保目标是一个二维数组 y_train, y_test = y_train.reshape((len(y_train),1)), y_test.reshape((len(y_test),1)) # 准备输入数据 pt1 = MinMaxScaler() pt1.fit(X_train) X_train = pt1.transform(X_train) X_test = pt1.transform(X_test) # 准备目标 pt2 = MinMaxScaler() pt2.fit(y_train) y_train = pt2.transform(y_train) y_test = pt2.transform(y_test) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit(X_train, y_train, epochs=200, batch_size=8, verbose=0) # 预测测试集 yhat = model.predict(X_test) # 反向变换 y_test = pt2.inverse_transform(y_test) yhat = pt2.inverse_transform(yhat) # 评估预测结果 score = mean_absolute_error(y_test, yhat) print('>%.3f' % score) scores.append(score) # 汇总所有分数 print('Mean MAE: %.3f (%.3f)' % (mean(scores), std(scores))) |
运行会报告运行结束时MAE的平均值和标准差。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到MLP模型实现了约30.388的MAE,这比我们迄今为止尝试过的任何其他配置都要好。
1 |
平均MAE:30.388 (14.258) |
我们可以继续测试模型架构(更多或更少的节点或层)、学习超参数(更多或更少的批次)以及数据变换的替代配置。
我将此作为一项练习;请告知我您的发现。您能获得更好的结果吗?
在下面的评论中发布您的结果,我很想看看您得到了什么。
接下来,我们看看如何拟合最终模型并使用它来做出预测。
最终模型及预测
选择模型配置后,我们可以使用所有可用数据训练最终模型,并用它来对新数据进行预测。
在这种情况下,我们将使用带有数据标准化的更深层模型作为我们的最终模型。
这意味着如果我们想将模型保存到文件,我们就必须保存模型本身(用于进行预测)、用于输入数据的变换(用于新的输入数据)以及用于目标变量的变换(用于新的预测)。
我们可以像以前一样准备数据并拟合模型,但这次是在整个数据集上,而不是在一个训练子集上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
... # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保目标是一个二维数组 y = y.reshape((len(y),1)) # 准备输入数据 pt1 = MinMaxScaler() pt1.fit(X) X = pt1.transform(X) # 准备目标 pt2 = MinMaxScaler() pt2.fit(y) y = pt2.transform(y) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') |
然后,我们可以使用此模型对新数据进行预测。
首先,我们可以定义一行新数据,对于这个数据集来说,它只有一个变量。
1 2 3 |
... # 定义一行新数据 row = [13] |
然后我们可以转换这些新数据,使其准备好作为模型的输入。
1 2 3 |
... # 转换输入数据 X_new = pt1.transform([row]) |
然后我们可以进行预测。
1 2 3 |
... # 进行预测 yhat = model.predict(X_new) |
然后对预测进行反向变换,以便我们可以使用或在正确的尺度上解释结果。
1 2 3 |
... # 对预测进行反向变换 yhat = pt2.inverse_transform(yhat) |
在这种情况下,我们将只报告预测结果。
1 2 3 |
... # 报告预测结果 print('f(%s) = %.3f' % (row, yhat[0])) |
将所有这些整合在一起,用于为汽车保险数据集拟合最终模型并使用它对新数据进行预测的完整示例列于下文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 拟合最终模型并对新数据进行预测。 from pandas import read_csv from sklearn.model_selection import KFold from sklearn.metrics import mean_absolute_error 从 sklearn.预处理 导入 MinMaxScaler from tensorflow.keras import Sequential from tensorflow.keras.layers import Dense # 加载数据集 path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/auto-insurance.csv' df = read_csv(path, header=None) # 分割成输入和输出列 X, y = df.values[:, :-1], df.values[:, -1] # 确保目标是一个二维数组 y = y.reshape((len(y),1)) # 准备输入数据 pt1 = MinMaxScaler() pt1.fit(X) X = pt1.transform(X) # 准备目标 pt2 = MinMaxScaler() pt2.fit(y) y = pt2.transform(y) # 确定输入特征的数量 n_features = X.shape[1] # 定义模型 model = Sequential() model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,))) model.add(Dense(8, activation='relu', kernel_initializer='he_normal')) model.add(Dense(1)) # 编译模型 model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit(X, y, epochs=200, batch_size=8, verbose=0) # 定义一行新数据 row = [13] # 转换输入数据 X_new = pt1.transform([row]) # 进行预测 yhat = model.predict(X_new) # 对预测进行反向变换 yhat = pt2.inverse_transform(yhat) # 报告预测结果 print('f(%s) = %.3f' % (row, yhat[0])) |
运行示例会将模型拟合到整个数据集,并为新数据的单行进行预测。
注意:由于算法或评估过程的随机性,或数值精度的差异,您的结果可能有所不同。可以考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到输入13导致输出为62(千瑞典克朗)。
1 |
f([13]) = 62.595 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
教程
总结
在本教程中,您将了解如何为瑞典汽车保险回归数据集开发多层感知器神经网络模型。
具体来说,你学到了:
- 如何加载和总结瑞典汽车保险数据集,并利用结果建议使用的数据准备和模型配置。
- 如何探索简单MLP模型和数据集上的数据转换的学习动态。
- 如何开发模型性能的稳健估计,调整模型性能并对新数据进行预测。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
杰森,这篇文章写得太棒了,感谢您的分享。祝您一切顺利!
谢谢!
哇,非常感谢你,杰森。
不客气。
我真的很需要这个!我曾经(大约一年前)在学校项目中使用过您的教程,但现在由于工作和处理一些有限的数据,这给了我一个很好的起点。非常感谢您的内容。
您在文章中提到,您更喜欢MAE而不是MSE或RSME?为什么呢?
很高兴听到这个消息。
好问题,MAE更容易理解。另外,请看这篇关于回归指标的文章。
https://machinelearning.org.cn/regression-metrics-for-machine-learning/
感谢提供信息
不客气!
亲爱的 Jason,
这是一个非常简单且最终有用的关于构建DL模型的流程的解释,非常感谢您的教程,它对像我这样的学习者来说非常有启发性。
使用PowerTransformer进行预处理对我来说是全新的。当数据不是高斯分布时,是否有关于预处理方面的教程?我认为大多数现实世界的数据都是这样的。
非常感谢您的辛勤工作……谢谢……
是的,这个例子将展示如何改变非高斯数据的分布。
https://machinelearning.org.cn/quantile-transforms-for-machine-learning/
杰森,您好,文章写得很棒。我尝试在我的数据集上应用Kfold(10)来计算MSE。在最后一次运行时,结果偏差太大,有什么原因吗?
>0.231
>0.192
>0.212
>0.198
>0.246
>0.230
>0.317
>0.298
>0.635
>7.583
干得好!
也许模型在那次运行中表现非常糟糕。
您好,文章写得非常好,谢谢。我有一个问题。在最终模型并进行预测之前,我们已经确定了使用哪个模型和缩放器,并且我们已经训练和测试了模型。这意味着输入变量的最佳可能参数已经由模型“计算”出来。我如何找到参数的值,以及它如何在最终模型和进行预测部分中使用?
我说的参数是指权重。
您可以从模型中检索权重,这取决于模型。
对于神经网络,您可以调用层或模型本身的get_weights。
谢谢!
也许这会有所帮助:输入值是我们希望用来制作预测的基础的领域中的原始数据。它们被输入到模型中,然后进行预测。