为什么 Sckit 的 fit_transform 会导致准确性和所有其他评估指标大幅下降?

数据挖掘 机器学习 深度学习 喀拉斯 scikit-学习
2022-02-17 23:39:37

尝试使用sc.fit_transform(X),我在同一模型上的准确性大幅下降。在不缩放我的数据集的值的情况下,我得到 80 - 82% 的准确度值。当我尝试使用 缩放它们时sc.fit_transform(X),我得到 70 - 74% 的准确度值。

准确度大幅下降的原因可能是什么?

编辑

这是我正在使用的代码:

# read the dataset file
basic_df = pd.read_csv('posts.csv', sep=';', encoding = 'ISO-8859-1', parse_dates=[2], dayfirst=True) 

# One-Hot-Encoding for categorical (strings) features
basic_df = pd.get_dummies(basic_df, columns=['industry', 'weekday', 'category_name', 'page_name', 'type']) 

# bring the label column to the end 
cols = list(basic_df.columns.values) # Make a list of all of the columns in the df
cols.pop(cols.index('successful')) # Remove target column from list
basic_df = basic_df[cols+['successful']] # Add it at the end of dataframe

dataset = basic_df.values

# separate the data from the labels 
X = dataset[:,0:45].astype(float)
Y = dataset[:,45]

#standardizing the input feature
X = sc.fit_transform(X)

# evaluate model with standardized dataset
#estimator = KerasClassifier(build_fn=create_baseline, epochs=5, batch_size=5, verbose=0)
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3, random_state=seed)
#estimator.fit(X_train, Y_train)
#predictions = estimator.predict(X_test)
#list(predictions)

# build the model 
model = Sequential()
model.add(Dense(100, input_dim=45, kernel_initializer='normal', activation='relu'))
model.add(Dense(50, kernel_initializer='normal', activation='relu'))
model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))

# Compile model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# Fit the model
history = model.fit(X_train, Y_train, validation_split=0.3, epochs=500, batch_size=10)

有一部分代码被注释了,因为我一开始就尝试使用 KerasClassifier。但是,当我使用 fit_transform(X) 时,这两种方法最终的准确度都要低得多(如上所述)。在不使用 fit_transform(X) 的情况下,我得到了 80 - 82% 的准确率。没有 70 - 74%。怎么会?难道我做错了什么?缩放输入数据并不总是会导致更好的(或至少几乎相同的精度结果)并且主要是更快的拟合?为什么使用它的时候准确率会有这么大的下降?

PS: 'sc' 是 StandardScaler() --> sc = StandardScaler()

这是使用的数据框(在 2 张照片中,因为它太宽而无法仅在一张照片中制作屏幕截图),列“成功”作为标签列: 自由度 1 自由度 2

2个回答

没有看到实际数据很难说。
我确实有一个猜测,当对所有数据使用缩放器时(在训练/测试拆分之前),您会造成数据泄漏。
意思是,模型拟合不应该看到的一些数据(测试集)有效地包含在训练集中(因为缩放器看到它并用于设置比例)。
这种数据泄漏会导致过度拟合,从而降低准确度得分。
尝试在每个火车/测试拆分上进行缩放部分(在火车上使用 fit_transform 并且仅在测试中进行变换)。这是模型研究的更好实践,并且显然更接近训练后的模型将如何实时执行(在尚未看到的数据上)。

请使用提前停止。我们不能一开始就选择一些 epoch 和一些超参数,然后改变(转换)数据,然后等着看会发生什么。如果您对输入数据进行归一化通常以更快的拟合模型结束的说法是正确的(这是预期的),那么模型也应该更快地过拟合。你应该监控你的学习并抓住你的模型适合的最佳时期您可以按如下方式执行此操作:

定义提前停止:

from keras.callbacks import EarlyStopping
es = EarlyStopping(monitor='val_acc',
                              min_delta=0,
                              patience=20,
                              verbose=0, mode='auto',restore_best_weights=True)

然后将其添加到您的培训中:

model.fit(X_train, Y_train, validation_split=0.3, epochs=500, batch_size=10,callbacks=[es])

您可以自行设置提前停止的参数。提前停止允许您在模型性能因过度拟合而开始下降的地方停止。通过选择restore_best_weights=True,您还可以在停止时从具有最佳性能的时期恢复模型。它也会缩短你的训练时间,因为它可能会停在某个地方。

有关提前停止的更多详细信息,请查看:https ://stackoverflow.com/questions/43906048/keras-early-stopping

您还可以使用批量归一化来归一化输入,以及神经网络隐藏层之间的中间张量。

model = Sequential()
model.add(Dense(100, input_dim=45, kernel_initializer='normal', activation='relu'))
model.add(BatchNormalization())
model.add(Dense(50, kernel_initializer='normal', activation='relu'))
model.add(BatchNormalization())
model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))

这将加快您的拟合速度,同时也会产生轻微的正则化效果。

深入了解(BatchNorm 论文):https ://arxiv.org/pdf/1502.03167.pdf

最后,为了回答您问题的具体核心,您需要标准化您的数据,而不是在您的上下文中对其进行标准化。这通常取决于激活函数,ReLU 与归一化配合得很好不要忘记在归一化之前将训练集和测试集分开;正如我所观察到的那样,您立即执行它们。这是导致数据泄漏的好方法。您可以使用以下配置:

from sklearn.preprocessing import Normalizer
transformer = Normalizer().fit(x_train)
x_train = transformer.transform(x_train)
transformer = Normalizer().fit(x_test)
x_test = transformer.transform(x_test)

希望我能帮上忙,祝你好运!