Tensorflow欺诈交易预测模型混淆矩阵全零问题求助
解决欺诈检测模型全预测0的问题
你的混淆矩阵显示所有样本都被预测为类别0,说明模型完全没有学到识别欺诈样本(类别1)的能力,以下是针对性的修复方案:
1. 调整数据拆分策略,保留足够训练样本
你当前设置test_size=0.95,导致训练集仅占总数据的5%,对于极度不平衡的数据集来说,训练集中的欺诈样本数量会少到可以忽略,SMOTE过采样也无法弥补样本量不足的问题。修改拆分逻辑,同时加入stratify参数保证各集合的类别比例与原数据一致:
# 先拆分训练+验证集与测试集(测试集占20%) X_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) # 再从训练+验证集中拆分训练集与验证集(验证集占训练+验证集的20%) X_train, X_val, y_train, y_val = train_test_split(X_train_val, y_train_val, test_size=0.2, random_state=42, stratify=y_train_val) # 再对训练集应用SMOTE过采样 sm = SMOTE(random_state=42) X_train, y_train = sm.fit_resample(X_train, y_train)
2. 正确使用归一化层
Keras的Normalization层需要先在训练数据上执行adapt操作,才能学习到训练集的均值和方差用于归一化,否则该层无法发挥作用:
# 初始化并适配归一化层到训练数据 normalizer = layers.Normalization() normalizer.adapt(X_train) model = models.Sequential() model.add(normalizer) # 使用适配后的归一化层 model.add(layers.Dense(25, activation="relu")) model.add(layers.Dropout(0.3)) model.add(layers.Dense(10, activation="relu")) model.add(layers.Dropout(0.3)) model.add(layers.Dense(5, activation="relu")) model.add(layers.Dropout(0.3)) model.add(layers.Dense(1, activation="sigmoid"))
3. 添加早停回调,避免过拟合/无意义训练
训练100个epoch容易导致过拟合或无效训练,加入早停回调监控验证集的Recall(核心目标是识别欺诈样本),自动停止并恢复最佳模型权重:
model.compile(optimizer="Adam", loss="binary_crossentropy", metrics=["Precision", "Recall", "AUC"]) # 早停配置:监控验证集Recall,10个epoch无提升则停止,恢复最佳权重 early_stopping = EarlyStopping(monitor='val_recall', patience=10, restore_best_weights=True, mode='max') history = model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=100, callbacks=[early_stopping])
4. 优化特征工程(可选但有效)
针对Time和Amount特征做针对性处理,提升模型学习效率:
Time:转换为小时数,捕捉交易时间规律Amount:对数变换,缓解金额的长尾分布影响
# 特征工程要在数据拆分前执行 # Time转换为小时(一天86400秒) X['Time'] = X['Time'] % 86400 / 3600 # Amount做对数变换(log1p避免0值报错) X['Amount'] = np.log1p(X['Amount'])
5. 引入类别权重(可选)
即使使用了SMOTE,也可以给欺诈样本分配更高的类别权重,让模型更重视欺诈样本的分类错误:
from sklearn.utils.class_weight import compute_class_weight # 计算平衡的类别权重 class_weights = compute_class_weight('balanced', classes=np.unique(y_train), y=y_train) class_weight_dict = {0: class_weights[0], 1: class_weights[1]} # 在fit时传入类别权重 history = model.fit(X_train, y_train, validation_data=(X_val, y_val), epochs=100, callbacks=[early_stopping], class_weight=class_weight_dict)
完成以上修改后,重新训练模型,再评估混淆矩阵和Recall、AUC等指标,应该能看到模型开始识别欺诈样本。
内容的提问来源于stack exchange,提问作者Lapin
相关产品推荐
相关产品推荐

