用sklearn实现特征正则化


我们在学习机器学习的时候会经常听到正则化(Regularization),其一般是用于改善或者减少过度拟合问题。
下图是一个回归问题的例子:

第一个模型是一个线性模型,欠拟合,不能很好地适应我们的训练集;第三个模型是一
个四次方的模型,过于强调拟合原始数据,而丢失了算法的本质:预测新数据。我们可以看
出,若给出一个新的值使之预测,它将表现的很差,是过拟合,虽然能非常好地适应我们的
训练集但在新输入变量进行预测时可能会效果不好;而中间的模型似乎最合适。

分类问题中也存在这样的问题:

就以多项式理解,x 的次数越高,拟合的越好,但相应的预测的能力就可能变差。
问题是,如果我们发现了过拟合问题,应该如何处理?

  1. 丢弃一些不能帮助我们正确预测的特征。可以是手工选择保留哪些特征,或者使用一些模型选择的算法来帮忙(例如 PCA)
  2. 正则化。 保留所有的特征,但是减少参数的大小(magnitude)。

在sklearn里实现正则化

X = [[1,-1,2],
     [2,0,0],
     [0,1,-1]]

# 使用L2正则化
from sklearn.preprocessing import normalize
X1 = normalize(X, norm = 'l2')

# 使用L1正则化
from sklearn.preprocessing import Normalizer
normalizer = Normalizer(norm= 'l1')
X2 = normalizer.fit_transform(X)

normalize()参数:

  • X : 需要正则化的特征
  • norm : 设置范数,‘l1’, ‘l2’, 或者’max’, 默认是’l2’
  • return_norm : boolean, 默认False,如果为True将会返回计算后的norm参数

正则化的结果如图:

 

 






 

L1正则化/Lasso

L1正则化将系数w的l1范数作为惩罚项加到损失函数上,由于正则项非零,这就迫使那些弱的特征所对应的系数变成0。因此L1正则化往往会使学到的模型很稀疏(系数w经常为0),这个特性使得L1正则化成为一种很好的特征选择方法。

Scikit-learn为线性回归提供了Lasso,为分类提供了L1逻辑回归。

下面的例子在波士顿房价数据上运行了Lasso,其中参数alpha是通过grid search进行优化的。

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。如果继续增加alpha的值,得到的模型就会越来越稀疏,即越来越多的特征系数会变成0。

然而,L1正则化像非正则化线性模型一样也是不稳定的,如果特征集合中具有相关联的特征,当数据发生细微变化时也有可能导致很大的模型差异。

L2正则化/Ridge regression

L2正则化将系数向量的L2范数添加到了损失函数中。由于L2惩罚项中系数是二次方的,这使得L2和L1有着诸多差异,最明显的一点就是,L2正则化会让系数的取值变得平均。对于关联特征,这意味着他们能够获得更相近的对应系数。还是以Y=X1+X2为例,假设X1和X2具有很强的关联,如果用L1正则化,不论学到的模型是Y=X1+X2还是Y=2X1,惩罚都是一样的,都是2alpha。但是对于L2来说,第一个模型的惩罚项是2 alpha,但第二个模型的是4*alpha。可以看出,系数之和为常数时,各系数相等时惩罚是最小的,所以才有了L2会让各个系数趋于相同的特点。

可以看出,L2正则化对于特征选择来说一种稳定的模型,不像L1正则化那样,系数会因为细微的数据变化而波动。所以L2正则化和L1正则化提供的价值是不同的,L2正则化对于特征理解来说更加有用:表示能力强的特征对应的系数是非零。

回过头来看看3个互相关联的特征的例子,分别以10个不同的种子随机初始化运行10次,来观察L1和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,能够反映出数据的内在结构。






#coding:utf-8
from __future__ import division
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import time
start_time = time.time()
import pandas as pd


# 输入训练样本的特征以及目标值,分别存储在变量X_train与y_train之中。
X_train = [[6], [8], [10], [14], [18]]
y_train = [[7], [9], [13], [17.5], [18]]

# 从sklearn.linear_model中导入LinearRegression。
from sklearn.linear_model import LinearRegression
# 使用默认配置初始化线性回归模型。
regressor = LinearRegression()
# 直接以披萨的直径作为特征训练模型。
regressor.fit(X_train, y_train)

# 导入numpy并且重命名为np。
import numpy as np
# 在x轴上从0至25均匀采样100个数据点。
xx = np.linspace(0, 26, 100)
xx = xx.reshape(xx.shape[0], 1)
# 以上述100个数据点作为基准,预测回归直线。
yy = regressor.predict(xx)

# 对回归预测到的直线进行作图。
import matplotlib.pyplot as plt
plt.scatter(X_train, y_train)
plt1, = plt.plot(xx, yy, label="Degree=1")
plt.axis([0, 25, 0, 25])
plt.xlabel('Diameter of Pizza')
plt.ylabel('Price of Pizza')
plt.legend(handles = [plt1])
plt.show()

# 输出线性回归模型在训练样本上的R-squared值。
print 'The R-squared value of Linear Regressor performing on the training data is', regressor.score(X_train, y_train)


# 从sklearn.preproessing中导入多项式特征产生器
from sklearn.preprocessing import PolynomialFeatures
# 使用PolynominalFeatures(degree=2)映射出2次多项式特征,存储在变量X_train_poly2中。
poly2 = PolynomialFeatures(degree=2)
X_train_poly2 = poly2.fit_transform(X_train)

# 以线性回归器为基础,初始化回归模型。尽管特征的维度有提升,但是模型基础仍然是线性模型。
regressor_poly2 = LinearRegression()

# 对2次多项式回归模型进行训练。
regressor_poly2.fit(X_train_poly2, y_train)

# 从新映射绘图用x轴采样数据。
xx_poly2 = poly2.transform(xx)

# 使用2次多项式回归模型对应x轴采样数据进行回归预测。
yy_poly2 = regressor_poly2.predict(xx_poly2)

# 分别对训练数据点、线性回归直线、2次多项式回归曲线进行作图。
plt.scatter(X_train, y_train)

plt1, = plt.plot(xx, yy, label='Degree=1')
plt2, = plt.plot(xx, yy_poly2, label='Degree=2')

plt.axis([0, 25, 0, 25])
plt.xlabel('Diameter of Pizza')
plt.ylabel('Price of Pizza')
plt.legend(handles = [plt1, plt2])
plt.show()

# 输出2次多项式回归模型在训练样本上的R-squared值。
print 'The R-squared value of Polynominal Regressor (Degree=2) performing on the training data is', regressor_poly2.score(X_train_poly2, y_train)




# 从sklearn.preprocessing导入多项式特征生成器。
from sklearn.preprocessing import PolynomialFeatures
# 初始化4次多项式特征生成器。
poly4 = PolynomialFeatures(degree=4)

X_train_poly4 = poly4.fit_transform(X_train)

# 使用默认配置初始化4次多项式回归器。
regressor_poly4 = LinearRegression()
# 对4次多项式回归模型进行训练。
regressor_poly4.fit(X_train_poly4, y_train)

# 从新映射绘图用x轴采样数据。
xx_poly4 = poly4.transform(xx)
# 使用4次多项式回归模型对应x轴采样数据进行回归预测。
yy_poly4 = regressor_poly4.predict(xx_poly4)

# 分别对训练数据点、线性回归直线、2次多项式以及4次多项式回归曲线进行作图。
plt.scatter(X_train, y_train)
plt1, = plt.plot(xx, yy, label='Degree=1')
plt2, = plt.plot(xx, yy_poly2, label='Degree=2')

plt4, = plt.plot(xx, yy_poly4, label='Degree=4')
plt.axis([0, 25, 0, 25])
plt.xlabel('Diameter of Pizza')
plt.ylabel('Price of Pizza')
plt.legend(handles = [plt1, plt2, plt4])
plt.show()

print 'The R-squared value of Polynominal Regressor (Degree=4) performing on the training data is',regressor_poly4.score(X_train_poly4, y_train)





# 准备测试数据。
X_test = [[6], [8], [11], [16]]
y_test = [[8], [12], [15], [18]]
# 使用测试数据对线性回归模型的性能进行评估。
regressor.score(X_test, y_test)

# 使用测试数据对2次多项式回归模型的性能进行评估。
X_test_poly2 = poly2.transform(X_test)
regressor_poly2.score(X_test_poly2, y_test)

# 使用测试数据对4次多项式回归模型的性能进行评估。
X_test_poly4 = poly4.transform(X_test)
regressor_poly4.score(X_test_poly4, y_test)

# 从sklearn.linear_model中导入Lasso。
from sklearn.linear_model import Lasso

# 从使用默认配置初始化Lasso。
lasso_poly4 = Lasso()
# 从使用Lasso对4次多项式特征进行拟合。
lasso_poly4.fit(X_train_poly4, y_train)

# 对Lasso模型在测试样本上的回归性能进行评估。
print lasso_poly4.score(X_test_poly4, y_test)


# 输出Lasso模型的参数列表。
print lasso_poly4.coef_


# 回顾普通4次多项式回归模型过拟合之后的性能。
print regressor_poly4.score(X_test_poly4, y_test)



# 回顾普通4次多项式回归模型的参数列表。
print regressor_poly4.coef_


# 输出上述这些参数的平方和,验证参数之间的巨大差异。
print np.sum(regressor_poly4.coef_ ** 2)

# 从sklearn.linear_model导入Ridge。
from sklearn.linear_model import Ridge
# 使用默认配置初始化Riedge。
ridge_poly4 = Ridge()

# 使用Ridge模型对4次多项式特征进行拟合。
ridge_poly4.fit(X_train_poly4, y_train)

# 输出Ridge模型在测试样本上的回归性能。
print ridge_poly4.score(X_test_poly4, y_test)

# 输出Ridge模型的参数列表,观察参数差异。
print ridge_poly4.coef_

# 计算Ridge模型拟合后参数的平方和。
print np.sum(ridge_poly4.coef_ ** 2)
"D:\Program Files\Python27\python.exe" D:/PycharmProjects/sklearn/模型正则化.py
The R-squared value of Linear Regressor performing on the training data is 0.910001596424
The R-squared value of Polynominal Regressor (Degree=2) performing on the training data is 0.98164216396
The R-squared value of Polynominal Regressor (Degree=4) performing on the training data is 1.0

0.83889268736
[  0.00000000e+00   0.00000000e+00   1.17900534e-01   5.42646770e-05
  -2.23027128e-04]
0.809588079575
[[  0.00000000e+00  -2.51739583e+01   3.68906250e+00  -2.12760417e-01
    4.29687500e-03]]
647.382645692
0.837420175937
[[ 0.         -0.00492536  0.12439632 -0.00046471 -0.00021205]]
0.0154989652035

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM