Lasso sklearn中normalize=True选项的作用是什么?

4 投票
2 回答
13902 浏览
提问于 2025-04-18 08:58

我有一个矩阵,每一列的平均值都是0,标准差是1。

In [67]: x_val.std(axis=0).min()
Out[70]: 0.99999999999999922

In [71]: x_val.std(axis=0).max()
Out[71]: 1.0000000000000007

In [72]: x_val.mean(axis=0).max()
Out[72]: 1.1990408665951691e-16

In [73]: x_val.mean(axis=0).min()
Out[73]: -9.7144514654701197e-17

如果我使用了归一化选项,那么非零系数的数量会发生变化。

In [74]: l = Lasso(alpha=alpha_perc70).fit(x_val, y_val)

In [81]: sum(l.coef_!=0)
Out[83]: 47

In [84]: l2 = Lasso(alpha=alpha_perc70, normalize=True).fit(x_val, y_val)

In [93]: sum(l2.coef_!=0)
Out[95]: 3

我觉得归一化只是把每一列的方差设为1。这让我觉得很奇怪,结果变化这么大。我的数据本来就已经方差为1了。

那么,normalize=T到底是做了什么呢?

2 个回答

0

我觉得最好的答案是错的...

在Lasso回归中,如果你把normalize设置为True,那么每一列的数据都会先被它的L2范数(也就是标准差乘以样本数量的平方根)除一下,然后再进行Lasso回归。这么做的结果是,设计矩阵的数值会变小,而“预期”的系数会变大。系数越大,L1惩罚就越强。因此,这个函数会更加关注L1惩罚,导致更多的特征被压缩到0。最终你会看到更多的稀疏特征(β=0)。

8

这是因为在 sklearn.linear_model.base.center_data 中,关于缩放的概念可能存在不一致。如果 normalize=True,那么它会对设计矩阵的每一列进行归一化,而不是用标准差来处理。值得一提的是,从 sklearn 版本 0.17 开始,normalize=True 这个关键词将会被弃用。

解决方案:不要使用 standardize=True。相反,构建一个 sklearn.pipeline.Pipeline,并在你的 Lasso 对象前面加上一个 sklearn.preprocessing.StandardScaler。这样你就不需要进行初始的缩放了。

请注意,在 sklearn 实现的 Lasso 中,数据损失项是通过 n_samples 来缩放的。因此,得到零解的最小惩罚是 alpha_max = np.abs(X.T.dot(y)).max() / n_samples(当 normalize=False 时)。

[1] 我说是潜在的不一致,因为 normalizenorm 这两个词在语言上是有联系的,所以至少在语言上是一致的 :)

[如果你不想看细节,就到这里停止阅读]

这里有一些可以复制粘贴的代码来重现这个问题

import numpy as np
rng = np.random.RandomState(42)

n_samples, n_features, n_active_vars = 20, 10, 5
X = rng.randn(n_samples, n_features)
X = ((X - X.mean(0)) / X.std(0))

beta = rng.randn(n_features)
beta[rng.permutation(n_features)[:n_active_vars]] = 0.

y = X.dot(beta)

print X.std(0)
print X.mean(0)

from sklearn.linear_model import Lasso

lasso1 = Lasso(alpha=.1)
print lasso1.fit(X, y).coef_

lasso2 = Lasso(alpha=.1, normalize=True)
print lasso2.fit(X, y).coef_

为了理解发生了什么,现在观察到

lasso1.fit(X / np.sqrt(n_samples), y).coef_ / np.sqrt(n_samples)

等于

lasso2.fit(X, y).coef_

因此,对设计矩阵进行缩放,并通过 np.sqrt(n_samples) 适当地重新缩放系数,可以将一个模型转换为另一个模型。这也可以通过对惩罚项进行调整来实现:一个使用 normalize=True 的 Lasso 估计器,如果其惩罚缩小了 np.sqrt(n_samples),就像一个使用 normalize=False 的 Lasso 估计器一样(针对你的数据类型,即已经标准化到 std=1)。

lasso3 = Lasso(alpha=.1 / np.sqrt(n_samples), normalize=True)
print lasso3.fit(X, y).coef_  # yields the same coefficients as lasso1.fit(X, y).coef_

撰写回答