Keras Regression using Scikit Learn StandardScaler with Pipeline and without Pipeline

Posted

技术标签:

【中文标题】Keras Regression using Scikit Learn StandardScaler with Pipeline and without Pipeline【英文标题】: 【发布时间】:2017-10-04 15:07:50 【问题描述】:

我正在比较使用 Scikit-Learn StandardScaler 的两个关于 KerasRegressor 的程序的性能:一个使用 Scikit-Learn Pipeline 的程序和一个没有 Pipeline 的程序。

方案一:

estimators = []
estimators.append(('standardise', StandardScaler()))
estimators.append(('multiLayerPerceptron', KerasRegressor(build_fn=build_nn, nb_epoch=num_epochs, batch_size=10, verbose=0)))
pipeline = Pipeline(estimators)
log = pipeline.fit(X_train, Y_train)
Y_deep = pipeline.predict(X_test)

方案二:

scale = StandardScaler()
X_train = scale.fit_transform(X_train)
X_test = scale.fit_transform(X_test)
model_np = KerasRegressor(build_fn=build_nn, nb_epoch=num_epochs, batch_size=10, verbose=0)
log = model_np.fit(X_train, Y_train)
Y_deep = model_np.predict(X_test)

我的问题是程序 1 的 R2 分数可以达到 0.98(平均 3 次试验),而程序 2 的 R2 分数只能达到 0.84(平均 3 次试验)。谁能解释这两个程序之间的区别?

【问题讨论】:

看来你是独立地重新缩放每个数据集,你应该使用X_train = scale.fit_transform(X_train)X_test = scale.transform(X_test) 【参考方案1】:

在第二种情况下,您同时在X_trainX_test 上调用StandardScaler.fit_transform()。它的错误用法。

您应该在X_train 上致电fit_transform(),然后在X_test 上仅致电transform()。因为这就是Pipeline 所做的。 正如文档所述,Pipeline 将:

fit()

一个接一个地拟合所有的变换并变换数据, 然后使用最终估计器拟合转换后的数据

预测()

对数据应用变换,并使用最终估计器进行预测

所以你看,它只会将transform()应用于测试数据,而不是fit_transform()

所以详细说明我的观点,你的代码应该是:

scale = StandardScaler()
X_train = scale.fit_transform(X_train)

#This is the change
X_test = scale.transform(X_test)

model_np = KerasRegressor(build_fn=build_nn, nb_epoch=num_epochs, batch_size=10, verbose=0)
log = model_np.fit(X_train, Y_train)
Y_deep = model_np.predict(X_test)

在测试数据上调用 fit()fit_transform() 会错误地将其缩放到与用于训练数据的比例不同的比例。并且是预测变化的来源。

编辑:回答评论中的问题:

看,fit_transform() 只是执行fit() 然后transform() 的快捷功能。对于StandardScalerfit() 不返回任何内容,只是学习数据的均值和标准差。然后transform() 将学习应用于数据以返回新的缩放数据。

所以你所说的导致以下两种情况:

场景 1:错误

1) X_scaled = scaler.fit_transform(X)
2) Divide the X_scaled into X_scaled_train, X_scaled_test and run your model. 
   No need to scale again.

场景2:错误(基本等于场景1,反转缩放和吐槽操作)

1) Divide the X into X_train, X_test
2) scale.fit_transform(X) [# You are not using the returned value, only fitting the data, so equivalent to scale.fit(X)]
3.a) X_train_scaled = scale.transform(X_train) #[Equals X_scaled_train in scenario 1]
3.b) X_test_scaled = scale.transform(X_test) #[Equals X_scaled_test in scenario 1]

您可以尝试任何场景,也许它会提高模型的性能。

但是其中缺少一件非常重要的事情。当您对整个数据进行缩放然后将它们分成训练和测试时,假设您知道测试(未见过的)数据,这在现实世界的情况下是不正确的。并且会给你结果,这与现实世界的结果不相符。因为在现实世界中,所有的数据都是我们的训练数据。这也可能导致过拟合,因为模型已经有一些关于测试数据的信息。

因此,在评估机器学习模型的性能时,建议您先将测试数据放在一边,然后再对其进行任何操作。因为这是我们看不见的数据,我们对此一无所知。所以理想的操作路径就是我回答的那个,即:

1) Divide X into X_train and X_test (same for y)
2) X_train_scaled = scale.fit_transform(X_train) [#Learn the mean and SD of train data]
3) X_test_scaled = scale.transform(X_test) [#Use the mean and SD learned in step2 to convert test data]
4) Use the X_train_scaled for training the model and X_test_scaled in evaluation.

希望对你有意义。

【讨论】:

亲爱的 Vivek:我听从你关于 fit_transform(X_train) 和 transform(X_test) 的建议,分数确实上升了。谢谢。但是,我在这里有两个问题。 (1) 按照datascience.stackexchange.com/questions/13350/… 下的示例,我在 X_train 和 X_test 上都使用了 fit_transform()。看起来那个程序也会有类似的问题,对吧? (2) “fit_transform(X), then transform(X_train) and transform(X_test), where X is equal to X_train plus X_test”效果更好吗? Vivek:感谢您的 cmets。我现在对这些功能有了更好的了解。 @Frank 如果我的回答对您有所帮助并且您的问题得到解决,那么请考虑将其标记为已接受。

以上是关于Keras Regression using Scikit Learn StandardScaler with Pipeline and without Pipeline的主要内容,如果未能解决你的问题,请参考以下文章

Linear Regression Using Gradient Descent 代码实现

Logistic Regression Using Gradient Descent -- Binary Classification 代码实现

Theano-Deep Learning Tutorials 笔记:Classifying MNIST digits using Logistic Regression

Keras using Conv2D for MINST

学习keras的regressor

Keras使用标量乘以层输出