在机器学习领域,经常遇到分类和回归问题。分类问题的目标是将结果划分为有限的不同类别,而回归问题则是预测一个范围无限的实数。例如,可以根据房屋的卧室数量和楼层来预测房价,或者根据产品规格来预测产品评级等。
神经网络是计算机视觉和自然语言处理领域中最重要的算法之一。本文将探讨如何将神经网络应用于表格数据的回归任务,并使用TensorFlow和Keras深度学习库来构建和训练神经网络。
用于训练模型的数据集是“Auto MPG”数据集。这个数据集包含了1980年代和90年代常用汽车的不同特征,如气缸数量、马力、汽车重量等。利用这些特征,需要预测汽车的每加仑英里数(MPG),因此这是一个多变量回归任务。更多关于数据集的信息可以查看。
首先,需要导入所需的库并下载数据集。以下是导入库的代码示例:
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import Sequential
from tensorflow.keras import optimizers
接下来,使用pandas库下载并解析数据集到数据框中。
url = "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data"
column_names = ["MPG", "Cylinders", "Displacement", "Horsepower", "Weight",
"Acceleration", "Model Year", "Origin"]
df = pd.read_csv(url, names=column_names, sep=" ",
comment="t", na_values="?", skipinitialspace=True)
直接使用pandas的read_csv方法下载数据集并解析到数据框中。可以通过查看数据框的头部来获取更多详细信息。
在将数据输入模型之前,需要对数据进行预处理。首先,需要检查数据中的空值,因为处理空值对于模型的学习至关重要。如果数据包含空值,模型将无法学习,导致结果为空。
dataset = df.copy()
dataset.isna().sum()
在‘Horsepower’列中遇到了一些空值,可以使用Pandas库轻松处理这些空值。可以使用dropna()方法删除所有包含空值的行,或者用整个列的平均值填充这些空值。将使用fillna()方法填充空值。
dataset['Horsepower'].fillna(dataset['Horsepower'].mean(), inplace=True)
dataset.isna().sum()
现在可以看到没有任何列包含空值。根据数据集,‘Origin’列不是数值型而是分类的,即每个数字代表每个国家。因此,将使用pandas的get_dummies()方法对这一列进行编码。
dataset['Origin'].value_counts()
dataset['Origin'] = dataset['Origin'].map({1: 'USA', 2: 'Europe', 3: 'Japan'})
dataset = pd.get_dummies(dataset, columns=['Origin'], prefix='', prefix_sep='')
在上面的输出中,可以看到单个‘Origin’列被替换为三个列,列名为国家名称,1或0代表原产国。
现在,将数据集分割为训练集和测试/验证集。这对于测试模型的有效性非常有用,即模型在未见过的数据上的表现如何。
train_dataset = dataset.sample(frac=0.8, random_state=0)
test_dataset = dataset.drop(train_dataset.index)
接下来,将标签和特征分开。
train_features = train_dataset.drop(["MPG"], axis=1)
test_features = test_dataset.drop(["MPG"], axis=1)
train_labels = train_dataset["MPG"]
test_labels = test_dataset["MPG"]
可以使用pandas的describe()函数来查看数据的一些基本统计信息。
train_dataset.describe().transpose()
现在可以进行下一步数据预处理:归一化。数据归一化是将数据转换为模型可以轻松处理的格式的基本预处理步骤之一。在这一步中,将数据缩放,使得均值为0,标准差为1。将使用sci-kit learn库来完成这一步骤。
from sklearn.preprocessing import StandardScaler
feature_scaler = StandardScaler()
label_scaler = StandardScaler()
分别对训练数据进行拟合和转换,因为拟合将学习输入数据的数据表示,而转换将应用学习到的数据表示。通过这种方式,将能够避免查看测试数据的表示/统计信息。
feature_scaler.fit(train_features.values)
label_scaler.fit(train_labels.values.reshape(-1, 1))
train_features = feature_scaler.transform(train_features.values)
test_features = feature_scaler.transform(test_features.values)
train_labels = label_scaler.transform(train_labels.values.reshape(-1, 1))
test_labels = label_scaler.transform(test_labels.values.reshape(-1, 1))
现在使用Keras的Sequential API来创建模型。可以将所需的层堆叠到顺序模型中,然后定义所需的架构。现在为数据创建一个基本的全连接密集神经网络。
model = Sequential([
layers.Dense(32, activation='relu'),
layers.Dense(64, activation='relu'),
layers.Dense(1)
])
通过添加两个分别具有32和64个单元的密集层来定义顺序模型,两者都使用Rectified Linear Unit激活函数,即Relu。最后,添加一个具有1个神经元的密集层,代表输出维度,即一个单独的数字。现在通过指定损失函数和优化器来编译模型。
model.compile(optimizer="RMSProp",
loss="mean_squared_error")
对于模型,使用RMSProp优化器和均方误差损失函数。这些是模型的重要参数,因为优化器定义了如何改进模型,损失定义了需要改进的内容。
现在通过指定训练特征和标签来训练模型,进行100个周期的训练。还可以传递验证数据以定期检查模型的性能。
history = model.fit(epochs=100, x=train_features, y=train_labels,
validation_data=(test_features, test_labels), verbose=0)
由于指定了verbose=0,将不会为每个周期获得任何模型训练日志。可以使用模型历史记录来绘制模型在训练期间的表现。让为此定义一个函数。
def plot_loss(history):
plt.plot(history.history['loss'], label='loss')
plt.plot(history.history['val_loss'], label='val_loss')
plt.ylim([0,10])
plt.xlabel('Epoch')
plt.ylabel('Error (Loss)')
plt.legend()
plt.grid(True)
现在可以看到模型在训练期间已经能够实现最小的损失。这要归功于模型能够轻松检测数据集中的模式的全连接层。
最后,在测试数据集上评估模型。
model.evaluate(test_features, test_labels)
model.save("trained_model.h5")
saved_model = models.load_model('trained_model.h5')
results = saved_model.predict(test_features)
decoded_result = label_scaler.inverse_transform(results.reshape(-1,1))
print(decoded_result)