为新数据集开发神经网络预测模型可能具有挑战性。
一种方法是首先检查数据集并就哪些模型可能起作用提出想法,然后探索数据集上简单模型的学习动态,最后使用强大的测试工具为数据集开发和调整模型。
此过程可用于为分类和回归预测建模问题开发有效的神经网络模型。
在本教程中,您将了解如何为癌症生存二元分类数据集开发多层感知器神经网络模型。
完成本教程后,您将了解:
-
如何加载和总结癌症生存数据集并使用结果来建议要使用的数据准备和模型配置。
-
如何探索简单 MLP 模型在数据集上的学习动态。
-
如何对模型性能进行稳健的估计、调整模型性能并对新数据进行预测。
让我们开始吧。
教程概述
本教程分为4部分;他们是:
-
Haberman 乳腺癌生存数据集
-
神经网络学习动力学
-
稳健的模型评估
-
最终模型并进行预测
Haberman 乳腺癌生存数据集
第一步是定义和探索数据集。
我们将使用“ haberman ”标准二元分类数据集。
该数据集描述了乳腺癌患者数据,结果是患者存活率。特别是患者是否存活了五年或更长时间,或者患者是否没有存活下来。
这是用于研究不平衡分类的标准数据集。根据数据集描述,这些手术是在 1958 年至 1970 年间在芝加哥大学比林斯医院进行的。
数据集中有306个例子,输入变量有3个;他们是:
-
手术时患者的年龄。
-
操作的两位数年份。
-
检测到的“阳性腋窝淋巴结”数量,衡量癌症是否已经扩散。
因此,除了数据集中可用的内容之外,我们无法控制构成数据集的案例的选择或在这些案例中使用的特征。
尽管该数据集描述了乳腺癌患者的存活率,但鉴于数据集规模较小,而且数据是基于几十年前的乳腺癌诊断和操作这一事实,因此基于该数据集构建的任何模型预计都不会泛化。
注意:明确地说,我们不是“解决乳腺癌”。我们正在探索一个标准的分类数据集。
下面是数据集前 5 行的示例
30,64,1,1 30,62,3,1 30,65,0,1 31,59,2,1 31,65,4,1 ... |
您可以在此处了解有关数据集的更多信息:
-
哈伯曼生存数据集 (haberman.csv)
-
Haberman 生存数据集详细信息 (haberman.names)
我们可以直接从 URL 加载数据集作为 Pandas DataFrame;例如:
# load the haberman dataset and summarize the shape
from pandas import read_csv
# define the location of the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/haberman.csv'
# load the dataset
df = read_csv(url, header=None)
# summarize shape
print(df.shape)
运行示例直接从 URL 加载数据集并报告数据集的形状。
在这种情况下,我们可以确认数据集有 4 个变量(3 个输入和 1 个输出)并且数据集有 306 行数据。
对于神经网络而言,这并不是很多数据行,这表明可能具有正则化的小型网络将是合适的。
它还表明,使用 k 折交叉验证将是一个好主意,因为它可以提供比训练/测试拆分更可靠的模型性能估计,并且因为单个模型将在几秒钟内拟合,而不是几小时或几天最大的数据集。
接下来,我们可以通过查看汇总统计数据和数据图来了解有关数据集的更多信息。
# show summary statistics and plots of the haberman dataset
from pandas import read_csv
from matplotlib import pyplot
# load the dataset
df = read_csv(url, header=None)
# show summary statistics
print(df.describe())
# plot histograms
df.hist()
pyplot.show()
运行示例首先加载之前的数据,然后输出每个变量的汇总统计信息。
我们可以看到值随均值和标准差的不同而变化,在建模之前可能需要进行一些归一化或标准化。
0 1 2 3
count 306.000000 306.000000 306.000000 306.000000
mean 52.457516 62.852941 4.026144 1.264706
std 10.803452 3.249405 7.189654 0.441899
min 30.000000 58.000000 0.000000 1.000000
25% 44.000000 60.000000 0.000000 1.000000
50% 52.000000 63.000000 1.000000 1.000000
75% 60.750000 65.750000 4.000000 2.000000
max 83.000000 69.000000 52.000000 2.000000
然后为每个变量创建直方图。
我们可以看到,第一个变量可能具有类高斯分布,接下来的两个输入变量可能具有指数分布。
我们在每个变量上使用幂变换可能会有一些好处,以使概率分布不那么偏斜,这可能会提高模型性能。
Haberman 乳腺癌生存分类数据集的直方图
我们可以看到两个类之间的示例分布有些偏差,这意味着分类问题不平衡。它是不平衡的。
了解数据集的实际不平衡程度可能会有所帮助。
我们可以使用 Counter 对象来计算每个类中示例的数量,然后使用这些计数来总结分布。
下面列出了完整的示例。
# summarize the class ratio of the haberman dataset
from pandas import read_csv
from collections import Counter
# define the dataset column names
columns = ['age', 'year', 'nodes', 'class']
# load the csv file as a data frame
dataframe = read_csv(url, header=None, names=columns)
# summarize the class distribution
target = dataframe['class'].values
counter = Counter(target)
for k,v in counter.items():
per = v / len(target) * 100
print('Class=%d, Count=%d, Percentage=%.3f%%' % (k, v, per))
运行示例总结了数据集的类分布。
我们可以看到,生存类 1 的样本最多,为 225,约占数据集的 74%。我们可以看到非生存类 2 在 81 处的示例较少,约占数据集的 26%。
类分布偏斜,但没有严重失衡。
Class=1, Count=225, Percentage=73.529%
Class=2, Count=81, Percentage=26.471%
这很有帮助,因为如果我们使用分类准确率,那么任何达到低于约 73.5% 准确率的模型都不具备该数据集的技能。
现在我们熟悉了数据集,让我们探索如何开发神经网络模型。
神经网络学习动力学
我们将使用TensorFlow为数据集开发多层感知器 (MLP) 模型。
我们不知道学习超参数的模型架构对这个数据集是好的还是最好的,所以我们必须试验并发现什么是有效的。
鉴于数据集很小,小批量可能是一个好主意,例如 16 或 32 行。开始时使用 Adam 版本的随机梯度下降是一个好主意,因为它会自动调整学习率并且在大多数数据集上运行良好。
在我们认真评估模型之前,最好先回顾学习动态并调整模型架构和学习配置,直到我们拥有稳定的学习动态,然后再考虑充分利用模型。
我们可以通过使用简单的数据训练/测试分割和学习曲线图来做到这一点。这将帮助我们了解我们是过度学习还是学习不足;然后我们可以相应地调整配置。
首先,我们必须确保所有输入变量都是浮点值,并将目标标签编码为整数值 0 和 1。
# ensure all data are floating point values
X = X.astype('float32')
# encode strings to integer
y = LabelEncoder().fit_transform(y)
接下来,我们可以将数据集拆分为输入和输出变量,然后拆分为 67/33 的训练集和测试集。
我们必须确保分割按类别分层,确保训练集和测试集具有与主数据集相同的类别标签分布。
...
# split into input and output columns
X, y = df.values[:, :-1], df.values[:, -1]
# split into train and test datasets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, stratify=y, random_state=3)
我们可以定义一个最小的 MLP 模型。在这种情况下,我们将使用一个具有 10 个节点的隐藏层和一个输出层(任意选择)。我们将使用隐藏层中的ReLU 激活函数和“ he_normal ”权重初始化,它们一起是一个很好的做法。
模型的输出是用于二元分类的 sigmoid 激活,我们将最小化二元交叉熵损失。
...
# determine the number of input features
n_features = X.shape[1]
# define model
model = Sequential()
model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,)))
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy')
我们将模型拟合 200 个训练时期(任意选择),批量大小为 16,因为它是一个小数据集。
我们正在根据原始数据拟合模型,我们认为这可能是个好主意,但这是一个重要的起点。
...
# fit the model
history = model.fit(X_train, y_train, epochs=200, batch_size=16, verbose=0, validation_data=(X_test,y_test))
在训练结束时,我们将评估模型在测试数据集上的性能,并将性能报告为分类准确率。
..
# predict test set
yhat = model.predict_classes(X_test)
# evaluate predictions
score = accuracy_score(y_test, yhat)
print('Accuracy: %.3f' % score)
最后,我们将在训练期间绘制训练集和测试集上交叉熵损失的学习曲线。
..
# plot learning curves
pyplot.title('Learning Curves')
pyplot.xlabel('Epoch')
pyplot.ylabel('Cross Entropy')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='val')
pyplot.legend()
pyplot.show()
将所有这些结合在一起,下面列出了在癌症生存数据集上评估我们的第一个 MLP 的完整示例。
# fit a simple mlp model on the haberman and review learning curves
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from matplotlib import pyplot
df = read_csv(path, header=None)
# split into input and output columns
X, y = df.values[:, :-1], df.values[:, -1]
# ensure all data are floating point values
X = X.astype('float32')
# encode strings to integer
y = LabelEncoder().fit_transform(y)
# split into train and test datasets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, stratify=y, random_state=3)
# determine the number of input features
n_features = X.shape[1]
# define model
model = Sequential()
model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,)))
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy')
# fit the model
history = model.fit(X_train, y_train, epochs=200, batch_size=16, verbose=0, validation_data=(X_test,y_test))
# predict test set
yhat = model.predict_classes(X_test)
# evaluate predictions
score = accuracy_score(y_test, yhat)
print('Accuracy: %.3f' % score)
# plot learning curves
pyplot.title('Learning Curves')
pyplot.xlabel('Epoch')
pyplot.ylabel('Cross Entropy')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='val')
pyplot.legend()
pyplot.show()
运行示例首先在训练数据集上拟合模型,然后在测试数据集上报告分类准确率。
在这种情况下,我们可以看到该模型的性能优于非技能模型,因为准确度高于约 73.5%。
然后创建训练集和测试集上的损失线图。
我们可以看到模型很快在数据集上找到了很好的拟合,并且没有出现过拟合或欠拟合的情况。
简单多层感知器在癌症生存数据集上的学习曲线
现在我们对数据集上的简单 MLP 模型的学习动态有了一些了解,我们可以考虑对数据集上的模型性能进行更稳健的评估。
稳健的模型评估
k 折交叉验证过程可以提供更可靠的 MLP 性能估计,尽管它可能非常慢。
这是因为必须拟合和评估 k 个模型。当数据集规模较小时,这不是问题,例如癌症生存数据集。
我们可以使用StratifiedKFold类并手动枚举每个折叠,拟合模型,评估它,然后在程序结束时报告评估分数的平均值。
...
# prepare cross validation
kfold = KFold(10)
# enumerate splits
scores = list()
for train_ix, test_ix in kfold.split(X, y):
# fit and evaluate the model...
...
...
# summarize all scores
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
我们可以使用这个框架,通过我们的基本配置,甚至使用一系列不同的数据准备、模型架构和学习配置,对 MLP 模型性能进行可靠的估计。
重要的是,在使用 k 折交叉验证来估计性能之前,我们首先了解了上一节中模型在数据集上的学习动态。如果我们直接开始调整模型,我们可能会得到很好的结果,但如果不是,我们可能不知道为什么,例如模型过度拟合或拟合不足。
如果我们再次对模型进行大量更改,最好返回并确认模型是否正确收敛。
下面列出了该框架的完整示例,用于评估上一节中的基本 MLP 模型。
# k-fold cross-validation of base model for the haberman dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import StratifiedKFold
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from matplotlib import pyplot
# load the dataset
path = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/haberman.csv'
df = read_csv(path, header=None)
# split into input and output columns
X, y = df.values[:, :-1], df.values[:, -1]
# ensure all data are floating point values
X = X.astype('float32')
# encode strings to integer
y = LabelEncoder().fit_transform(y)
# prepare cross validation
kfold = StratifiedKFold(10, random_state=1)
# enumerate splits
scores = list()
for train_ix, test_ix in kfold.split(X, y):
# split data
X_train, X_test, y_train, y_test = X[train_ix], X[test_ix], y[train_ix], y[test_ix]
# determine the number of input features
n_features = X.shape[1]
# define model
model = Sequential()
model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,)))
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy')
# fit the model
model.fit(X_train, y_train, epochs=200, batch_size=16, verbose=0)
# predict test set
yhat = model.predict_classes(X_test)
# evaluate predictions
score = accuracy_score(y_test, yhat)
print('>%.3f' % score)
scores.append(score)
# summarize all scores
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行示例报告评估程序的每次迭代的模型性能,并报告运行结束时分类准确度的均值和标准差。
在这种情况下,我们可以看到 MLP 模型实现了大约 75.2% 的平均准确率,这与我们在上一节中的粗略估计非常接近。
这证实了我们的预期,即基本模型配置可能比此数据集的朴素模型更有效
>0.742
>0.774
>0.774
>0.806
>0.742
>0.710
>0.767
>0.800
>0.767
>0.633
Mean Accuracy: 0.752 (0.048)
这是一个好结果吗?
事实上,这是一个具有挑战性的分类问题,达到 74.5% 以上的分数是好的。
接下来,让我们看看如何拟合最终模型并使用它进行预测。
最终模型并进行预测
一旦我们选择了模型配置,我们就可以在所有可用数据上训练最终模型,并使用它对新数据进行预测。
在这种情况下,我们将使用带有 dropout 和小批量的模型作为我们的最终模型。
我们可以像以前一样准备数据并拟合模型,尽管是在整个数据集而不是数据集的训练子集上。
...
# split into input and output columns
X, y = df.values[:, :-1], df.values[:, -1]
# ensure all data are floating point values
X = X.astype('float32')
# encode strings to integer
le = LabelEncoder()
y = le.fit_transform(y)
# determine the number of input features
n_features = X.shape[1]
# define model
model = Sequential()
model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,)))
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy')
然后我们可以使用这个模型对新数据进行预测。
首先,我们可以定义一行新数据。
...
# define a row of new data
row = [30,64,1]
注意:我从数据集的第一行中取出这一行,预期的标签是“1”。
然后我们可以进行预测。
...
# make prediction
yhat = model.predict_classes([row])
然后反转预测的变换,这样我们就可以在正确的标签中使用或解释结果(这只是这个数据集的一个整数)。
...
# invert transform to get label for class
yhat = le.inverse_transform(yhat)
在这种情况下,我们将简单地报告预测。
...
# report prediction
print('Predicted: %s' % (yhat[0]))
将所有这些结合在一起,下面列出了为 haberman 数据集拟合最终模型并使用它对新数据进行预测的完整示例。
# fit a final model and make predictions on new data for the haberman dataset
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import Dropout
df = read_csv(path, header=None)
# split into input and output columns
X, y = df.values[:, :-1], df.values[:, -1]
# ensure all data are floating point values
X = X.astype('float32')
# encode strings to integer
le = LabelEncoder()
y = le.fit_transform(y)
# determine the number of input features
n_features = X.shape[1]
# define model
model = Sequential()
model.add(Dense(10, activation='relu', kernel_initializer='he_normal', input_shape=(n_features,)))
model.add(Dense(1, activation='sigmoid'))
# compile the model
model.compile(optimizer='adam', loss='binary_crossentropy')
# fit the model
model.fit(X, y, epochs=200, batch_size=16, verbose=0)
# define a row of new data
row = [30,64,1]
# make prediction
yhat = model.predict_classes([row])
# invert transform to get label for class
yhat = le.inverse_transform(yhat)
# report prediction
print('Predicted: %s' % (yhat[0]))
运行示例在整个数据集上拟合模型,并对单行新数据进行预测。
在这种情况下,我们可以看到模型预测了输入行的“1”标签。
概括
在本文中,您了解了如何为癌症生存二元分类数据集开发多层感知器神经网络模型。
具体来学到了:
-
如何加载和总结癌症生存数据集并使用结果来建议要使用的数据准备和模型配置。
-
如何探索简单 MLP 模型在数据集上的学习动态。
-
如何对模型性能进行稳健的估计、调整模型性能并对新数据进行预测。
在公众号「python风控模型」里回复关键字:学习资料,就可免费领取。
欢迎各位同学了解<python机器学习生物信息学>课程,系统化学习机器学习建模知识
https://edu.csdn.net/combo/detail/1930