【机器学习】Feature selection – Part II: linear models and regularization

Selecting good features – Part II: linear models and regularization


在我之前的文章中,我讨论了单变量特征选择,其中每个特征都是根据响应变量独立评估的。另一种流行的方法是利用机器学习模型进行特征排序。许多机器学习模型要么具有一些固有的特征内部排序,要么很容易根据模型的结构生成排序。这适用于回归模型、支持向量机、决策树、随机森林等。

在本文中,我将讨论使用回归模型的系数来选择和解释特征。这是基于这样的思想,即当所有特征都在同一尺度上时,模型中最重要的特征应当具有最高的系数,而与输出变量无关的特征应当具有接近于零的系数值。当数据不是非常嘈杂(或者与特征的数量相比存在大量数据)并且特征是(相对地)独立的时,即使对于简单的线性回归模型,该方法也可以很好地工作:

from sklearn.linear_model import LinearRegression
import numpy as np

np.random.seed(0)
size = 5000

# A dataset with 3 features
X = np.random.normal(0,1,(size,3))
# Y=X0+2*X1+noise
Y=X[:,0]+2*X[:,1]+np.random.normal(0,2,size)
lr=LinearRegression()
lr.fit(X,Y)

# A helper method for pretty-printing linear models
def pretty_print_linear(coefs, names = None, sort = False):
    if names == None:
        names = ["X%s" % x for x in range(len(coefs))]
    lst = zip(coefs, names)
    if sort:
        lst = sorted(lst,  key = lambda x:-np.abs(x[0]))
    return " + ".join("%s * %s" % (round(coef, 3), name)
                                   for coef, name in lst)
 
print("Linear model",pretty_print_linear(lr.coef_))

正如您在本例中看到的,尽管数据中存在相当大的噪声,但模型确实很好地恢复了数据的底层结构。但实际上,这种学习问题特别适合于线性模型:特征和响应变量之间的纯线性关系,特征之间没有相关性

当存在多个(线性)相关特征时(如许多真实生活数据集的情况),模型变得不稳定,这意味着数据的小变化会导致模型的大变化(即系数值),使得模型解释非常困难(所谓的多重共线性问题)。例如,假设我们有数据集,其中数据的“真”模型是Y=X_1+X_2,同时我们观察到\widehat{Y}=X_1+X_2+\varepsilon,其中是噪声。此外,假设X1和X2是线性相关的,使得X_1\approx X_2。理想的学习模型是Y=X_1+X_2。但是根据噪声量_、手头数据量以及X1和X2之间的相关性,它也可以是Y=2X_1(即,仅使用X1作为预测器)或Y=-X_1+3X_2(系数的移位可能恰好在噪声训练集中给出更好的拟合)等。

让我们看看与随机森林示例中相同的相关数据集,其中添加了一些噪声。

from sklearn.linear_model import LinearRegression
 
size = 100
np.random.seed(seed=5)
 
X_seed = np.random.normal(0, 1, size)
X1 = X_seed + np.random.normal(0, .1, size)
X2 = X_seed + np.random.normal(0, .1, size)
X3 = X_seed + np.random.normal(0, .1, size)
  
Y = X1 + X2 + X3 + np.random.normal(0,1, size)
X = np.array([X1, X2, X3]).T
  
lr = LinearRegression()
lr.fit(X,Y)
print("Linear model:", pretty_print_linear(lr.coef_))

系数总和~3,所以我们可以期望学习模型表现良好。另一方面,如果我们以面值来解释系数,那么根据模型X3对输出变量有很强的正向影响,而X1对输出变量有负向影响。实际上,所有特征几乎都与输出变量相关联

同样的方法和关注点也适用于其他类似的线性方法,例如logistic回归。

正则化模型

正则化是一种向模型添加附加约束或惩罚的方法,目的是防止过拟合和改进泛化。代替最小化损失函数E(X,Y),最小化损失函数变成E(X,Y)+\alpha ||\omega ||,其中\omega是模型系数的向量,||·||是典型的L1或L2范数,α是可调的自由参数,指定正则化量(因此α=0意味着非正则化模型)。对于回归模型,两种广泛使用的正则化方法是L1和L2正则化方法,当应用于线性回归时,也称为套索回归和岭回归

L1正则化/Lasso

L1正则化将惩罚\alpha \sum_{i=1}^{n}{|w_i|}添加到损失函数(L1-范数)。由于每个非零系数都增加了惩罚,因此它强制弱特征具有零作为系数。因此,L1正则化产生稀疏解,固有地执行特征选择。

对于回归,Scikit-learning为线性回归提供Lasso,为分类提供L1惩罚的Logistic回归。

让我们在波士顿住房数据集上运行Lasso,该数据集具有良好的α(例如,可以通过网格搜索找到):

from sklearn.linear_model import Lasso
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_boston
  
boston = load_boston()
scaler = StandardScaler()
X = scaler.fit_transform(boston["data"])
Y = boston["target"]
names = boston["feature_names"]
  
lasso = Lasso(alpha=.3)
lasso.fit(X, Y)
  
print("Lasso model: ", pretty_print_linear(lasso.coef_, names, sort = True))

我们看到许多特征具有系数0。如果我们进一步增加α,则解将越来越稀疏,即越来越多的特征将具有0作为系数。

然而,请注意,L1正则化回归以与非正则化线性模型类似的方式是不稳定的,这意味着当数据中有相关特征时,系数(以及因此特征秩)即使在小的数据变化时也可以显著变化。这给我们带来了L2正则化。

L2正则化/岭回归

L2正则化(称为线性回归的岭回归)将L2范数惩罚(\alpha \sum_{i=1}^{n}{w_i^2})添加到损失函数。

由于在罚函数表达式中系数是平方的,因此它与L1范数具有不同的效果,即它迫使系数值更均匀地展开。对于相关的特征,这意味着它们趋向于得到相似的系数。回到Y=X_1+X_2的例子,X1和X2是强相关的,那么对于L1,无论学习模型是Y=1*X_1+1*X_2还是Y=2*X_1+0*X_2,惩罚都是一样的。在这两种情况下,惩罚都是2*\alpha。然而,对于L2,第一模型的惩罚是1^2+1^2=2\alpha,而对于第二模型,惩罚是2^2+0^2=4\alpha

这样做的效果是模型更加稳定(系数对于小的数据变化不像非规则或L1模型那样波动)。因此,虽然L2正则化不像L1那样执行特征选择,但对于特征*解释"更有用:预测特征将得到非零系数,这通常不是L1的情况。

让我们再次看一个具有三个相关特征的例子,用不同的随机种子运行这个例子10次,以强调L2回归的稳定性。

from sklearn.linear_model import Ridge
from sklearn.metrics import r2_score
size = 100
 
#We run the method 10 times with different random seeds
for i in range(10):
    print("Random seed %s" % i)
    np.random.seed(seed=i)
    X_seed = np.random.normal(0, 1, size)
    X1 = X_seed + np.random.normal(0, .1, size)
    X2 = X_seed + np.random.normal(0, .1, size)
    X3 = X_seed + np.random.normal(0, .1, size)
    Y = X1 + X2 + X3 + np.random.normal(0, 1, size)
    X = np.array([X1, X2, X3]).T
 
 
    lr = LinearRegression()
    lr.fit(X,Y)
    print("Linear model:", pretty_print_linear(lr.coef_))
 
    ridge = Ridge(alpha=10)
    ridge.fit(X,Y)
    print("Ridge model:", pretty_print_linear(ridge.coef_))
    print()

Random seed 0
Linear model: 0.728 * X0 + 2.309 * X1 + -0.082 * X2
Ridge model: 0.938 * X0 + 1.059 * X1 + 0.877 * X2

Random seed 1
Linear model: 1.152 * X0 + 2.366 * X1 + -0.599 * X2
Ridge model: 0.984 * X0 + 1.068 * X1 + 0.759 * X2

Random seed 2
Linear model: 0.697 * X0 + 0.322 * X1 + 2.086 * X2
Ridge model: 0.972 * X0 + 0.943 * X1 + 1.085 * X2

Random seed 3
Linear model: 0.287 * X0 + 1.254 * X1 + 1.491 * X2
Ridge model: 0.919 * X0 + 1.005 * X1 + 1.033 * X2

Random seed 4
Linear model: 0.187 * X0 + 0.772 * X1 + 2.189 * X2
Ridge model: 0.964 * X0 + 0.982 * X1 + 1.098 * X2

Random seed 5
Linear model: -1.291 * X0 + 1.591 * X1 + 2.747 * X2
Ridge model: 0.758 * X0 + 1.011 * X1 + 1.139 * X2

Random seed 6
Linear model: 1.199 * X0 + -0.031 * X1 + 1.915 * X2
Ridge model: 1.016 * X0 + 0.89 * X1 + 1.091 * X2

Random seed 7
Linear model: 1.474 * X0 + 1.762 * X1 + -0.151 * X2
Ridge model: 1.018 * X0 + 1.039 * X1 + 0.901 * X2

Random seed 8
Linear model: 0.084 * X0 + 1.88 * X1 + 1.107 * X2
Ridge model: 0.907 * X0 + 1.071 * X1 + 1.008 * X2

Random seed 9
Linear model: 0.714 * X0 + 0.776 * X1 + 1.364 * X2
Ridge model: 0.896 * X0 + 0.903 * X1 + 0.98 * X2

正如您从示例中看到的,对于线性回归,系数可以广泛变化,这取决于生成的数据。然而,对于L2正则化模型,系数相当稳定并且紧密地反映数据是如何生成的(所有系数接近1)

总结

正则化线性模型是一组用于特征解释和选择的强大工具。Lasso产生稀疏的解决方案,因此选择强大的特征子集对提高模型性能非常有用。另一方面,岭回归由于其稳定性和有用的特征往往具有非零系数,可用于数据解释。由于响应变量与特征之间的关系常常是非线性的,所以basis-expansion可以用来将特征转换为更合适的空间,同时保持简单的线性模型完全适用。

接下来:选择好的特性,第三部分:基于树的方法。

原文链接:http://blog.datadive.net/selecting-good-features-part-ii-linear-models-and-regularization/

猜你喜欢

转载自blog.csdn.net/ARPOSPF/article/details/85016009