线性回归模型预测值出现负值的问题排查请求
线性回归预测出现负值的成因及解决办法
一、核心问题成因分析
1. 代码中的致命错误
你对连续目标变量y(CPM)使用了pd.get_dummies(),这是完全错误的操作:
- CPM是数值型连续变量,而
pd.get_dummies()是用于处理分类变量的one-hot编码工具。 - 该操作会把原本连续的CPM值拆分成多个二进制列,将回归任务错误转换成多分类任务,直接导致模型训练逻辑混乱,预测结果必然异常,包括出现负值。
另外代码中存在冗余且可能引发问题的操作:
X = dataFrame.astype(object) y = dataFrame.astype(object)
这段代码把整个数据集强制转为object类型,后续又重新赋值X和y,不仅无意义还可能引入类型冲突。
2. 线性回归模型的固有特性
即使代码修正后,标准线性回归(LinearRegression)是无约束模型:它通过最小化均方误差拟合参数,不会主动限制预测值符合数据的非负特性。当特征组合的线性加权加上截距后计算结果为负时,模型就会输出负值,这是这类模型的正常表现。
二、修正方案
第一步:修复代码中的错误
先纠正目标变量的处理逻辑,清理冗余代码,确保模型训练符合回归任务的要求:
import numpy as np import pandas as pd from sklearn import metrics import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score from sklearn import linear_model %matplotlib inline # 数据读取与预处理 dataFrame = pd.read_csv("fskning/Data cleaned.csv", delimiter=";") # 直接选择特征与目标变量,无需先转object类型 X = dataFrame[['Alder','Eksponeringer','Køn']] y = dataFrame['CPM (pris pr. 1000 eksponeringer)'] # 仅对分类特征做one-hot编码,加drop_first避免多重共线性 X = pd.get_dummies(X, drop_first=True) # 数据集拆分 X_train,X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 100) # 训练线性回归模型 reg_model = LinearRegression().fit(X_train, y_train) print('截距:',reg_model.intercept_) print('特征系数:', list(zip(X.columns, reg_model.coef_))) # 预测与评估 y_pred= reg_model.predict(X_test) x_pred= reg_model.predict(X_train) mse = mean_squared_error(y_test,y_pred) print("均方误差:{:.2f}".format(mse)) print("均方根误差:{:.2f}".format(np.sqrt(mse)))
第二步:解决预测负值的问题
修复代码后如果仍出现负值,可采用以下几种方案:
1. 使用带非负约束的回归模型
Scikit-learn的Lasso或ElasticNet支持设置positive=True,强制所有系数为正,结合截距约束减少负值输出:
# 使用带非负约束的Lasso回归 reg_model = linear_model.Lasso(alpha=0.1, positive=True, random_state=100) reg_model.fit(X_train, y_train) y_pred = reg_model.predict(X_test)
2. 对目标变量做变换
如果CPM分布偏态,可先对y做对数变换,预测后再反变换,自然避免负值:
# 对数变换目标变量(log1p避免0值问题) y_log = np.log1p(y) reg_model = LinearRegression().fit(X_train, y_log) y_pred_log = reg_model.predict(X_test) # 反变换得到原始尺度的预测值 y_pred = np.expm1(y_pred_log)
3. 截断预测值
若上述方法不适用,可直接将预测负值替换为0或数据集中CPM的最小值:
# 将负值设为0 y_pred = np.maximum(y_pred, 0) # 或者设为数据集的最小CPM值 min_cpm = dataFrame['CPM (pris pr. 1000 eksponeringer)'].min() y_pred = np.maximum(y_pred, min_cpm)
内容的提问来源于stack exchange,提问作者ems111111
相关产品推荐
相关产品推荐

