自定义Logistic回归代码遇RuntimeWarning: exp溢出问题求助
问题描述
实现自定义Logistic回归代码后,模型预测结果全为0,同时出现以下警告:
RuntimeWarning: overflow encountered in exp
predictions = 1 / (1 + np.exp(-predictions))
附上的代码如下:
import numpy as np import pandas as pd dataset = pd.read_csv('data.csv') dataset = (dataset - dataset.mean()) / dataset.std() from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(dataset.iloc[:, :-1], dataset.iloc[:, -1], test_size=0.25, random_state=42) def logisticRegression_model(X, y, learning_rate, num_epochs): weights = np.zeros(X.shape[1]) for epoch in range(num_epochs): logisticRegression_update_weights(X, y, weights, learning_rate) return weights def logisticRegression_update_weights(X, y, weights, learning_rate): gradient = logisticRegression_calculate_gradient(X, y, weights) weights += learning_rate * gradient return weights def logisticRegression_calculate_gradient(X, y, weights): #calculating the predictions predictions = logisticRegression_predict(X, weights) #calculating the errors error = y - predictions gradient = np.dot(X.T, error) return gradient def logisticRegression_predict(X, weights): predictions = np.dot(X, weights) predictions = 1 / (1 + np.exp(-predictions)) return predictions def logisticRegression_accuracy(y_true, y_pred): accuracy = np.sum(y_true == y_pred) / len(y_true) return accuracy def logisticRegression_train(X_train, y_train, learning_rate, num_epochs): weights = logisticRegression_model(X_train, y_train, learning_rate, num_epochs) return weights weights = logisticRegression_train(X_train, y_train, 0.1, 1000) y_pred_train = logisticRegression_predict(X_train, weights) y_pred_test = logisticRegression_predict(X_test, weights) y_pred_train = (y_pred_train > 0.5).astype(int) y_pred_test = (y_pred_test > 0.5).astype(int) acc_train = logisticRegression_accuracy(y_train, y_pred_train) acc_test = logisticRegression_accuracy(y_test, y_pred_test) print('Train accuracy:', acc_train) print('Test accuracy:', acc_test)
问题原因与修复方案
1. 权重更新未生效(核心问题)
logisticRegression_model函数中,调用logisticRegression_update_weights时未接收返回的更新后权重,导致weights始终是初始全0数组,最终预测值全为0.5,经>0.5判断后输出全0。
修复代码:
def logisticRegression_model(X, y, learning_rate, num_epochs): weights = np.zeros(X.shape[1]) for epoch in range(num_epochs): # 接收更新后的权重 weights = logisticRegression_update_weights(X, y, weights, learning_rate) return weights
2. 指数溢出问题
当np.dot(X, weights)结果绝对值过大时,np.exp(-predictions)会超出浮点数范围。可改用稳定版sigmoid实现:
方案一:手动处理溢出
def logisticRegression_predict(X, weights): predictions = np.dot(X, weights) # 分情况计算避免溢出 predictions = np.where(predictions >= 0, 1 / (1 + np.exp(-predictions)), np.exp(predictions) / (1 + np.exp(predictions))) return predictions
方案二:使用scipy内置函数(需导入from scipy.special import expit)
def logisticRegression_predict(X, weights): predictions = np.dot(X, weights) predictions = expit(predictions) return predictions
3. 学习率与迭代次数优化
当前学习率0.1过高,易导致权重震荡发散,建议降至0.01或0.001,并根据模型收敛情况调整迭代次数。
4. 添加偏置项
标准Logistic回归需要偏置项(截距),原代码缺失会影响拟合效果。在分割数据集后添加:
# 给训练集和测试集添加全1的偏置列 X_train = np.hstack((np.ones((X_train.shape[0], 1)), X_train)) X_test = np.hstack((np.ones((X_test.shape[0], 1)), X_test))
同时初始化权重时要包含偏置项维度:
def logisticRegression_model(X, y, learning_rate, num_epochs): weights = np.zeros(X.shape[1]) ...
修复后完整代码示例
import numpy as np import pandas as pd from sklearn.model_selection import train_test_split from scipy.special import expit dataset = pd.read_csv('data.csv') # 仅标准化特征,目标变量无需标准化 X = dataset.iloc[:, :-1] y = dataset.iloc[:, -1] X = (X - X.mean()) / X.std() # 添加偏置项 X = np.hstack((np.ones((X.shape[0], 1)), X)) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42) def logisticRegression_model(X, y, learning_rate, num_epochs): weights = np.zeros(X.shape[1]) for epoch in range(num_epochs): weights = logisticRegression_update_weights(X, y, weights, learning_rate) return weights def logisticRegression_update_weights(X, y, weights, learning_rate): gradient = logisticRegression_calculate_gradient(X, y, weights) weights += learning_rate * gradient return weights def logisticRegression_calculate_gradient(X, y, weights): predictions = logisticRegression_predict(X, weights) error = y - predictions # 按样本数归一化梯度,提升稳定性 gradient = np.dot(X.T, error) / len(y) return gradient def logisticRegression_predict(X, weights): predictions = np.dot(X, weights) predictions = expit(predictions) return predictions def logisticRegression_accuracy(y_true, y_pred): accuracy = np.sum(y_true == y_pred) / len(y_true) return accuracy def logisticRegression_train(X_train, y_train, learning_rate, num_epochs): weights = logisticRegression_model(X_train, y_train, learning_rate, num_epochs) return weights # 调整学习率和迭代次数 weights = logisticRegression_train(X_train, y_train, 0.01, 1000) y_pred_train = logisticRegression_predict(X_train, weights) y_pred_test = logisticRegression_predict(X_test, weights) y_pred_train = (y_pred_train > 0.5).astype(int) y_pred_test = (y_pred_test > 0.5).astype(int) acc_train = logisticRegression_accuracy(y_train, y_pred_train) acc_test = logisticRegression_accuracy(y_test, y_pred_test) print('Train accuracy:', acc_train) print('Test accuracy:', acc_test)
内容的提问来源于stack exchange,提问作者Melad
相关产品推荐
相关产品推荐

