Keras机器学习——回归基础:预测燃油效率

在回归(regression)问题中,我们的目的是预测出如价格或概率这样的连续值的输出。相对于分类(classification)问题,分类(classification)的目的是从多种的分类出选择出一个分类(如,指定一张包含苹果或橘子的图片,识别出图片中是此类水果)。

我们将使用经典的Auto MPG数据集,并整合了一个用来预测70年代末到80年代初的汽车燃油效率的模型。为了做到这一点,我们将为该模型提供许多那个时期的汽车描述。这个描述包含:气缸数,排量,马力以及重量。

# 使用 seaborn 绘制矩阵图 (pairplot)
!pip install -q seaborn
from __future__ import absolute_import, division, print_function, unicode_literals

import pathlib

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

一、自动MPG数据集,该数据集可以从UCI机器学习库中获取。

dataset_path = keras.utils.get_file("auto-mpg.data", "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")

使用pandas导入数据集:

column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin']
raw_dataset = pd.read_csv(dataset_path, names=column_names,
                      na_values = "?", comment='\t',
                      sep=" ", skipinitialspace=True)

dataset = raw_dataset.copy()
dataset.tail()

在这里插入图片描述
二、数据清洗

dataset.isna().sum()

在这里插入图片描述
为了保证这个初始示例的简单性,删除这些行:

dataset = dataset.dropna()

“Origin” 列实际代表分类,而不仅仅是一个数字。所以把它转换为独热码(one-hot):

origin = dataset.pop('Origin')
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
dataset.tail()

在这里插入图片描述
三、初步训练数据集和测试数据集

现在需要将数据集分解为一个训练数据集和一个测试数据集。
我们最后将使用测试数据集对模型进行评估。

train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

四、数据检查:快速查看训练集中几对列的联合分布。

sns.pairplot(train_dataset[["MPG", "Cylinders", "Displacement", "Weight"]], diag_kind="kde")

在这里插入图片描述
也可以查看总体的数据统计:

train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()
train_stats

在这里插入图片描述
五、从标签中分离特征

这个标签是你使用训练模型进行预测的值。

train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')

六、数据规范化

再次审视下上面的train_stats部分,并注意每个特征的范围有什么不同。

使用不同的尺度和范围对特征归一化是好的实践。虽然模型可能在没有特征归一化的情况下收敛,它会导致模型训练更加复杂,并会生成的模型依赖输入所使用的单位选择。

注意:尽管我们仅仅从训练集中有意生成这些统计数据,但是这些统计信息也会用于归一化的测试数据集。我们需要这样做,将测试数据集加入到已经已经训练过的模型相同的分布中。

def norm(x):
  return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)

我们将会使用这个已经归一化的数据来训练模型。

七、建立模型

让我们来构建我们自己的模型。这里,我们将会使用一个“顺序”模型,其中包含两个紧密相连的隐藏层,以及返回替换,连续值得输出层。模型的构建步骤包含于一个名叫’ build_model’的函数中,稍后我们将会创建第二个模型。两个密集连接的隐藏层。

def build_model():
  model = keras.Sequential([
    layers.Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
    layers.Dense(64, activation='relu'),
    layers.Dense(1)
  ])

  optimizer = tf.keras.optimizers.RMSprop(0.001)

  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae', 'mse'])
  return model
model = build_model()

八、检查模型:使用.summary方法来打印该模型的简单描述。

model.summary()

现在试用下这个模型。从训练数据中批量获取’10’条示例重复这些示例调用model.predict。

example_batch = normed_train_data[:10]
example_result = model.predict(example_batch)
example_result

九、训练模型

对模型进行1000个周期的训练,并在history对象中记录训练和验证的准确性。

# 通过为每个完成的时期打印一个点来显示训练进度
class PrintDot(keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs):
    if epoch % 100 == 0: print('')
    print('.', end='')

EPOCHS = 1000

history = model.fit(
  normed_train_data, train_labels,
  epochs=EPOCHS, validation_split = 0.2, verbose=0,
  callbacks=[PrintDot()])

使用history对象中存储的统计信息可视化模型的训练进度。

hist = pd.DataFrame(history.history)
hist['epoch'] = history.epoch
hist.tail()

在这里插入图片描述

def plot_history(history):
  hist = pd.DataFrame(history.history)
  hist['epoch'] = history.epoch

  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Abs Error [MPG]')
  plt.plot(hist['epoch'], hist['mae'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mae'],
           label = 'Val Error')
  plt.ylim([0,5])
  plt.legend()

  plt.figure()
  plt.xlabel('Epoch')
  plt.ylabel('Mean Square Error [$MPG^2$]')
  plt.plot(hist['epoch'], hist['mse'],
           label='Train Error')
  plt.plot(hist['epoch'], hist['val_mse'],
           label = 'Val Error')
  plt.ylim([0,20])
  plt.legend()
  plt.show()
plot_history(history)

在这里插入图片描述
该图表显示在约100个历元之后误差非但没有改进,反而出现恶化。我们让更新model.fit调用,当验证值没有提高上是自动停止训练。我们将使用一个EarlyStopping回调来测试每个历元的训练条件。如果经过一定数量的时代后没有改进,则自动停止训练。

十、做预测

最后,使用测试集中的数据预测MPG值:

test_predictions = model.predict(normed_test_data).flatten()

plt.scatter(test_labels, test_predictions)
plt.xlabel('True Values [MPG]')
plt.ylabel('Predictions [MPG]')
plt.axis('equal')
plt.axis('square')
plt.xlim([0,plt.xlim()[1]])
plt.ylim([0,plt.ylim()[1]])
_ = plt.plot([-100, 100], [-100, 100])

在这里插入图片描述
这看起来我们的模型预测得相当好。我们来看下误差分布。

error = test_predictions - test_labels
plt.hist(error, bins = 25)
plt.xlabel("Prediction Error [M

在这里插入图片描述

它不是完全的高斯分布,但我们可以预期出,这是因为样本的数量很小所导致的。

原创文章 22 获赞 4 访问量 784

猜你喜欢

转载自blog.csdn.net/weixin_42224055/article/details/105774187