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)))
_
結果のデータフレームは次のとおりです。
調整できない3つの質問があります。
normalize=False
_を設定しても何も起こらないようです。予測とR ^ 2値が同じであることは理解できますが、機能の数値スケールが異なるため、正規化がまったく影響しない理由がわかりません。 StandardScaler
を使用すると係数が大幅に変化すると考えると、これは二重に混乱します。Normalizer
を使用したモデルが他のモデルとは根本的に異なる係数値を引き起こす理由、特にLinearRegression(normalize=True)
を使用したモデルがまったく変更を行わない場合は、理解できません。それぞれのドキュメントを見ると、同一ではないにせよ非常に似ているように見えます。
sklearn.linear_model.LinearRegression() のドキュメントから:
normalize:ブール値、オプション、デフォルトFalse
このパラメーターは、fit_interceptがFalseに設定されている場合は無視されます。 Trueの場合、リグレッサXは、平均を差し引き、l2-ノルムで割ることにより、回帰前に正規化されます。
一方、_sklearn.preprocessing.Normalizer
_ のドキュメントには、デフォルトでl2ノルムに正規化されていると記載されています 。
これら2つのオプションの機能に違いは見られません。また、なぜ係数値に他のオプションとの根本的な違いがあるのかわかりません。
StandardScaler
を使用したモデルの結果は一貫していますが、StandardScaler
を使用し、_set_intercept=False
_を設定したモデルのパフォーマンスが低い理由がわかりません。線形回帰モジュール のドキュメントから:
fit_intercept:ブール値、オプション、デフォルトTrue
このモデルの切片を計算するかどうか。 Falseに設定すると、いいえ
切片が計算に使用されます(たとえば、データはすでに存在すると予想されます)
centered)。
StandardScaler
はデータを中央揃えにするため、_fit_intercept=False
_で使用すると一貫性のない結果が生成される理由がわかりません。
Sklearn
が背後で係数を非正規化するためです。 参考この非正規化が行われたのは、テストデータの場合、co-effを直接適用できるためです。テストデータを正規化せずに予測を取得します。
したがって、normalize=True
の設定は、係数に影響を与えますが、いずれにしても最適線には影響しません。
Normalizer
は、各サンプルに関する正規化を行います(行単位)。参照コード here が表示されます。サンプルを個別に正規化して単位ノルムにします。
一方、normalize=True
は、各列/機能に関する正規化を行います。 参考
データの異なる次元での正規化の影響を理解するための例。 2つの次元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()
図1、2、4のデータの最適線は同じになることがわかります。列/機能の正規化またはデータの標準化が原因でR2_-scoreが変更されないことを示します。それだけで、最終的には異なるco-effになります。値。
注:fig3
の最適な線は異なります。
予測 インターセプトがゼロの場合、ターゲット変数がスケーリングされていない(平均= 0)場合、問題が発生すると予想されます。すべての行で22.532の違いを確認できます。これは、出力の影響を示しています。
最初の2つのモデルの意味は_reg1
_および_reg2
_であると想定しています。そうでない場合はお知らせください。
データを正規化するかどうかに関係なく、線形回帰は同じ予測力を持ちます。したがって、_normalize=True
_を使用しても予測には影響しません。これを理解する1つの方法は、正規化(列単位)が各列(_(x-a)/b
_)の線形演算であり、線形回帰でのデータの線形変換は係数推定に影響を与えないことを確認することです。値。このステートメントはLasso/Ridge/ElasticNetには当てはまらないことに注意してください。
では、なぜ係数に違いがないのでしょうか?まあ、_normalize=True
_は、ユーザーが通常望むのは正規化された特徴ではなく、元の特徴の係数であることも考慮に入れます。そのため、係数を調整します。これが理にかなっていることを確認する1つの方法は、より簡単な例を使用することです。
_# 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を正しくキャプチャしていることを確認します。
Normalizer
はあなたが期待するものではありません。各行を行ごとに正規化します。そのため、結果は劇的に変化し、特定のケース(TF-IDFなど)を除いて、回避したい機能とターゲット間の関係が破壊される可能性があります。
方法を確認するには、上記の例を想定してください。ただし、y
に関連しない別の機能_x3
_を検討してください。 Normalizer
を使用すると、_x1
_が_x3
_の値によって変更され、y
との関係の強度が低下します。
係数間の不一致は、フィッティングの前に標準化すると、係数は標準化された特徴に関連することになります。これは、回答の最初の部分で参照したのと同じ係数です。これらは、_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 = a1*[(x1 - mu1)/sigma1] + a2*[(x2 - mu2)/sigma2] + a0
を使用してyとxの関係を回復できます。これはy = (a1/sigma1)*x1 + (a2/sigma2)*x2 + (a0 - a1*mu1/sigma1 - a2*mu2/sigma2)
に簡略化できます。
_reg4.coef_ / scaler.scale_
_は、上記の表記法で_[a1/sigma1, a2/sigma2]
_を表します。これは、係数が同じであることを保証するために_normalize=True
_が行うこととまったく同じです。
標準化された特徴は平均がゼロですが、ターゲット変数は必ずしもそうではありません。したがって、切片を近似しないと、モデルはターゲットの平均を無視します。私が使用している例では、_y = 3 + ...
_の「3」は適合していません。これにより、モデルの予測力が自然に低下します。 :)