首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >线性回归中StandardScaler与正规化器结果的比较

线性回归中StandardScaler与正规化器结果的比较
EN

Stack Overflow用户
提问于 2019-01-07 01:12:08
回答 3查看 6.9K关注 0票数 24

我正在研究不同场景下线性回归的一些例子,比较使用NormalizerStandardScaler的结果,结果令人费解。

我正在使用波士顿住房数据集,并以这样的方式准备:

代码语言:javascript
运行
复制
import numpy as np
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.preprocessing import Normalizer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression

#load the data
df = pd.DataFrame(boston.data)
df.columns = boston.feature_names
df['PRICE'] = boston.target

目前,我正试图对从以下场景中得到的结果进行推理:

  • 用参数normalize=TrueNormalizer初始化线性回归
  • 用参数fit_intercept = False初始化线性回归,不论标准化与否。

总的来说,我觉得结果令人困惑。

我是这样安排一切的:

代码语言:javascript
运行
复制
# Prep the data
X = df.iloc[:, :-1]
y = df.iloc[:, -1:]
normal_X = Normalizer().fit_transform(X)
scaled_X = StandardScaler().fit_transform(X)

#now prepare some of the models
reg1 = LinearRegression().fit(X, y)
reg2 = LinearRegression(normalize=True).fit(X, y)
reg3 = LinearRegression().fit(normal_X, y)
reg4 = LinearRegression().fit(scaled_X, y)
reg5 = LinearRegression(fit_intercept=False).fit(scaled_X, y)

然后,我创建了三个单独的数据框架来比较每个模型的R_score、系数值和预测值。

为了创建用于比较每个模型的系数值的数据,我执行了以下操作:

代码语言:javascript
运行
复制
#Create a dataframe of the coefficients
coef = pd.DataFrame({
    'coeff':                       reg1.coef_[0],
    'coeff_normalize_true':        reg2.coef_[0],
    'coeff_normalizer':            reg3.coef_[0],
    'coeff_scaler':                reg4.coef_[0],
    'coeff_scaler_no_int':         reg5.coef_[0]
})

下面是我如何创建dataframe来比较每个模型的R^2值:

代码语言:javascript
运行
复制
scores = pd.DataFrame({
    'score':                        reg1.score(X, y),
    'score_normalize_true':         reg2.score(X, y),
    'score_normalizer':             reg3.score(normal_X, y),
    'score_scaler':                 reg4.score(scaled_X, y),
    'score_scaler_no_int':          reg5.score(scaled_X, y)
    }, index=range(1)
)

最后,下面是比较每一种预测的数据:

代码语言:javascript
运行
复制
predictions = pd.DataFrame({
    'pred':                        reg1.predict(X).ravel(),
    'pred_normalize_true':         reg2.predict(X).ravel(),
    'pred_normalizer':             reg3.predict(normal_X).ravel(),
    'pred_scaler':                 reg4.predict(scaled_X).ravel(),
    'pred_scaler_no_int':          reg5.predict(scaled_X).ravel()
}, index=range(len(y)))

下面是生成的数据文件:

COEFFICIENTS:

分数:

PREDICTIONS:

我有三个我无法调和的问题:

  1. 为什么前两种模式完全没有区别?设置normalize=False似乎没有任何作用。我能理解有相同的预测值和R^2值,但是我的特性有不同的数值尺度,所以我不知道为什么正常化会没有任何影响。当您考虑到使用StandardScaler会显着地改变系数时,这是双重混淆的。
  2. 我不明白为什么使用Normalizer的模型会导致与其他模型完全不同的系数值,特别是当带有LinearRegression(normalize=True)的模型完全没有变化的时候。

如果要查看每个文档,它们似乎非常相似,如果不是完全相同的话。

model.LinearRegression()上的文档

规范化:布尔、可选、默认的假 当fit_intercept设置为False时,将忽略此参数。如果为真,则在回归之前,通过减去均值,再除以L2-范数,将回归量X归一化。

同时,sklearn.preprocessing.Normalizer 默认情况下,它将规范为l2规范。上的文档。

我看不出这两个选项之间有什么区别,我也不明白为什么其中一个在系数值上会与另一个有如此大的差别。

  1. 使用StandardScaler的模型的结果对我来说是一致的,但是我不明白为什么使用StandardScaler和设置set_intercept=False的模型表现这么差。

线性回归模上的文档

fit_intercept :布尔值,可选,默认的真 是否计算此模型的截距。如果设置为False,则不 拦截将用于计算(例如,数据预计已经被使用)。 中心)。

StandardScaler将您的数据作为中心,所以我不明白为什么将它与fit_intercept=False一起使用会产生不一致的结果。

EN

Stack Overflow用户

发布于 2020-08-06 17:39:13

关于fit_intercept=0和标准化数据不一致结果的最后一个问题(3)还没有得到充分的回答。

OP很可能期望StandardScaler将X和y标准化,这将使拦截必须达到0 (证明 1/3的下行方式)。

然而,StandardScaler忽略y。参见api接口

TransformedTargetRegressor提供了一个解决方案。这种方法对于因变量的非线性转换也很有用,例如y的日志转换(但考虑)。

下面是一个解决OP问题#3的例子:

代码语言:javascript
运行
复制
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import make_pipeline
from sklearn.datasets import make_regression
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
import numpy as np

# define a custom transformer
class stdY(BaseEstimator,TransformerMixin):
    def __init__(self):
        pass
    def fit(self,Y):
        self.std_err_=np.std(Y)
        self.mean_=np.mean(Y)
        return self
    def transform(self,Y):
        return (Y-self.mean_)/self.std_err_
    def inverse_transform(self,Y):
        return Y*self.std_err_+self.mean_

# standardize X and no intercept pipeline
no_int_pipe=make_pipeline(StandardScaler(),LinearRegression(fit_intercept=0)) # only standardizing X, so not expecting a great fit by itself.

# standardize y pipeline
std_lin_reg=TransformedTargetRegressor(regressor=no_int_pipe, transformer=stdY()) # transforms y, estimates the model, then reverses the transformation for evaluating loss.

#after returning to re-read my answer, there's an even easier solution, use StandardScaler as the transfromer:
std_lin_reg_easy=TransformedTargetRegressor(regressor=no_int_pipe, transformer=StandardScaler())

# generate some simple data
X, y, w = make_regression(n_samples=100,
                          n_features=3, # x variables generated and returned 
                          n_informative=3, # x variables included in the actual model of y
                          effective_rank=3, # make less than n_informative for multicollinearity
                          coef=True,
                          noise=0.1,
                          random_state=0,
                          bias=10)

std_lin_reg.fit(X,y)
print('custom transformer on y and no intercept r2_score: ',std_lin_reg.score(X,y))

std_lin_reg_easy.fit(X,y)
print('standard scaler on y and no intercept r2_score: ',std_lin_reg_easy.score(X,y))

no_int_pipe.fit(X,y)
print('\nonly standard scalar and no intercept r2_score: ',no_int_pipe.score(X,y))

回传

代码语言:javascript
运行
复制
custom transformer on y and no intercept r2_score:  0.9999343800041816

standard scaler on y and no intercept r2_score:  0.9999343800041816

only standard scalar and no intercept r2_score:  0.3319175799267782
票数 1
EN
查看全部 3 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54067474

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档