LinearRegression预测结果因输入类型不同而异

我正在开发一个根据汽车属性预测价格的模型。我注意到LinearRegression模型的预测结果会因输入类型(numpy.ndarrayscipy.sparse.csr.csr_matrix)的不同而有所差异。

我的数据包括一些数值和分类属性,没有NaN值。

以下是一个简单的准备数据代码(对于我接下来描述的所有情况都通用):

from sklearn.pipeline import Pipelinefrom sklearn.compose import ColumnTransformerfrom sklearn.linear_model import LinearRegression# 划分测试和训练集X = data_orig.drop("price", axis=1)y = data_orig[["price"]]X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 数值属性管道num_pipeline = Pipeline([ ("scaler", StandardScaler()) ])# 分类属性管道cat_pipeline = Pipeline([ ("encoder", OneHotEncoder(handle_unknown="ignore")) ])# 完整管道full_pipeline = ColumnTransformer([    ("cat", cat_pipeline, ["model", "transmission", "fuelType"]),    ("num", num_pipeline, ["year", "mileage", "tax", "mpg", "engineSize"]),])

让我们构建一个LinearRegression模型(X_trainX_test将是scipy.sparse.csr.csr_matrix的实例):

...   X_train = full_pipeline.fit_transform(X_train)X_test = full_pipeline.transform(X_test)from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression().fit(X_train, y_train)pred = lin_reg.predict(X_test)r2_score(y_test, pred) # 0.896044623680753 OK

如果我将X_testX_train转换为numpy.ndarray类型,模型的预测结果完全不正确:

...   X_train = full_pipeline.fit_transform(X_train).toarray() # 这里X_test = full_pipeline.transform(X_test).toarray() # 和这里from sklearn.linear_model import LinearRegressionlin_reg = LinearRegression().fit(X_train, y_train)pred = lin_reg.predict(X_test)    r2_score(y_test, pred) # -7.919935999010152e+19 出了问题

我还测试了DecisionTreeRegressorRandomForestRegressorSVR,但只有LinearRegression出现了这个问题。


回答:

源代码中,你可以看到如果你的输入是稀疏矩阵,它会进行一些居中处理,然后调用稀疏版本的线性最小二乘法。如果数组是密集的,它会调用numpy版本的线性最小二乘法

然而,这个例子中更大的问题是在执行独热编码之前,你应该检查是否有任何分类值只有一个条目:

data_orig.select_dtypes(['object']).apply(lambda x:min(pd.Series.value_counts(x)))model              1transmission    2708fuelType          28

如果我们检查模型:

data_orig['model'].value_counts().tail() SQ7    8 S8     4 S5     3 RS7    1 A2     1

所以如果RS7和A2在测试集中但不在训练集中,那么这个系数将完全是垃圾,因为它的所有值都是零。如果我们尝试使用另一个种子来分割数据,你可以看到两个拟合结果相似:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=22)

一个函数,用于以不同方式拟合稀疏/密集数据:

import matplotlib.pyplot as pltdef fit(X_tr,X_ts,y_tr,y_ts,is_sparse=True):    data_train = full_pipeline.fit_transform(X_tr)    data_test = full_pipeline.transform(X_ts)        if not is_sparse:        data_train = data_train.toarray()        data_test = data_test.toarray()        lin_reg = LinearRegression().fit(data_train, y_tr)    pred = lin_reg.predict(data_test)        plt.scatter(y_ts,pred)    return {'r2_train':r2_score(y_tr, lin_reg.predict(data_train)),            'r2_test':r2_score(y_ts, pred),            'pred':pred}

我们可以看到训练和测试的r2值:

sparse_pred = fit(X_train,X_test,y_train,y_test,is_sparse=True)[sparse_pred['r2_train'],sparse_pred['r2_test']][0.8896333645670668, 0.898030271986993]

enter image description here

sparse_pred = fit(X_train,X_test,y_train,y_test,is_sparse=False)[sparse_pred['r2_train'],sparse_pred['r2_test']][0.8896302753422759, 0.8980115229388697]

enter image description here

你可以尝试在你的例子中使用种子(42),你会发现训练的r^2值是相似的。预测结果才是出问题的部分。

所以如果你使用稀疏矩阵,最小二乘法可能会为全零列返回一个较少无意义的系数(这可能是@piterbarg指出的问题)。

尽管如此,我认为在投入管道之前,应该检查测试和训练数据之间是否有这样的缺失因素。对于这个数据集来说,它很可能不是过定,因此稀疏与密集不应该是差异所在。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注