Сравнение результатов StandardScaler и нормализатора в линейной регрессии - PullRequest
0 голосов
/ 07 января 2019

Я работаю над некоторыми примерами линейной регрессии при различных сценариях, сравнивая результаты использования Normalizer и StandardScaler, и результаты озадачивают.

Я использую набор данных для бостонского корпуса и подготавливаю его следующим образом:

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=True против использования Normalizer
  • Инициализация линейной регрессии с помощью параметра fit_intercept = False со стандартизацией и без нее.

В совокупности я нахожу результаты запутанными

Вот как я все настраиваю:

# 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)

Затем я создал 3 отдельных кадра данных, чтобы сравнить R_score, значения коэффициентов и прогнозы для каждой модели.

Чтобы создать фрейм данных для сравнения значений коэффициентов для каждой модели, я сделал следующее:

#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]
})

Вот как я создал фрейм данных для сравнения значений R ^ 2 для каждой модели:

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)
)

Наконец, вот кадр данных, который сравнивает прогнозы для каждого:

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)))

Вот результирующие кадры данных:

КОЭФФИЦИЕНТЫ: Dataframe comparing the coefficients from different models

СЧЕТ: Dataframe comparing the R^2 values from different models

ПРОГНОЗ: Dataframe comparing the prediction values from different models

У меня есть три вопроса, которые я не могу решить:

  1. Почему нет абсолютно никакой разницы между первыми двумя моделями? Похоже, что установка normalize=False ничего не делает. Я могу понять, что прогнозы и значения R ^ 2 одинаковы, но у моих функций разные числовые масштабы, поэтому я не уверен, почему нормализация не будет иметь никакого эффекта. Это вдвойне запутанно, если учесть, что использование StandardScaler значительно меняет коэффициенты.
  2. Я не понимаю, почему модель, использующая Normalizer, вызывает такие радикально отличающиеся значения коэффициентов от других, особенно когда модель с LinearRegression(normalize=True) не меняет вообще.

Если вы посмотрите на документацию по каждому из них, похоже, что они очень похожи, если не идентичны.

Из документов по sklearn.linear_model.LinearRegression () :

normalize: логический, необязательный, по умолчанию False

Этот параметр игнорируется, если для fit_intercept задано значение False. Если True, регрессоры X будут нормализованы до регрессии путем вычитания среднего значения и деления на l2-норму.

Между тем, документы по sklearn.preprocessing.Normalizer утверждают, что по умолчанию она нормализуется до уровня l2 .

Я не вижу разницы между тем, что делают эти два варианта, и я не понимаю, почему у одного были бы такие радикальные отличия в значениях коэффициента от другого.

  1. Результаты модели, использующей StandardScaler, мне соответствуют, но я не понимаю, почему модель, использующая StandardScaler и настройку set_intercept=False, работает так плохо.

Из документов модуля Линейная регрессия :

fit_intercept: логический, необязательный, по умолчанию True

рассчитывать ли перехват для этой модели. Если установлено значение False, нет
перехват будет использоваться в расчетах (например, ожидается, что данные уже будут
по центру).

StandardScaler центрирует ваши данные, поэтому я не понимаю, почему использование его с fit_intercept=False дает несогласованные результаты.

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Ответ на вопрос 1

Я предполагаю, что вы имеете в виду первые две модели reg1 и reg2. Дайте нам знать, если это не так.

Линейная регрессия имеет такую ​​же прогностическую силу, если вы нормализуете данные или нет. Следовательно, использование normalize=True не влияет на прогнозы. Один из способов понять это - увидеть, что нормализация (по столбцам) - это линейная операция над каждым из столбцов ((x-a)/b), и линейные преобразования данных по линейной регрессии не влияют на оценку коэффициента, а только изменяют их значения. Обратите внимание, что это утверждение не верно для Lasso / Ridge / ElasticNet.

Итак, почему коэффициенты не отличаются? Ну, normalize=True также принимает во внимание, что обычно пользователь хочет получить коэффициенты на исходные характеристики, а не нормализованные функции. Как таковой, он корректирует коэффициенты. Один из способов проверить, имеет ли это смысл, - использовать более простой пример:

# two features, normal distributed with sigma=10
x1 = np.random.normal(0, 10, size=100)
x2 = np.random.normal(0, 10, size=100)

# y is related to each of them plus some noise
y = 3 + 2*x1 + 1*x2 + np.random.normal(0, 1, size=100)

X = np.array([x1, x2]).T  # X has two columns

reg1 = LinearRegression().fit(X, y)
reg2 = LinearRegression(normalize=True).fit(X, y)

# check that coefficients are the same and equal to [2,1]
np.testing.assert_allclose(reg1.coef_, reg2.coef_) 
np.testing.assert_allclose(reg1.coef_, np.array([2, 1]), rtol=0.01)

Что подтверждает, что оба метода правильно фиксируют реальный сигнал между [x1, x2] и y, а именно 2 и 1. соответственно.

Ответ на вопрос 2

Normalizer не то, что вы ожидаете. Он нормализует каждый ряд по строкам. Таким образом, результаты резко изменятся и, вероятно, разрушат отношения между объектами и целью, которых вы хотите избежать, за исключением особых случаев (например, TF-IDF).

Чтобы увидеть, как, предположим, приведенный выше пример, но рассмотрим другую функцию, x3, которая не связана с y. Использование Normalizer приводит к изменению x1 на значение x3, уменьшая прочность его отношения с y.

Расхождение коэффициентов между моделями (1,2) и (4,5)

Несоответствие между коэффициентами заключается в том, что при стандартизации перед подгонкой коэффициенты будут соответствовать стандартизированным признакам, то есть коэффициентам, которые я указывал в первой части ответа. Они могут быть сопоставлены с исходными параметрами, используя reg4.coef_ / scaler.scale_:

x1 = np.random.normal(0, 10, size=100)
x2 = np.random.normal(0, 10, size=100)
y = 3 + 2*x1 + 1*x2 + np.random.normal(0, 1, size=100)
X = np.array([x1, x2]).T

reg1 = LinearRegression().fit(X, y)
reg2 = LinearRegression(normalize=True).fit(X, y)
scaler = StandardScaler()
reg4 = LinearRegression().fit(scaler.fit_transform(X), y)

np.testing.assert_allclose(reg1.coef_, reg2.coef_) 
np.testing.assert_allclose(reg1.coef_, np.array([2, 1]), rtol=0.01)

# here
coefficients = reg4.coef_ / scaler.scale_
np.testing.assert_allclose(coefficients, np.array([2, 1]), rtol=0.01)

Это связано с тем, что математически, установив z = (x - mu)/sigma, модель reg4 решает y = a1*z1 + a2*z2 + a0. Мы можем восстановить связь между y и x с помощью простой алгебры: y = a1*[(x1 - mu1)/sigma1] + a2*[(x2 - mu2)/sigma2] + a0, которую можно упростить до y = (a1/sigma1)*x1 + (a2/sigma2)*x2 + (a0 - a1*mu1/sigma1 - a2*mu2/sigma2).

reg4.coef_ / scaler.scale_ представляет [a1/sigma1, a2/sigma2] в приведенных выше обозначениях, что именно то, что normalize=True делает, чтобы гарантировать, что коэффициенты одинаковы.

Расхождение балла модели 5.

Стандартизированные функции имеют нулевое среднее значение, но целевая переменная не обязательно. Следовательно, отсутствие соответствия перехвату приводит к тому, что модель игнорирует среднее значение цели. В примере, который я использовал, «3» в y = 3 + ... не подходит, что, естественно, уменьшает предсказательную силу модели. :)

0 голосов
/ 10 января 2019
  1. Причиной отсутствия различий в коэффициентах между первыми двумя моделями является то, что Sklearn отменяет нормализацию коэффициентов за кулисами после расчета коэффициентов на основе нормализованных входных данных. Ссылка

Эта ненормализация была сделана так, чтобы любые тестовые данные мы могли напрямую применить коэффицентам. и получить прогноз с нормализацией тестовых данных.

Следовательно, настройка normalize=True оказывает влияние на коэффициенты, но в любом случае они не влияют на линию наилучшего соответствия.

  1. Normalizer выполняет нормализацию по каждому образцу (имеется в виду по строкам). Вы видите код ссылки здесь .

Из документации:

Нормализация образцов индивидуально в единицу нормы

, тогда как normalize=True выполняет нормализацию по каждому столбцу / элементу. Ссылка

Пример, чтобы понять влияние нормализации на разные измерения данных. Давайте возьмем два измерения x1 & x2 и y будет целевой переменной. Значение целевой переменной имеет цветовую кодировку на рисунке.

import matplotlib.pyplot as plt
from sklearn.preprocessing import Normalizer,StandardScaler
from sklearn.preprocessing.data import normalize

n=50
x1 = np.random.normal(0, 2, size=n)
x2 = np.random.normal(0, 2, size=n)
noise = np.random.normal(0, 1, size=n)
y = 5 + 0.5*x1 + 2.5*x2 + noise

fig,ax=plt.subplots(1,4,figsize=(20,6))

ax[0].scatter(x1,x2,c=y)
ax[0].set_title('raw_data',size=15)

X = np.column_stack((x1,x2))

column_normalized=normalize(X, axis=0)
ax[1].scatter(column_normalized[:,0],column_normalized[:,1],c=y)
ax[1].set_title('column_normalized data',size=15)

row_normalized=Normalizer().fit_transform(X)
ax[2].scatter(row_normalized[:,0],row_normalized[:,1],c=y)
ax[2].set_title('row_normalized data',size=15)

standardized_data=StandardScaler().fit_transform(X)
ax[3].scatter(standardized_data[:,0],standardized_data[:,1],c=y)
ax[3].set_title('standardized data',size=15)

plt.subplots_adjust(left=0.3, bottom=None, right=0.9, top=None, wspace=0.3, hspace=None)
plt.show()

enter image description here

Вы могли видеть, что линия наилучшего соответствия для данных на рис. 1,2 и 4 будет такой же; означает, что показатель R2_ не изменится из-за нормализации столбца / элемента или стандартизации данных. Только это заканчивается различными эффектами. значения.

Примечание: линия наилучшего соответствия для fig3 будет другой.

  1. Когда вы устанавливаете fit_intercept = False, термин смещения вычитается из прогноза. Значение перехвата установлено равным нулю, что в противном случае было бы средним значением целевой переменной.

Прогноз с перехватом в нуле, как ожидается, будет плохо работать для задач, где целевые переменные не масштабируются (среднее = 0). Вы можете увидеть разницу в 22,532 в каждой строке, что означает влияние выходных данных.

...