用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