1.數(shù)據(jù)預處理
概念:數(shù)據(jù)預處理是從數(shù)據(jù)中檢測,糾正或刪除損壞,不準確或不適用模型的記錄的過程
可能面對的問題:
- 數(shù)據(jù)類型不同:比如有的是文字权烧,有的是數(shù)字,有的含時間序列咳蔚,有的連續(xù)豪嚎,有的離散
- 數(shù)據(jù)的質(zhì)量不行:有噪聲,有異常谈火,有缺失侈询,數(shù)據(jù)出錯,量綱不一糯耍,有重復扔字,數(shù)據(jù)是偏態(tài),數(shù)據(jù)量太大或太小
數(shù)據(jù)預處理的目的:讓數(shù)據(jù)使用模型温技,匹配模型的需求
1.1 數(shù)據(jù)無量綱化
數(shù)據(jù)的無量綱化是指將不同規(guī)格的數(shù)據(jù)轉(zhuǎn)換到統(tǒng)一規(guī)格革为,或者講不通分布的數(shù)據(jù)轉(zhuǎn)換到某個特定分布的需求,這種需求統(tǒng)稱為數(shù)據(jù)的無量綱化
1.1.1 數(shù)據(jù)歸一化preprocessing.MinMaxScaler
將數(shù)據(jù)壓縮到指定的范圍,默認為[0,1]舵鳞,也可以通過參數(shù)feature_range
把數(shù)據(jù)壓縮到其他范圍
from sklearn.preprocessing import MinMaxScaler
data = [[-1,2],[-0.5,6],[0,10],[1,18]]
scaler = MinMaxScaler().fit(data) # fit本質(zhì)是生成最大值和最小值
result = scaler.transform(data)
result
#MinMaxScaler().fit_transform(data) 也可以一步到位
array([[0. , 0. ],
[0.25, 0.25],
[0.5 , 0.5 ],
[1. , 1. ]])
通過方法inverse_transform
震檩,可以將歸一化之后的結(jié)果逆轉(zhuǎn)
result_ = inverse_transform(result)
array([[-1. , 2. ],
[-0.5, 6. ],
[ 0. , 10. ],
[ 1. , 18. ]])
通過參數(shù)feature_range
把數(shù)據(jù)壓縮到其他范圍
data = [[-1,2],[-0.5,6],[0,10],[1,18]]
scaler = MinMaxScaler(feature_range=[5,10]) # 通過參數(shù)feature_range把數(shù)據(jù)壓縮到[5,10]
result = scaler.fit_transform(data)
result
array([[ 5. , 5. ],
[ 6.25, 6.25],
[ 7.5 , 7.5 ],
[10. , 10. ]])
1.1.2 數(shù)據(jù)標準化preprocessing.StandardScaler
通過標準化處理,將數(shù)據(jù)為標準正態(tài)分布
from sklearn.preprocessing import StandardScaler
data = [[-1,2],[-0.5,6],[0,10],[1,18]]
scaler = StandardScaler()
scaler = scaler.fit(data) #fit蜓堕,本質(zhì)是生成均值和方差
scaler.mean_ # 返回各列的平均值 array([-0.125, 9. ])
scaler.var_ # 返回各列的方差 array([ 0.546875, 35. ])
result = scaler.transform(data)
result
array([[-1.18321596, -1.18321596],
[-0.50709255, -0.50709255],
[ 0.16903085, 0.16903085],
[ 1.52127766, 1.52127766]])
查看標準化之后的平均值和方差抛虏,看是否符合標準正態(tài)分布
result.mean() # 返回值1.0
result.var() # 返回值0.0
preprocessing.MinMaxScaler
和preprocessing.StandardScaler
的選擇問題
因為preprocessing.MinMaxScaler
對異常值非常敏感,所以在PCA套才,聚類迂猴,邏輯回歸,支持向量機背伴,神經(jīng)網(wǎng)絡(luò)這些算法中沸毁,StandardScaler
往往是最好的選擇
MinMaxScaler
在不涉及距離度量峰髓,梯度,方差息尺,協(xié)方差計算以及數(shù)據(jù)需要被壓縮到特定區(qū)間時使用廣泛携兵。
綜上,可以優(yōu)先選擇StandardScaler
當效果不好時可以考慮選擇MinMaxScaler
1.2 缺失值處理
運用impute.SimpleImpute(missing_values=np.nan,strategy=,fill_value=,copy)
模塊對缺失值進行填充處理
參數(shù) | 含義 |
---|---|
missing_values |
告訴Simpleimpute 缺失值的類型 |
startegy |
用于填補缺失值的策略掷倔,mean ,median ,most_frequent ,constant
|
fill_value |
當參數(shù)strategy=constant 眉孩,可輸入字符串或數(shù)字,表示要填充的值 |
copy |
默認為True 勒葱,將創(chuàng)建特征矩陣的副本浪汪,反之則會將缺失值填補到原本的特征矩陣中去 |
(1)讀取修改之后的帶有缺失數(shù)據(jù)的泰坦尼克號數(shù)據(jù)集
import pandas as pd
df = pd.read_csv('Narrativedata.csv',index_col=0)
df.head()
Age | Sex | Embarked | Survived | |
---|---|---|---|---|
0 | 22.0 | male | S | No |
1 | 38.0 | female | C | Yes |
2 | 26.0 | female | S | Yes |
3 | 35.0 | female | S | Yes |
4 | 35.0 | male | S | No |
(2) 查看數(shù)據(jù)集的情況
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
Age 714 non-null float64
Sex 891 non-null object
Embarked 889 non-null object
Survived 891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
(3)對Age
分別用平均值,0凛虽,中位數(shù)進行缺失值填充
Age = df.loc[:,'Age'].values.reshape(-1,1) # sklearn當中死遭,特征矩陣必須是二維數(shù)組
from sklearn.impute import SimpleImputer
imp_mean = SimpleImputer(missing_values=np.nan,strategy='mean').fit_transform(Age)
imp_median = SimpleImputer(missing_values=np.nan,strategy='median').fit_transform(Age)
imp_0 = SimpleImputer(missing_values=np.nan,strategy='constant',fill_value=0).fit_transform(Age)
imp_mean[:20]
array([[22. ],
[38. ],
[26. ],
[35. ],
[35. ],
[29.69911765],
[54. ],
[ 2. ],
[27. ],
[14. ],
[ 4. ],
[58. ],
[20. ],
[39. ],
[14. ],
[55. ],
[ 2. ],
[29.69911765],
[31. ],
[29.69911765]])
# 在這里我們使用中位數(shù)對Age進行填補,因為mean有小數(shù)凯旋,年齡是沒有小數(shù)的
df.loc[:,'Age'] = imp_median
df.info() # 再次查看數(shù)據(jù)集糕再,可以發(fā)現(xiàn)Age已經(jīng)全部被填充完畢了
<class 'pandas.core.frame.DataFrame'>
Int64Index: 891 entries, 0 to 890
Data columns (total 4 columns):
Age 891 non-null float64
Sex 891 non-null object
Embarked 889 non-null object
Survived 891 non-null object
dtypes: float64(1), object(3)
memory usage: 34.8+ KB
同理使用同樣的方法對Embarked
進行缺失值填充處理
我們也可以直接使用pandas對缺失數(shù)據(jù)進行填充
import pandas as pd
import numpy as np
data = pd.read_csv('Narrativedata.csv',index_col=0)
data.loc[:,'Age'] = data.loc[:,'Age'].fillna(data.loc[:,'Age'].median())
data.dropna(axis=0,inplace=True) # axis=0枉长,在列方向上對行進行操作
1.3 處理分類型特征:編碼與啞變量
1.3.1 編碼
在實際生活中我們所收集到的特征信息绸硕,并不是以數(shù)字表示的勾怒,而是以文字表示的,比如收款方式荒椭,支付寶或者微信谐鼎,學歷,高中趣惠,大學狸棍,碩士,這些文字變量味悄,機器學習是無法fit的草戈,所以在建立模型之前要事先對這些變量進行處理,將文字轉(zhuǎn)化為數(shù)字變量侍瑟,這一過程稱之為編碼唐片,而這些文字本質(zhì)上代表類別,所以具有分類型數(shù)據(jù)的特征
標簽編碼preprocessing.LabelEncoder
from sklearn.preprocessing import LabelEncoder
y = df.iloc[:,-1] # 此處fit的是標簽涨颜,所以可以是一維的
le = LabelEncoder().fit(y) # 實例化導入數(shù)據(jù)
label = le.transform(y) # transform接口調(diào)取結(jié)果
le.classes_ # 通過classes_屬性费韭,查看標簽中究竟有多少類別
#[*set(y)] 也可以直接查看標簽中的不重復類別
array(['No', 'Unknown', 'Yes'], dtype=object)
df.iloc[:,-1] = label #使用編碼后的標簽替換原標簽
df.head()
Age | Sex | Embarked | Survived | |
---|---|---|---|---|
0 | 22.0 | male | S | 0 |
1 | 38.0 | female | C | 2 |
2 | 26.0 | female | S | 2 |
3 | 35.0 | female | S | 2 |
4 | 35.0 | male | S | 0 |
特征編碼preprocessing.OrdinalEncode
from sklearn.preprocessing import OrdinalEncoder
df_ = df.copy()
# 把Sex和Embarked轉(zhuǎn)化為數(shù)值變量
df_.iloc[:,1:3] = OrdinalEncoder().fit_transform(df_.iloc[:,1:3])
df_head()
Age | Sex | Embarked | Survived | |
---|---|---|---|---|
0 | 22.0 | male | 2.0 | 0 |
1 | 38.0 | female | 0.0 | 2 |
2 | 26.0 | female | 2.0 | 2 |
3 | 35.0 | female | 2.0 | 2 |
4 | 35.0 | male | 2.0 | 0 |
獨熱編碼:創(chuàng)建特征啞變量preprocessing.OneHotEncode
- 名義變量:指變量之間沒有完全沒有任何聯(lián)系,相互獨立咐低,比如艙門(S,C,Q)
- 有序變量:變量不是完全獨立揽思,存在一定的順序聯(lián)系袜腥,但是各個取值之間不能進行運算见擦,例如(小學钉汗,初中,高中鲤屡,大學)
- 有距變量:指分類變量之間可以通過運算來相互轉(zhuǎn)換损痰,例如(體重>45kg,>90kg,>135kg)
所以在上面特征編碼的方式里,是存在錯誤的酒来,艙門和性別并不具備可運算關(guān)系卢未,所以我們要運用獨熱編碼,將其轉(zhuǎn)化為啞變量
from sklearn.preprocessing import OneHotEncoder
X = df.iloc[:,1:3]
enc = OneHotEncoder(categories='auto').fit(X)
result = enc.transform(X).toarray()
result
#OneHotEncoder(categories='auti').fit_transform(X).toarray() 代碼一步到位
array([[0., 1., 0., 0., 1.],
[1., 0., 1., 0., 0.],
[1., 0., 0., 0., 1.],
...,
[1., 0., 0., 0., 1.],
[0., 1., 1., 0., 0.],
[0., 1., 0., 1., 0.]])
enc.get_feature_names() # 得到每一列的啞變量名稱
array(['x0_female', 'x0_male', 'x1_C', 'x1_Q', 'x1_S'], dtype=object)
result = pd.DataFrame(result)
df.drop(['Sex','Embarked'],axis=1,inplace=True)
newdata = pd.concat([df,result],axis=1,columns=['Age','Survived','female','male','Embarked_C','Embarked_Q','Embarked_S'])
newdata.head()
Age | Survived | female | male | Embarked_C | Embarked_Q | Embarked_S | |
---|---|---|---|---|---|---|---|
0 | 22.0 | 0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 |
1 | 38.0 | 2 | 1.0 | 0.0 | 1.0 | 0.0 | 0.0 |
2 | 26.0 | 2 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 |
3 | 35.0 | 2 | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 |
4 | 35.0 | 0 | 0.0 | 1.0 | 0.0 | 0.0 | 1.0 |
同樣的標簽也可以做啞變量堰汉,使用的模塊為preprocessing.LabelBinarizer
1.4處理連續(xù)型特征:二值化與分類變量
1.4.1 二值化preprocessing.Binarizer
根據(jù)閾值將數(shù)值二值化(將特征值設(shè)置為0或1),用于處理連續(xù)型變量辽社。大于閾值的值映射為1,而小于或等于閾值的值映射為0翘鸭,默認閾值為0是滴铅,特征中所有的正值為1,負值為0就乓,二值化是對文本計數(shù)數(shù)據(jù)的常見操作汉匙,可以決定僅考慮某種現(xiàn)象的存在與否,還可以用作考慮布爾隨機變量的估計器的預處理步驟
# 將年齡二值化
data_2 = newdata.copy()
from sklearn.preprocessing import Binarizer
x = data_2.loc[:,'Age'].values.reshape(-1,1) # 特征必須是二維的
transformer = Binarizer(threshold=30).fit_transform(x)
transformer
array([[0.],
[1.],
[0.],
[1.],
[1.],
[0.],
[1.],
[0.],
[0.],
……
1.4.2 分類變量preprocessing.KBinsDiscretizer
這是將連續(xù)型變量劃分為分類變量的類生蚁,能夠?qū)⑦B續(xù)型變量排序之后按順序分箱后編碼
參數(shù) | 含義&輸入 |
---|---|
n_bins |
每個特征中分箱的個數(shù)噩翠,默認為5,一次會被運用到所有導入的特征 |
encode |
編碼的方式邦投,默認onehot 啞變量伤锚,返回稀疏矩陣,ordinal 每個特征的每個箱都被編碼為一個整數(shù)尼摹,返回一列是一個特征见芹,每個特征下含有不同整數(shù)編碼的箱的矩陣 |
strategy |
用來定義箱寬的方式,默認quantile 表示等位分箱蠢涝,uniform 表示等寬分箱玄呛,kmeans 表示聚類分箱 |
# 將年齡進行分箱
data_3 = newdata.copy()
x = data_3.loc[:,'Age'].values.reshape(-1,1) # 特征必須是二維的
from sklearn.preprocessing import KBinsDiscretizer
est = KBinsDiscretizer(n_bins=3,encode='ordinal',strategy='quantile')
result = est.fit_transform(x)
set(result.ravel()) # 返回值{0.0, 1.0, 2.0}
# 設(shè)置編碼方式為獨熱編碼
est = KBinsDiscretizer(n_bins=3,encode='onehot',strategy='uniform')
result = est.fit_transform(x).toarray()
set(result.ravel()) # 返回值{0.0, 1.0}
2.特征選擇
特征提取 (feature extraction) |
特征創(chuàng)造 (feature creation) |
特征選取 (feature selection) |
---|---|---|
從圖像,文字和二,聲音等其他非結(jié)構(gòu)化數(shù)據(jù)中提取新信息作為特征 | 把現(xiàn)有特征進行組合徘铝,或相互計算得到新的特征 | 從所有的特征中選出有意義,對模型有幫助的特征惯吕,以避免把所有特征都導入模型取訓練結(jié)果 |
import pandas as pd
data = pd.read_csv('digit recognizor.csv')
x = data.iloc[:,1:]
y = data.iloc[:,0]
x.shape
(42000, 784)
可見x具有相當多的特征惕它,如果將所有的特征都導入矩陣,無疑會給矩陣的運行增加負擔废登,所以我們要事先對齊進行篩選
2.1 Filter過濾法
過濾方法通常做數(shù)據(jù)的預處理步驟淹魄,特征選擇完全獨立于任何機器學習算法,它是根據(jù)各種統(tǒng)計檢驗中的分數(shù)以及相關(guān)性的各項指標來選取特征
類 | 說明 | 超參數(shù)的選擇 |
---|---|---|
VarianceThreshold |
方差過濾堡距,可輸入方差閾值甲锡,返回方差大于閾值的新特征矩陣 | 一般選取閾值為0過濾掉特征值差異小的特征 |
SelectKBest |
用來選取K個統(tǒng)計量結(jié)果最佳的特征兆蕉,生成符合統(tǒng)計量要求的新特征矩陣 | 與卡方檢驗,F(xiàn)檢驗和互信息法配合使用 |
chi2 |
卡方檢驗缤沦,用于分類算法虎韵,捕捉相關(guān)性 | 追求p值小于顯著性水平的特征 |
f_classif |
F檢驗分類,只能捕捉線性相關(guān)缸废,要求數(shù)據(jù)服從正態(tài)分布 | 追求P值小于顯著性水平的特征 |
f_regression |
F檢驗回歸包蓝,只能捕捉線性相關(guān),要求數(shù)據(jù)服從正太分布 | 追求p值小于顯著性水平的特征 |
mutual_info_classif |
互信息分類企量,可以捕捉任何相關(guān)性测萎,不能用于稀疏矩陣 | 追求互信息估計大于0的特征 |
mutual_info_regression |
互信息分類,可以捕捉任何相關(guān)性届巩,不能用于稀疏矩陣 | 追求互信息估計大于0的特征 |
2.1.1 方差過濾VarianceThreshold
通過特征本身的方差來篩選特征的類绳泉,比如一個特征本身的方差很小,就表示樣本在這個特征上基本沒有差異姆泻,可能是特征中的大多數(shù)值都一樣零酪,甚至整個特征的取值都相同,那這個特征對于樣本區(qū)別就沒有作用拇勃,所以要優(yōu)先消除方差為0的特征
VarianceThreshold有重要參數(shù)threshold四苇,表示方差的閾值,表示舍棄所有方差小于閾值的特征方咆,默認為0月腋,即刪除所有記錄都相同的特征
from sklearn.feature_selection import VarianceThreshold
x_var0 = VarianceThreshold().fit_transform(x)
x_var0.shape
(42000, 708)
可以看到,方差過濾之后剩余的特征還有708個瓣赂,比之前的784減少了72個榆骚,如果我們知道我們需要多少個特征,方差也可以直接幫助我們一次性篩選到位煌集,比如我們希望留下一半的特征妓肢,那么我們就把閾值設(shè)定為中位數(shù)
x_median = VarianceThreshold(x.var().median()).fit_transform(x)
x_median.shape
(42000, 392)
可以看到使用中位數(shù)之后,特征值減少了一半
2.1.2方差過濾對模型的影響
使用KNN和隨機森林對方差過濾前后的模型分別進行建模分析苫纤,查看過濾前后的準確度
(1)導入模塊并準備數(shù)據(jù)
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier as KNN
from sklearn.model_selection import cross_val_score
x = data.iloc[:,1:]
y = data.iloc[:,0]
x_median = VarianceThreshold(x.var().median()).fit_transform(x)
(2)KNN方差過濾前
cross_val_score(knn(),x,y,cv=5).mean()
0.9658569700264943
%%timeit #python中的魔法命令碉钠,可以計算運行該cell所需要的時間,運行7次求平均卷拘,會嚴重影響運行時間
cross_val_score(knn(),x,y,cv=5).mean()
33min 58s ± 43.9 s per loop (mean ± std. dev. of 7 runs, 1 lppo each)
(3)KNN方差過濾后
cross_val_score(knn(),x_median,y,cv=5).mean()
0.9659997478150573
%%timeit #python中的魔法命令喊废,可以計算運行該cell所需要的時間,運行7次求平均栗弟,會嚴重影響運行時間
cross_val_score(knn(),x_median,y,cv=5).mean()
20min ± 4min 55s per per loop (mean ± std. dev. of 7 runs, 1 lppo each)
可以看出污筷,對于KNN過濾之后的效果十分明顯,準確率稍有提升乍赫,單平均運行時間減少了10分鐘瓣蛀,特征選擇過后算法的效率上升了1/3
(4)隨機森林方差過濾前
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x,y,cv=5).mean()
0.9380003861799541
%%timeit
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x,y,cv=5).mean()
18.9 s ± 2.2 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
(5)隨機森林方差過濾之后
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x,y,cv=5).mean()
0.9388098166696807
%%timeit
cross_val_score(RandomForestClassifier(n_estimators=10,random_state=0),x_median,y,cv=5).mean()
17.5 s ± 597 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
可以看到方差過濾前后對隨機森林預測的準確率影響不大斤寂,對運行時間的影響也不大
這是因為最近鄰算法KNN,單棵決策樹揪惦,支持向量機SVM,神經(jīng)網(wǎng)絡(luò)罗侯,歸回算法器腋,都需要對所有特征進行遍歷或升維來進行運算,而隨機森林本身就不需要遍歷所有的隨機變量钩杰,只需要選取固定數(shù)量的特征就可以進行建模分析纫塌,所以方差過濾對其影響不大,
過濾法的主要對象讲弄,就是需要遍歷特征或升維的算法們措左,而過濾法的主要目的就是在維持算法表現(xiàn)的前提下,幫助算法們降低運算的成本
2.2 相關(guān)性過濾
2.2.1卡方過濾
卡方過濾是專門針對離散型標簽(分類問題)的相關(guān)過濾避除,卡方檢驗feature_selection.chi2
計算每非負特征和標簽之間的卡方統(tǒng)計量怎披,并依照卡方統(tǒng)計量由高到低的為特征排名,再結(jié)合feature_selection.SelectKBest
這個可以輸入“評分標準”來選出前K個分數(shù)最高的類瓶摆,去除獨立標簽凉逛,即與我們分類目的無關(guān)的標簽
卡方檢驗檢測到某個特征中所有的值都相同,會提示我們進行方差過濾群井,同時卡方計算的是非負標簽状飞,所以我們可以優(yōu)先對標簽進行歸一化處理
from sklearn.ensemble import RandomForestClassifier as rfc
from sklearn.model_selection import cross_val_score
from sklearn.feature_selection import chi2
from sklearn.feature_selection import SelectKBest
# 假設(shè)在這里我們需要300個特征
x_kbest = SelectKBest(chi2,k=300).fit_transform(x_median,y)
x_kbest.shape # 返回值(42000, 300)
cross_val_score(rfc(n_estimators=10,random_state=0),x_kbest,y,cv=5).mean()
0.9333098667649198
我們可以看到,模型的效果降低了书斜,說明我們在設(shè)置k=300時刪除了一些與模型相關(guān)且有效的特征诬辈,可以通過繪制超參數(shù)曲線來找到最佳k值
%matplotlib inline
import matplotlib.pyplot as plt
score = []
for i in range(390,200,-10):
x_kbest = SelectKBest(chi2,k=i).fit_transform(x_median,y)
once = cross_val_score(rfc(n_estimators=10,random_state=0),x_kbest,y,cv=5).mean()
score.append(once)
plt.plot(range(390,200,-10),score)
plt.show()
通過這條曲線,我們可以看到隨著K值得不斷增加荐吉,模型的表現(xiàn)不斷上升焙糟,這說明K越大越好,即數(shù)據(jù)中的特征與標簽均相關(guān)样屠,
卡方檢驗的本質(zhì)是推測兩組數(shù)組之間的差異酬荞,其檢驗的原假設(shè)是“兩組數(shù)據(jù)是相互獨立的”,卡方檢驗返回卡防值和P值兩個統(tǒng)計量瞧哟,一般用p值作為有效性的范圍界定混巧,即當P值小于0.01或0.05時,我們認為兩組數(shù)據(jù)是相關(guān)的勤揩,拒絕原假設(shè)
P值 | <=0.05或0.01 | >=0.05或0.01 |
---|---|---|
數(shù)據(jù)差異 | 差異不是自然形成的 | 差異是很自然的樣本誤差 |
相關(guān)性 | 兩組數(shù)據(jù)是相關(guān)的 | 兩組數(shù)據(jù)是相互獨立的 |
原假設(shè) | 拒絕原假設(shè)接受備擇假設(shè) | 接受原假設(shè) |
從特征工程角度咧党,我們希望選取卡方值很大,p值小于0.05的特征
chivalue,pvalue_chi = chi2(x_median,y)
k = chivalue.shape[0]-(pvalue_chi > 0.05).sum()
k # 返回值392
可以觀察到陨亡,所有特征的p值都是0傍衡,說明對于digit recognizon這個數(shù)據(jù)集來說深员。方差驗證已經(jīng)把所有和標簽無關(guān)的特征剔除掉了,在這種情況下蛙埂,舍棄任何一個特征倦畅,都會舍棄對模型有用信息,從而使模型表現(xiàn)下降
2.2.2 F檢驗
F檢驗绣的,又稱齊方差檢驗叠赐,是用來捕捉每個特征和標簽之間的線性關(guān)系的過濾方法,包含feature_selection.f_classif
F分類檢驗和feature_selection.f_regression
F回歸檢驗
和卡方檢驗相同屡江,這兩個類需要和SelectKBest
連用芭概,F(xiàn)檢驗在數(shù)據(jù)服從正態(tài)分布的時候非常穩(wěn)定,所以在使用F檢驗之前惩嘉,我們可以先對數(shù)據(jù)進行標準正態(tài)化罢洲,然后再進行F檢驗
F檢驗的本質(zhì)是尋找兩組數(shù)據(jù)之間的線性關(guān)系,其原假設(shè)是“數(shù)據(jù)不存在顯著的線性關(guān)系”文黎。它返回F值和p值兩個統(tǒng)計量惹苗。當p值小于0.01或0.05時我們認為兩個變量之間存在線性關(guān)系,即我們要舍棄p值大于0.01或0.05的值
from sklearn.feature_selection import f_classif
F,pvalues_f = f_classif(x_median,y)
k = F.shape[0]-(pvalues_f>0.05).sum()
k # 返回值392
得到的結(jié)果和卡方過濾得到的結(jié)論保持一致耸峭,沒有任何值得特征大于0.01鸽粉,所有的特征都是和標簽相關(guān)的,因此我們不需要相關(guān)性過濾
2.2.3互信息法
互信息是用來捕捉每個特征與標簽之間的任意關(guān)系(包括線性和非線性關(guān)系)的過濾方法抓艳,包含feature_selection.mutual_info_classif
(互信息分類)和feature_selection.mutual_info_regression
(互信息回歸)触机。互信息法返回“每個特征與目標之間的互信息量的估計”玷或,這個估計量在[0,1]之間取值儡首,為0表示兩個變量獨立,為1表示兩個變量完全相關(guān)
from sklearn.feature_selection import mutual_info_classif as MIC
result = MIC(x_median,y)
k = result.shape[0]-sum(result<=0)
k # 返回值392
#X_KBest_mutual = SelectKBest(MIC,k=392).fit_transform(x_median,y)
#cross_val_score(RFC(n_estimators=10,random_state=0),X_KBest_mutual,y,cv=10)
2.3 嵌入法Embedded
嵌入法是一種方算法自己決定使用那些特征的方法偏友,即特征選擇和算法訓練同時進行蔬胯,在使用嵌入法時,先使用某些機器學習的算法和模型進行訓練位他,得到每個特征的權(quán)值系數(shù)氛濒,根據(jù)權(quán)值系數(shù)從大到小選擇特征,這些權(quán)值系數(shù)代表特征對標簽的重要性程度鹅髓,比如決策樹和樹的集成模型中的feature_importances_
屬性舞竿,可以列出各個特征對樹的建立貢獻,因此相對于過濾法窿冯,嵌入法的結(jié)果會更加精確到模型的效用本身骗奖,對于提高模型效力有更好的效果
但是嵌入法返回的是權(quán)值系數(shù),我們無法和卡方檢驗和F檢驗,通過篩選P值的方式來進行篩選执桌,我們并不知道權(quán)值系數(shù)處于一個什么樣的范圍是最好的鄙皇,因此我們可以使用學習曲線的方式來選取最優(yōu)權(quán)值參數(shù)
feature_selection.SelectFromModel(estimator,threshold=None)
SelectModel
是一個元變換器,可以與任何在擬合后具有coef_
,feature_importances_
屬性或參數(shù)中可選懲罰項的評估器一起使用仰挣,比如隨機森林和樹模型就有屬性feature_importances_
伴逸,邏輯回歸就帶有l1
和l2
懲罰項,線性支持向量機也支持l2
懲罰項
參數(shù) | 說明 |
---|---|
estimator |
使用的模型評估器膘壶,只要是帶feature_importances_和coef_的都可以使用 |
threshold |
特征重要性的閾值错蝴,重要性低于這個閾值的特征都將被刪除 |
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.feature_selection import SelectFromModel
RFC_ = RFC(n_estimators=10,random_state=0)
X_embedded = SelectFromModel(RFC_,threshold=0.005).fit_transform(x,y)
X_embedded.shape # 返回值(42000, 47)
可以看到特征數(shù)降為47,但是這樣設(shè)定閾值是不準確的香椎,我們可以通過繪制學習曲線來找到最優(yōu)的閾值
#==========【TIME WARNING:10 MINS】============#
import numpy as pd
import matplotlib.pyplot as plt
RFC_.fit(x,y).feature_importances_
threshold = np.linspace(0,(RFC_.fit(x,y).feature_importances_).max(),20)
score = []
for i in threshold:
X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(x,y)
once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
score.append(once)
plt.figure(figsize=(20,5))
plt.plot(threshold,score)
plt.xticks(threshold)
plt.show()
從圖像上來看,隨著閾值越來越高禽篱,模型的效果越來越差畜伐,被刪除的特征值越來越多,信息損失也越來越大躺率,但是在0.00134之前玛界,模型的效果都可以維持在0.93以上,因此我們可以繼續(xù)選定一個范圍悼吱,細化學習曲線來找到最佳值
score2 = []
for i in np.linspace(0,0.00134,20):
X_embedded = SelectFromModel(RFC_,threshold=i).fit_transform(x,y)
once = cross_val_score(RFC_,X_embedded,y,cv=5).mean()
score2.append(once)
plt.figure(figsize=(20,5))
plt.plot(np.linspace(0,0.00134,20),score2)
plt.xticks(np.linspace(0,0.00134,20))
plt.show()
從圖像上可以看到閾值為0.000564時模型的效果是最好的慎框,我們可以把0.000564帶入模型看一下效果
from sklearn.feature_selection import SelectFromModel
X_embedded = SelectFromModel(RFC_,threshold=0.000564).fit_transform(x,y)
cross_val_score(RFC_,X_embedded,y,cv=5).mean()
0.9408335415056387
可以看到模型的準確率升高為94%點多,因此后添,比起要考慮很多統(tǒng)計量的過濾法來說笨枯,前復發(fā)可能是更有效的一種方法,然而遇西,在算法本身復雜的時候馅精,過濾法的計算量遠遠比嵌入法快,所以在大型數(shù)據(jù)中粱檀,還是要優(yōu)先考慮過濾法
2.4 包裝法Wrapper
包裝法也是特征選擇和算法同時進行的方法洲敢,與嵌入法相同的是包裝法也是通過模型訓練之后的feature_importantances_
或者coef_
來進行特征的選擇,與嵌入法不同的是包裝法不需要我們指定閾值茄蚯,包裝法通過coef_
屬性或feature_importantances_
屬性獲得每個特征的重要性压彭,然后從當前的一組特征中修剪最不重要的特征。在修剪的集合上地柜地重復該過程渗常,直到最終到達所需數(shù)量的要選擇的特征
包裝法是最能保證模型效果的特征選擇方法壮不,但是包裝法要使用特征子集進行多次訓練,所以包裝法需要的計算成本是最高的
feature_selection.RFE(estimator,n_features_to_select=None,step=1,verbose=0)
feature_selection.RFECV(estimator,n_features_to_select=None,step=1,verbose=0,cv=5)
參數(shù)estimator
是需要填寫的實例化后的評估器皱碘,n_features_to_select
是想要選擇的特征個數(shù)忆畅,step
表示每次迭代中希望移除的特征個數(shù)。除此之外,RFE類有兩個很重要的屬性家凯,support_
返回所有的特征的是否最后被選中的布爾矩陣缓醋,以及ranking_
返回特征的按數(shù)次迭代中綜合重要性的排名。類feature_selection.RFECV會在交叉驗證循環(huán)中執(zhí)行RFE以找到最佳數(shù)量的特征绊诲,增加參數(shù)cv送粱,其他用法都和RFE一模一樣。
from sklearn.feature_selection import RFE
RFC_ = RFC(n_estimators=10,random_state=0)
selector = RFE(RFC_,n_features_to_select=50,step=50).fit(x,y)
#selector.support_.sum() support_屬性返回特征選擇的布爾矩陣
#selector.ranking_ ranking_屬性返回特征的按次數(shù)迭代中綜合重要性的排名
X_wrapper = selector.transform(x)
cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
0.9056911999667074
使用超參數(shù)曲線尋找最優(yōu)的特征保留數(shù)目
score =[]
for i in range(1,751,50):
X_wrapper = RFE(RFC_,n_features_to_select=i,step=50).fit_transform(x,y)
once = cross_val_score(RFC_,X_wrapper,y,cv=5).mean()
score.append(once)
plt.figure(figsize=(20,5))
plt.plot(range(1,751,50),score)
plt.xticks(range(1,751,50))
plt.show()
明顯可以看出掂之,在包裝法下抗俄,應用50個特征時,模型的表現(xiàn)就已經(jīng)達到了90%世舰,比嵌入法和過濾法都高效很多动雹,在特征數(shù)相同的情況下,包裝法在效果上匹敵嵌入法跟压,同樣我們也可以進一步細化超參數(shù)曲線來找到最優(yōu)的特征數(shù)胰蝠。