1. 程式人生 > >【機器學習】Feature selection – Part II: linear models and regularization

【機器學習】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/