银行分支交易数据训练神经网络时部分分支预测全为0问题
问题分析与解决方案
核心原因排查
部分分支模型预测全0,排除数据缺失后,主要原因集中在以下几点:
- 样本极端不均衡:部分分支非0交易数据占比极低(比如工作日交易量也很少,叠加周末/节假日的0值),模型为了最小化MSE损失,会倾向于输出0——因为大部分样本是0,这种“偷懒”的预测能让整体误差最小。
- 输出层激活函数不合适:输出层用
relu会截断所有小于0的预测值,若模型因数据分布极端,最后一层的权重偏置调整到让所有输入都小于0,就会全输出0。 - 模型未利用时间序列特性:交易数据是时间序列,但当前模型用的是全连接层,没有捕捉日期间的依赖关系,小分支的有限非0样本无法让模型学到有效模式。
具体解决方案
1. 调整输出层激活函数
回归任务中,交易金额是连续值,relu不适合作为输出层激活函数,换成linear后再对负预测值做截断:
model.add(Dense(1, activation='linear')) # 预测后处理负数值 predictions = np.maximum(model.predict(X), 0)
2. 解决样本不均衡问题
给非0样本的损失赋予更高权重,迫使模型重视非0交易的预测:
import tensorflow as tf def weighted_mse(y_true, y_pred): # 非0样本的误差权重设为10,可根据实际情况调整 weight = tf.where(y_true > 0, 10.0, 1.0) return tf.reduce_mean(weight * tf.square(y_true - y_pred)) # 编译模型时使用自定义损失 model.compile(loss=weighted_mse, optimizer=Adam())
3. 改用LSTM处理时间序列
交易数据有时间依赖,用LSTM替代全连接层能更好捕捉规律,先把数据转换成LSTM要求的格式:
import numpy as np def create_sequences(data, seq_length): X, y = [], [] # 用过去seq_length天的数据预测下一天的交易量 for i in range(len(data) - seq_length): X.append(data[i:i+seq_length]) y.append(data[i+seq_length]) return np.array(X), np.array(y) # 针对单个分支数据处理,seq_length设为7(一周) seq_length = 7 branch_data = df['branch_id_X'] # 替换为目标分支列 X, y = create_sequences(branch_data.values, seq_length) # 调整形状为(样本数, 时间步长, 特征数) X = X.reshape(X.shape[0], X.shape[1], 1)
然后构建LSTM模型:
model = Sequential() model.add(LSTM(32, return_sequences=True, input_shape=(seq_length, 1))) model.add(Dropout(0.2)) # 防止过拟合 model.add(LSTM(64)) model.add(Dense(32, activation='relu')) model.add(Dense(1, activation='linear')) model.compile(loss='mean_squared_error', optimizer=Adam())
4. 优化数据预处理
对非0数据单独做归一化,避免0值拉低整体尺度:
from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() # 仅用非0数据拟合归一化器 non_zero = branch_data[branch_data > 0].values.reshape(-1, 1) scaler.fit(non_zero) # 转换数据,0值保持不变 scaled_data = branch_data.copy() scaled_data[scaled_data > 0] = scaler.transform(scaled_data[scaled_data > 0].values.reshape(-1,1)).flatten() # 之后用scaled_data生成序列训练模型
5. 调整训练参数
- 减小
batch_size:当前31对于小样本分支过大,改成8或16,让模型更关注小批量样本的规律。 - 加入早停机制:防止过拟合,同时确保模型学到最优参数:
from keras.callbacks import EarlyStopping early_stop = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True) model.fit(X, y, epochs=100, batch_size=8, validation_split=0.2, callbacks=[early_stop], verbose=1)
内容的提问来源于stack exchange,提问作者GMDin
相关产品推荐
相关产品推荐

