Keras二分类模型结合Scaler与特征选择时在线预测结果异常
我搭建了一个可定时(每小时/每日)用新数据训练Keras二分类(0或1)模型的应用,训练和测试环节表现都符合预期。训练时会测试不同特征,并用MinMaxScaler对数据做缩放(部分数值为负)。
但用单条实时数据预测时,结果极不真实——大多在0.9987到1之间,和实际情况不符。这个预测结果代表样本接近"1"的程度,持续高数值会触发告警。
在线预测代码
current_df是包含1行实时数据及列名的pandas DataFrame,需选择对应特征(训练时采用动态特征选择,每次训练的模型对应特征可能不同,特征列表从数据库加载):
# Convert literal str to list features = ast.literal_eval(features)
然后在DataFrame中筛选所需特征:
# Select the features selected_df = current_df[features]
提取数据为列表:
# Get the values of the df current_list = selected_df.values.tolist()[0]
进行第一次重塑:
# Reshape to allow scaling and predicting current_list = np.reshape(current_list, (-1, 1))
若此处调用transform而非fit_transform,会报错:This MinMaxScaler instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.
再次重塑:
# Reshape to be able to scale current_list = np.reshape(current_list, (1, -1))
加载Keras模型并预测:
# Loads the model from the local folder reconstructed_model = keras.models.load_model(model_location) prediction = reconstructed_model.predict(current_list) prediction = prediction.flat[0]
补充信息
训练时的数据缩放采用fit_transform和transform(使用MinMaxScaler,也可替换为Standard Scaler):
X_train = pd.DataFrame(scaler.fit_transform(X_train), columns=X_train.columns, index=X_train.index) X_test = pd.DataFrame(scaler.transform(X_test), columns=X_test.columns, index=X_test.index)
训练流程如下(模型结构未展示):
# Compile the model model.compile(optimizer=optimizer, loss=loss, metrics=['binary_accuracy']) # build the model model.fit(X_train, y_train, epochs=epochs, verbose=0) # Evaluate using Keras built-in function scores = model.evaluate(X_test, y_test, verbose=0) testing_accuracy = scores[1] # create model with sklearn KerasClassifier for evaluation eval_model = KerasClassifier(model=model, epochs=epochs, batch_size=10, verbose=0) # Evaluate model using RepeatedStratifiedKFold accuracy = ML.evaluate_model_KFold(eval_model, X_test, y_test) # Predict testing data pred_test= model.predict(X_test, verbose=0) pred_test = pred_test.flatten() # extract the predicted class labels y_predicted_test = np.where(pred_test > 0.5, 1, 0)
特征选择方面,每次训练的特征不固定——我会使用SelectKBest(选10或15个特征)或RFECV,选择准确率最高的训练模型,因此不同模型对应的特征可能不同。
问题分析与修正方案
1. 核心错误:未复用训练阶段的预处理组件
预测时你完全没有使用训练时拟合好的Scaler,也没有保存/加载特征选择器,直接用原始数据喂给模型,而模型是基于缩放后的数据训练的,这必然导致预测结果异常。报错提示Scaler未拟合,是因为你用了全新的Scaler实例,而非训练时保存的那个。
2. 关键流程错误:特征选择与缩放的顺序
训练时必须严格遵循:原始数据 → 特征选择(fit+transform)→ Scaler拟合+缩放 → 模型训练。如果先缩放再做特征选择,会导致Scaler的拟合范围包含被丢弃的特征,后续预测时的缩放逻辑和训练阶段不一致。
同时,每次训练后必须把特征列表、特征选择器、Scaler、模型作为一个整体保存,因为不同模型对应不同的特征集合和缩放参数,不能只保存模型。
3. 修正后的代码示例
训练阶段:保存所有必要组件
import joblib # 假设训练时的特征选择器为selector,Scaler为scaler,模型为model # 保存特征选择器 joblib.dump(selector, f"{model_location}_selector.pkl") # 保存Scaler joblib.dump(scaler, f"{model_location}_scaler.pkl") # 保存模型 model.save(model_location) # 同时将本次训练的特征列表存入数据库
预测阶段:复用训练时的预处理逻辑
import ast import pandas as pd import joblib import keras # 加载特征列表、特征选择器、Scaler、模型 features = ast.literal_eval(features) selector = joblib.load(f"{model_location}_selector.pkl") scaler = joblib.load(f"{model_location}_scaler.pkl") reconstructed_model = keras.models.load_model(model_location) # 筛选特征 selected_df = current_df[features] # 执行特征选择转换(和训练顺序一致) selected_data = selector.transform(selected_df) # 用训练好的Scaler做缩放(只能用transform,绝对不能fit) scaled_data = scaler.transform(selected_data) # 预测 prediction = reconstructed_model.predict(scaled_data, verbose=0) prediction = prediction.flat[0]
额外注意事项
- 绝对不能在预测阶段对新数据执行
fit或fit_transform,必须复用训练时拟合好的特征选择器和Scaler - 每次训练的特征集合、预处理组件、模型必须一一对应,避免出现"用A模型的特征喂给B模型"的情况
内容的提问来源于stack exchange,提问作者galgo

