03.11 通過正則化和隨機森林來選擇特徵

一、為什麼要做特徵選擇?

如果一個模型在訓練數據上的表現比在測試數據上要好很多,這就表示這個模型過擬合了。過擬合是指模型的參數對於訓練數據的特定觀測值擬合的非常接近,而訓練數據的分佈於真實數據的分佈並不一致,所以模型具有較高的方差。產生過擬合的原因是因為,對於訓練數據集上的模型過於複雜,通常我們可以通過以下幾種方式來降低過擬合:

1、收集更多的訓練數據

2、通過正則化引入罰項

3、選擇一個參數相對較少的簡單模型

4、降低數據的維度

特徵選擇除了防止模型過擬合降低模型的泛化誤差之外,它還可以減少硬件資源的損耗,降低模型的開發成本,減少訓練的時間。下面我們會介紹通過正則化、隨機森林算法進行特徵選擇。

二、使用L1正則化進行特徵選擇

常用的正則化有L1正則化和L2正則化,L1正則化和L2正則化都是為代價函數添加罰項,不同的是L1正則化增加的罰項是使用權重絕對值的和而L2正則化增加的罰項時權重的平方和。L1正則化生成的是一個稀疏的特徵向量,且大多數的權值為0。如果數據集中包含了許多不相關的特徵,尤其是不相關的特徵數量大於樣本的數量時,通過L1正則化處理之後能降低模型的複雜度。

import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
if __name__ == "__main__":
data = pd.read_csv("G:/dataset/wine.csv")
#將data分為特徵和類標
x,y = data.ix[:,1:],data.ix[:,0]
#對特徵進行標準化處理
std = StandardScaler()
x_std = std.fit_transform(x)
#將數據集分為訓練集和測試集
train_x,test_x,train_y,test_y = train_test_split(x_std,y,test_size=0.3,random_state=1)
#使用L1正則化進行特徵選擇
L1_model = LogisticRegression(penalty="l1",C=0.1)
L1_model.fit(train_x,train_y)
#判斷模型在訓練數據上的準確率
print("training accuracy:",L1_model.score(train_x,train_y))
#判斷模型在測試數據上的準確率
print("test accuracy:",L1_model.score(test_x,test_y))

通過正則化和隨機森林來選擇特徵

通過模型在訓練集和測試集上的準確率可以發現,模型沒有產生過擬合,因為訓練集和測試集的準確率差不多。

1、查看模型的截距

#查看logistic模型的截距
print(L1_model.intercept_)

通過正則化和隨機森林來選擇特徵

2、查看模型的權重係數

#查看模型的權重係數
print(L1_model.coef_)

通過正則化和隨機森林來選擇特徵

因為我們使用的是多類別分類的logistic迴歸,所以它使用一對多(one-vs-Rest,OvR)的方法。第一個權重表示類別1相對於類別2和3的匹配結果,第二個權重表示的是類別2相對於類別1和3的匹配結果,第三個權重表示的是類別3相對於類別1和2的匹配結果。可以發現每一個權重都有13數,其中有很多項的值都為0,這是因為通過L1正則化之後產生的,這13個數表示模型在13個權重上的比重,對應不為0的特徵係數,表示是選擇的特徵。

3、獲取L1正則化所選擇的列名

#獲取特徵的列名,因為第一列表示的酒的類別
data_cols_name = data.columns[1:]
#獲取第一個特徵的係數
coef1 = L1_model.coef_[0]
#獲取一個特徵係數的bool類型的數組,不為0為true
coef1_bool = coef1 != 0
print(data_cols_name[coef1_bool])
#獲取第二個特徵的係數
coef2 = L1_model.coef_[1]
coef2_bool = coef2 != 0
print(data_cols_name[coef2_bool])
#獲取第三個特徵的係數
coef3 = L1_model.coef_[2]
coef3_bool = coef3 != 0
print(data_cols_name[coef3_bool])

通過正則化和隨機森林來選擇特徵

3、參數C對於L1正則化的影響

if __name__ == "__main__":
data = pd.read_csv("G:/dataset/wine.csv")
# 將data分為特徵和類標
x, y = data.ix[:, 1:], data.ix[:, 0]
# 對特徵進行標準化處理
std = StandardScaler()
x_std = std.fit_transform(x)
# 將數據集分為訓練集和測試集
train_x, test_x, train_y, test_y = train_test_split(x_std, y, test_size=0.3, random_state=1)
fig = plt.figure()
ax = plt.figure(111)
colors = ["blue","green","red","cyan",
"magenta","yellow","black","pink",
"lightgreen","lightblue","gray","indigo",
"indigo","organge"]
weights,params = [],[]
for c in np.arange(-4,6):
model = LogisticRegression(penalty="l1",C=float(10)**c,random_state=0)
model.fit(train_x,train_y)
weights.append(model.coef_[1])
params.append(float(10)**c)
weights = np.array(weights)
for column,color in zip(range(weights.shape[1]),colors):
plt.plot(params,weights[:,column],label=data.columns[column+1],color=color)
plt.axhline(0,color="black",linestyle="--",linewidth=3)
plt.xlim([10**(-5),10**5])
plt.ylabel("weight coefficent")
plt.xlabel("C")
plt.xscale("log")
plt.legend(loc="upper left")
plt.show()

通過正則化和隨機森林來選擇特徵

參數C是正則化參數

通過正則化和隨機森林來選擇特徵

的倒數,,當C越小的時候,所有參數的權重都接近0。通過上面的圖,我們可以發現特徵與參數C的變化關係。

三、使用隨機森林判斷特徵的重要性

使用隨機森林來判斷特徵的重要性的時候,不需要考慮特徵是否是線性可分的,也不需要對特徵做歸一化或者標準化處理。通過隨機森林算法之後,可以知道每一個特徵的重要性,特徵的重要性之和為1。

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import matplotlib.pyplot as plt
import numpy as np
if __name__ == "__main__":
data = pd.read_csv("G:/dataset/wine.csv")
#將data分為特徵和類標
x,y = data.ix[:,1:],data.ix[:,0]
#將數據集分為訓練集和測試集
train_x,test_x,train_y,test_y = train_test_split(x,y,test_size=0.3,random_state=1)
#定義一個由10000顆決策樹組成的隨機森林模型
rf_model = RandomForestClassifier(n_estimators=10000,random_state=0,n_jobs=-1)
#訓練
rf_model.fit(train_x,train_y)
#獲取特徵的重要性
importances = rf_model.feature_importances_
#對特徵的重要性進行排序
indices = np.argsort(importances)[::-1]
cols_name = data.columns[1:]
for f in range(train_x.shape[1]):
print("%2d) %-*s %f" % (f + 1,30,cols_name[f],importances[indices[f]]))
plt.title("特徵的重要性")
plt.bar(range(train_x.shape[1]),importances[indices],color="lightblue",align="center")
plt.xticks(range(train_x.shape[1]),cols_name,rotation=90)
plt.xlim([-1,train_x.shape[1]])
plt.show()

通過正則化和隨機森林來選擇特徵

通過正則化和隨機森林來選擇特徵


分享到:


相關文章: