一、特征工程的重要性
有這么一句話在業界廣泛流傳:數據和特征決定了機器學習的上限,而模型和算法只是逼近這個上限而已,在樓主本人親自做的機器學習項目中也發現,不同的機器學習算法對結果的准確率影響有限,好的特征工程以及數據集才影響到了模型本質的結果。那特征工程到底是什么呢?顧名思義,其本質是一項工程活動,目的是最大限度地從原始數據中提取特征以供算法和模型使用。通過總結和歸納,人們認為特征工程包括以下方面:
該圖引用於別人的博客,在文章的最后可以看到參考鏈接。
但根據我個人的理解,這張圖雖然比較全面,但是我認為特征工程的核心工作是一個線性的階段性的過程,而不是圖中描述的很多並行化過程。
特征工程主要有三個主要階段,本文也將從這三個階段講解特征工程:1、特征清洗、數據清洗。2、特征處理、數據處理。3、特征選擇
特征是機器學習系統的原材料,對最終模型的影響是毋庸置疑的。定義:特征工程是將原始數據轉化為特征,更好表示預測模型處理的實際問題,提升對於未知數據的准確性。它是用目標問題所在的特定領域知識或者自動化的方法來生成、提取、刪減或者組合變化得到特征。
數據特征會直接影響你使用的預測模型和實現的預測結果。准備和選擇的特征越好,則實現的結果越好。影響預測結果好壞的因素:模型的選擇、可用的數據、特征的提取。
優質的特征往往描述了數據的固有結構。大多數模型都可以通過數據中良好的結構很好的學習,即使不是最優的模型,優質的特征也可以得到不錯的效果。優質特征的靈活性可以讓你使用簡單的模型運算的更快,更容易理解,更容易維護。優質的特征可以在使用不是最優的模型參數的情況下得到不錯的預測結果,這樣你就不必費力去選擇最適合的模型和最優的參數了。
首先,我們大家都知道,數據特征會直接影響我們模型的預測性能。你可以這么說:“選擇的特征越好,最終得到的性能也就越好”。這句話說得沒錯,但也會給我們造成誤解。事實上,你得到的實驗結果取決於你選擇的模型、獲取的數據以及使用的特征,甚至你問題的形式和你用來評估精度的客觀方法也扮演了一部分。此外,你的實驗結果還受到許多相互依賴的屬性的影響,你需要的是能夠很好地描述你數據內部結構的好特征。
(1)特征越好,靈活性越強
只要特征選得好,即使是一般的模型(或算法)也能獲得很好的性能,因為大多數模型(或算法)在好的數據特征下表現的性能都還不錯。好特征的靈活性在於它允許你選擇不復雜的模型,同時運行速度也更快,也更容易理解和維護。
(2)特征越好,構建的模型越簡單
有了好的特征,即便你的參數不是最優的,你的模型性能也能仍然會表現的很nice,所以你就不需要花太多的時間去尋找最有參數,這大大的降低了模型的復雜度,使模型趨於簡單。
(3)特征越好,模型的性能越出色
顯然,這一點是毫無爭議的,我們進行特征工程的最終目的就是提升模型的性能。
惰性是推動科技發展的動力,很多算法工程也在思考,能不能通過模型的方式來自動的學習和構成特征呢?"所有的想法都會有實現的一天",現在市面上有效的特征構造模型有 FM(Factorization Machine 因子分解機)、深度學習(提取訓練好的模型中隱層作為特征)可以自己學習出一些特征以及特征之間的組合關系,有人使用過主題模型 LDA、word2vec、FM 來作為特征生成的模型,將模型訓練的中間結果,比如 LDA 的主題分布、word2vec 生成的詞向量用於 LR 這樣的線性模型,線上測試效果都非常好。
通過上面的例子我們可以知道特征構造大致思路,也就是從場景目標出發,去找出與之有關的因素。但是在實際場景除了天馬行空想特征之外,還需要對於想出來的特征做一可行性評估:獲取難度、覆蓋度、准確度等,比如笛卡爾積會使得特征維度增加的非常快,會出現大量覆蓋度低的特征,如果把這些覆蓋度低的特征加入到模型中訓練,模型會非常不穩定;然而這一系列的工作就是傳說中的特征工程。
下面從特征工程的多個子問題全方位分析特種工程。
二、特征工程的子問題
通過特征提取,我們能得到未經處理的特征,這時的特征可能有以下問題:
- 不屬於同一量綱:即特征的規格不一樣,不能夠放在一起比較。無量綱化可以解決這一問題。
- 信息冗余:對於某些定量特征,其包含的有效信息為區間划分,例如學習成績,假若只關心“及格”或不“及格”,那么需要將定量的考分,轉換成“1”和“0”表示及格和未及格。二值化可以解決這一問題。
- 定性特征不能直接使用:某些機器學習算法和模型只能接受定量特征的輸入,那么需要將定性特征轉換為定量特征。最簡單的方式是為每一種定性值指定一個定量值,但是這種方式過於靈活,增加了調參的工作。通常使用啞編碼的方式將定性特征轉換為定量特征:假設有N種定性值,則將這一個特征擴展為N種特征,當原始特征值為第i種定性值時,第i個擴展特征賦值為1,其他擴展特征賦值為0。啞編碼的方式相比直接指定的方式,不用增加調參的工作,對於線性模型來說,使用啞編碼后的特征可達到非線性的效果。
- 存在缺失值:缺失值需要補充。
- 信息利用率低:不同的機器學習算法和模型對數據中信息的利用是不同的,之前提到在線性模型中,使用對定性特征啞編碼可以達到非線性的效果。類似地,對定量變量多項式化,或者進行其他的轉換,都能達到非線性的效果。
在模型訓練過程中,我們會對訓練數據集進行抽象、抽取大量特征,這些特征中有離散型特征也有連續型特征。若此時你使用的模型是簡單模型(如LR),那么通常我們會對連續型特征進行離散化操作,然后再對離散的特征,進行one-hot編碼或啞變量編碼。這樣的操作通常會使得我們模型具有較強的非線性能力。
1. 特征清洗、數據清洗
在實際生產環境中,業務數據並非如我們想象那樣完美,可能存在各種問題,比如上報異常、惡意作弊行為、爬蟲抓取等。為了讓模型能夠學到真實的行為規律,我們需要對已經構造的原始特征進行清洗,排除掉臟數據。主要包括一下兩個方面:
1. 結合業務情況進行數據的過濾,例如去除 crawler 抓取,spam,作弊等數據。
2. 異常點檢測,采用異常點檢測算法對樣本進行分析,常用的異常點檢測算法包括
-
- 偏差檢測,例如聚類,最近鄰等。
- 基於統計的異常點檢測算法
例如極差,四分位數間距,均差,標准差等,這種方法適合於挖掘單變量的數值型數據。全距(Range),又稱極差,是用來表示統計資料中的變異量數(measures of variation) ,其最大值與最小值之間的差距;四分位距通常是用來構建箱形圖,以及對概率分布的簡要圖表概述。
-
- 基於距離的異常點檢測算法,
主要通過距離方法來檢測異常點,將數據集中與大多數點之間距離大於某個閾值的點視為異常點,主要使用的距離度量方法有絕對距離 ( 曼哈頓距離 ) 、歐氏距離和馬氏距離等方法。
-
- 基於密度的異常點檢測算法
考察當前點周圍密度,可以發現局部異常點,例如 LOF 算法
2. 特征處理、數據處理
1) 連續型特征
-
歸一化
歸一化有很多好處,比如可以加快梯度下降尋找最優解的速度,可以提升模型的精度,同時也使得特征之間具有可比性,當然所有的事情都是雙面的,經過歸一化處理之后,會損失掉源特征的一些信息,但這個損失相對應帶來的好處我們還是可以接受的。
歸一化可以分為以下三種類型:
- 線性歸一化:
這種歸一化方法比較適用在數值比較集中的情況。這種方法有個缺陷,如果 max 和 min 不穩定,很容易使得歸一化結果不穩定,使得后續使用效果也不穩定。實際使用中可以用經驗常量值來替代 max 和 min。
使用preproccessing庫的MinMaxScaler類對數據進行區間縮放的代碼如下:
from sklearn.preprocessing import MinMaxScaler MinMaxScaler().fit_transform(iris.data)
- 標准化歸一化:
在完全隨機的情況下,我們可以假設我們的數據是符合標准正態分布的,也就是均值為 0,標准差為 1;那么其歸一化函數如下:
from sklearn.preprocessing import StandardScaler #標准化歸一化 StandardScaler().fit_transform(iris.data)
- 非線性歸一化:
在數據分化比較大的場景中,有些數值很大,有些很小。通過一些數學函數,將原始值進行映射。該方法包括 log、指數,正切等。需要根據數據分布的情況,決定非線性函數的曲線,比如 log(V, 2) 還是 log(V, 10) 等。
實際業務中我們可以根據自己對數據的理解進行不同的歸一化方法,下面是手游推薦業務使用到的歸一化函數:
正向特征,特征越大打分越大,例如付費金額
,其中
反向特征,特征越大打分越小,例如首次付費距離當前天數
,其中
匯總特征,取均值,例如活躍天=score/天數
這樣的歸一化為啥會比其他歸一化更好呢!或許數學家們可以從公式上進行推到證明,而我們的理解是,其實每個業務的數據都會有特定的分布,比如完全隨機的時候數據滿足正態分布,那么所選擇的方法必須要符合這種數據分布的特點,一般情況下會根據自己對業務數據的了解,對公式進行調整,但是歸一化的思路還是跟上面提到的一樣的。
-
離散化
離散化可以理解為將連續的特征值轉換為為離散的特征值的過程,也稱為分區或分箱。離散化對於線性模型來說是非常有幫助的,原因是它可以將目標值 Y 與特征值的線性轉為目標值與離散化之后轉化的向量里的每個元素之間的線性關系,這樣向量的每個分量都有一個權重,引入了非線性,提升了模型擬合能力。之前做過實驗,使用同樣的特征,有經過離散化處理的特征訓練出來的模型,會比沒有經過離散化訓練出來的模型效果好 20%以上;現在使用比較多的特征離散化的方法有,等頻離散、等距離散、樹模型離散。
arr = np.random.randn(20) pd.cut(arr , 4)
[(-1.234, -0.551], (-1.234, -0.551], (-0.551, 0.13], (0.81, 1.491], (-1.234, -0.551], ..., (-0.551, 0.13], (-0.551, 0.13], (0.13, 0.81], (0.81, 1.491], (0.81, 1.491]] Length: 20 Categories (4, interval[float64]): [(-1.234, -0.551] < (-0.551, 0.13] < (0.13, 0.81] < (0.81, 1.491]]
arr = np.random.randn(20) pd.cut(arr , [-5,-1,0,1,5])
[(0, 1], (-1, 0], (0, 1], (-1, 0], (0, 1], ..., (-5, -1], (-1, 0], (-5, -1], (0, 1], (-5, -1]] Length: 20 Categories (4, interval[int64]): [(-5, -1] < (-1, 0] < (0, 1] < (1, 5]
2) 離散型特征
一些屬性是類別型而不是數值型,舉一個簡單的例子,由{紅,綠、藍}組成的顏色屬性,最常用的方式是把每個類別屬性轉換成二元屬性,即從{0,1}取一個值。因此基本上增加的屬性等於相應數目的類別,並且對於你數據集中的每個實例,只有一個是1(其他的為0),這也就是獨熱(one-hot)編碼方式(類似於轉換成啞變量)。
如果你不了解這個編碼的話,你可能會覺得分解會增加沒必要的麻煩(因為編碼大量的增加了數據集的維度)。相反,你可能會嘗試將類別屬性轉換成一個標量值,例如顏色屬性可能會用{1,2,3}表示{紅,綠,藍}。這里存在兩個問題:首先,對於一個數學模型,這意味着某種意義上紅色和綠色比和藍色更“相似”(因為|1-3| > |1-2|)。除非你的類別擁有排序的屬性(比如鐵路線上的站),這樣可能會誤導你的模型。然后,可能會導致統計指標(比如均值)無意義,更糟糕的情況是,會誤導你的模型。還是顏色的例子,假如你的數據集包含相同數量的紅色和藍色的實例,但是沒有綠色的,那么顏色的均值可能還是得到2,也就是綠色的意思。
one-hot編碼和dummy編碼是比較像的兩種編碼,兩者的區別是,如果離散型特征有5個屬性,one-hot編碼會生成5個特征,而dummy編碼則生成4個。
from sklearn.preprocessing import OneHotEncoder data = iris.target.reshape((-1,1)) print(data.shape) data = OneHotEncoder().fit_transform(data) print(data.shape)
(150, 1) (150, 3)
3) 時間型特征
時間特征既可以看作是連續型,也可以看作是離散型。
連續型:持續時間(單頁瀏覽時長)、間隔時間(上次購買、點擊離現在的時間)
離散型:哪個時段(0-24),星期幾,工作日/周末/法定假日。
4) 文本型特征
文本型特征常見的處理方法有兩類,第一類采用最普通的詞袋(bag of words)模型,以及在此基礎上加入ngram擴充詞袋,以及使用tfidf加權特征值。第二類是基於Word2vec生成詞向量。
-
詞袋模型
文本數據預處理后,去掉停用詞,剩下的詞組成的list, 在詞庫中的映射稀疏向量,這就是詞袋模型。以下摘自sklearn文檔
-
詞袋模型 + ngram
由於普通的詞袋模型沒有很好的考慮上下文的關系,只把每個單詞當做單個特征來處理,因此就有了ngram改進普通的詞袋模型,普通的詞袋模型是1-gram,兩個單詞為2-gram,以此類推。
-
詞袋模型 + ngram + tfidf加權
原本的詞袋模型其實是表征的詞袋中每一個詞在該文檔中的出現次數 ,但如果這個詞僅在所以樣本中都出現了很多次,該詞的特征值就失去了良好的特征表達能力,因此就出現了tfidf來平衡權值。TFIDF的主要思想是:如果某個詞或短語在一篇文章中出現的頻率TF高,並且在其他文章中很少出現,則認為此詞或者短語具有很好的類別區分能力,適合用來分類。TFIDF實際上是:TF * IDF,TF詞頻(Term Frequency),IDF反文檔頻率(Inverse Document Frequency)。
在一份給定的文件里,詞頻(term frequency,TF)指的是某一個給定的詞語在該文件中出現的頻率。這個數字是對詞數(term count)的歸一化,以防止它偏向長的文件。(同一個詞語在長文件里可能會比短文件有更高的詞數,而不管該詞語重要與否。)對於在某一特定文件里的詞語 來說,它的重要性可表示為:
以上式子中 是該詞
在文件
中的出現次數,而分母則是在文件
中所有字詞的出現次數之和。
逆向文件頻率(inverse document frequency,IDF)是一個詞語普遍重要性的度量。某一特定詞語的IDF,可以由總文件數目除以包含該詞語之文件的數目,再將得到的商取對數得到
,有時候為了防止出現0的情況,會加上平滑
。
-
word2vec
前面提到的基於詞袋的三種特征方法是自然語言處理以前的方法,都是會生成很稀疏的矩陣,而且對表達詞與詞之間的相似性能力有限。而word2vec可以將自然語言中的字詞轉為計算機可以理解的稠密向量(Dense Vector)。Python版的word2vec工具箱:gensim
2013年,Google開源了一款用於詞向量計算的工具——word2vec,引起了工業界和學術界的關注。首先,word2vec可以在百萬數量級的詞典和上億的數據集上進行高效地訓練;其次,該工具得到的訓練結果——詞向量(word embedding),可以很好地度量詞與詞之間的相似性。隨着深度學習(Deep Learning)在自然語言處理中應用的普及,很多人誤以為word2vec是一種深度學習算法。其實word2vec算法的背后是一個淺層神經網絡。另外需要強調的一點是,word2vec是一個計算word vector的開源工具。當我們在說word2vec算法或模型的時候,其實指的是其背后用於計算word vector的CBoW模型和Skip-gram模型。很多人以為word2vec指的是一個算法或模型,這也是一種謬誤。在本文,由於篇幅原因,就不對word2vec做詳細的原理介紹,以后會專門寫一篇介紹Word2vec原理的文章。
5) 統計型特征
當前樣本集的各種統計信息,包括均值、最大值、1分位數、4分位數等。
import pandas as pd
import numpy as np series = pd.Series(np.random.randn(500)) series.describe() count 500.000000 mean -0.063427 std 1.007670 min -3.032698 25% -0.749055 50% 0.001290 75% 0.607432 max 2.900834 dtype: float64
6) 組合特征(交叉特征)
-
簡單特征組合:拼接型
1.user_id&&category: 10001&&女裙,10002&&男士牛仔
2.user_id&&style:10001&&蕾絲,10002&&全棉
實際應用過程中不會直接將用戶id號和商品組合而產生非常稀疏的矩陣,會事先對用戶做一個聚類。
-
模型特征組合:GBDT
GBDT + LR是一套經典的特征組合+訓練的方式,最早由Facebook提出。
思路大概是用先用GBDT訓練模型,由於樹模型是具有很好的解釋性的,從根節點到葉子節點的路徑就是一條特征組合,然后可以將組合特征和原始特征一起訓練。
7) 缺失值處理
在實際業務中,可能會因為各種原因會造成數據的缺失,比如某些用戶年齡、性別、設備這類型的特征無法獲取到,同時線上模型又有使用這些類型的特征,那么缺失了這些特征的用戶在線上打分的時候會出現比較大的偏差;通常會有幾種方式來進行處理:數值型特征可以使用均值或者中位數進行簡單的替換,年齡這類型的特征可以通過關系鏈進行加權打分,當然也可以通過把缺失的全部都歸為一類,用戶默認值來替代。
當然對於新用戶或者新 item 來說其實也是屬於一種缺失值情況,對於這種情況已經屬於領一個非常大的領域,那就是推薦系統的啟動問題。對於冷啟動我問題,現在的做法會從兩個方面着手,一種是通過集體智慧來解決,另外一種是通過網絡模型;第一種方法就是使用協同過濾的思想,與這個新用戶類似的用戶表現來知道新用戶的推薦。第二種利用網絡把 item 周圍信息考慮進去,比如下面會提到的層次平滑,熱傳導模型也可以通過引入基礎屬性到二部圖中,達到解決冷啟動問題。
3. 特征選擇
當數據預處理完成后,我們需要選擇有意義的特征輸入機器學習的算法和模型進行訓練。通常來說,從兩個方面考慮來選擇特征:
- 特征是否發散:如果一個特征不發散,例如方差接近於0,也就是說樣本在這個特征上基本上沒有差異,這個特征對於樣本的區分並沒有什么用。
- 特征與目標的相關性:這點比較顯見,與目標相關性高的特征,應當優選選擇。除方差法外,本文介紹的其他方法均從相關性考慮。
特征選擇的原因是因為特征維度太高,可能出現冗余:部分特征的相關度太高了,消耗計算性能;也可能會出現噪聲:部分特征是對預測結果沒有幫助甚至有負影響。
特征選擇的目的是選擇模型最優特征子集。特征與特征之間多多少少會有一些相互作用,比如有些特征是包含其他特征,有些特征與另一些特征存在相關性的,也有一些特征需要與其他特征組合起來才能起作用,還有一些特征是會存在負相關的,如果只使用正是因為特征之間的這些關系,合理的選擇適合的特征集合對於模型效果有非常大的作用。現有的特征選擇方法可以大體分成三種類型:
- Filter:過濾法,按照發散性或者相關性對各個特征進行評分,設定閾值或者待選擇閾值的個數,選擇特征。
- Wrapper:包裝法,根據目標函數(通常是預測效果評分),每次選擇若干特征,或者排除若干特征。
- Embedded:嵌入法,先使用某些機器學習的算法和模型進行訓練,得到各個特征的權值系數,根據系數從大到小選擇特征。類似於Filter方法,但是是通過訓練來確定特征的優劣。
特征選擇主要有兩個目的:
- 減少特征數量、降維,使模型泛化能力更強,減少過擬合;
- 增強對特征和特征值之間的理解。
1) Filter(過濾法)
這種方法是衡量單個特征值與目標變量也就是樣本 label 值之間的關聯。但這種方法的缺點是沒有考慮到特征之間的關聯,有可能把有用的關聯特征過濾掉。
對於分類問題(y離散),可采用:
卡方檢驗,互信息
對於回歸問題(y連續),可采用:
皮爾森相關系數,最大信息系數
-
互信息和最大信息系數 (Mutual information and maximal information coefficient (MIC)
經典的互信息(互信息為隨機變量X與Y之間的互信息I(X;Y)I(X;Y)為單個事件之間互信息的數學期望)也是評價定性自變量對定性因變量的相關性的,互信息計算公式如下:

互信息直接用於特征選擇其實不是太方便:1、它不屬於度量方式,也沒有辦法歸一化,在不同數據及上的結果無法做比較;2、對於連續變量的計算不是很方便(X和Y都是集合,x,y都是離散的取值),通常變量需要先離散化,而互信息的結果對離散化的方式很敏感。
最大信息系數克服了這兩個問題。它首先尋找一種最優的離散化方式,然后把互信息取值轉換成一種度量方式,取值區間在[0,1]。
from sklearn.feature_selection import SelectKBest from minepy import MINE #由於MINE的設計不是函數式的,定義mic方法將其為函數式的,返回一個二元組,二元組的第2項設置成固定的P值0.5 def mic(x, y): m = MINE() m.compute_score(x, y) return (m.mic(), 0.5) #選擇K個最好的特征,返回特征選擇后的數據 SelectKBest(lambda X, Y: array(map(lambda x:mic(x, Y), X.T)).T, k=2).fit_transform(iris.data, iris.target)
MIC的統計能力遭到了一些質疑 ,當零假設不成立時,MIC的統計就會受到影響。在有的數據集上不存在這個問題,但有的數據集上就存在這個問題。
-
卡方檢驗
經典的卡方檢驗是檢驗定性自變量對定性因變量的相關性。假設自變量有N種取值,因變量有M種取值,考慮自變量等於i且因變量等於j的樣本頻數的觀察值與期望的差距,構建統計量:
from sklearn.datasets import load_iris from sklearn.feature_selection import SelectKBest from sklearn.feature_selection import chi2 iris = load_iris() X, y = iris.data, iris.target X.shape (150, 4) X_new = SelectKBest(chi2, k=2).fit_transform(X, y) X_new.shape (150, 2)
-
Pearson相關系數
皮爾森相關系數是一種最簡單的,能幫助理解特征和響應變量之間關系的方法,該方法衡量的是變量之間的線性相關性,結果的取值區間為[-1,1],-1表示完全的負相關,+1表示完全的正相關,0表示沒有線性相關。
Pearson Correlation速度快、易於計算,經常在拿到數據(經過清洗和特征提取之后的)之后第一時間就執行。Scipy的 pearsonr 方法能夠同時計算 相關系數 和p-value.
import numpy as np from scipy.stats import pearsonr np.random.seed(0) size = 300 x = np.random.normal(0, 1, size) # pearsonr(x, y)的輸入為特征矩陣和目標向量 print("Lower noise", pearsonr(x, x + np.random.normal(0, 1, size))) print("Higher noise", pearsonr(x, x + np.random.normal(0, 10, size))) >>> # 輸出為二元組(sorce, p-value)的數組 Lower noise (0.71824836862138386, 7.3240173129992273e-49) Higher noise (0.057964292079338148, 0.31700993885324746)
-
基於模型的特征排序 (Model based ranking)
這種方法的思路是直接使用你要用的機器學習算法,針對每個單獨的特征和響應變量建立預測模型。假如特征和響應變量之間的關系是非線性的,可以用基於樹的方法(決策樹、隨機森林)、或者擴展的線性模型 等。基於樹的方法比較易於使用,因為他們對非線性關系的建模比較好,並且不需要太多的調試。但要注意過擬合問題,因此樹的深度最好不要太大,再就是運用交叉驗證。
在我之前講解隨機森林模型的博客中介紹了隨機森林的一個重要特性OOB估計,可以在不進行交叉驗證的情況下高效的計算特征對模型的重要程度。
from sklearn.cross_validation import cross_val_score, ShuffleSplit from sklearn.datasets import load_boston from sklearn.ensemble import RandomForestRegressor import numpy as np # Load boston housing dataset as an example boston = load_boston() X = boston["data"] Y = boston["target"] names = boston["feature_names"] rf = RandomForestRegressor(n_estimators=20, max_depth=4) scores = [] # 單獨采用每個特征進行建模,並進行交叉驗證 for i in range(X.shape[1]): score = cross_val_score(rf, X[:, i:i+1], Y, scoring="r2", # 注意X[:, i]和X[:, i:i+1]的區別 cv=ShuffleSplit(len(X), 3, .3)) scores.append((format(np.mean(score), '.3f'), names[i])) print(sorted(scores, reverse=True))
-
方差選擇法
這種方法和前幾種方法不太一樣,前幾種方法是計算單個特征與結果值之間的相關程度從而刪選特征,這種方法僅從特征的統計特性來考慮,沒有考慮和結果值之間的相關度。
假設某特征的特征值只有0和1,並且在所有輸入樣本中,95%的實例的該特征取值都是1,那就可以認為這個特征作用不大。如果100%都是1,那這個特征就沒意義了。當特征值都是離散型變量的時候這種方法才能用,如果是連續型變量,就需要將連續變量離散化之后才能用。而且實際當中,一般不太會有95%以上都取某個值的特征存在,所以這種方法雖然簡單但是不太好用。可以把它作為特征選擇的預處理,先去掉那些取值變化小的特征,然后再從接下來提到的的特征選擇方法中選擇合適的進行進一步的特征選擇。
from sklearn.feature_selection import VarianceThreshold X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]] sel = VarianceThreshold(threshold=(.8 * (1 - .8))) sel.fit_transform(X) array([[0, 1], [1, 0], [0, 0], [1, 1], [1, 0], [1, 1]])
2) Wrapper(包裝法)
Wrapper 這一類特征選擇方法,應該來說是比較科學的,但是也是非常耗時,工業界在生產環境中很少使用,非常耗時,也是一個 NP 復雜的問題,一般通過不斷迭代,然后每次加入一個特征,來訓練模型,使用模型評估比如 AUC 或者 MSE 等函數評估是否將特征加入到特征子集中。
遞歸消除特征法使用一個基模型來進行多輪訓練,每輪訓練后,移除若干權值系數的特征,再基於新的特征集進行下一輪訓練。
sklearn官方解釋:對特征含有權重的預測模型(例如,線性模型對應參數coefficients),RFE通過遞歸減少考察的特征集規模來選擇特征。首先,預測模型在原始特征上訓練,每個特征指定一個權重。之后,那些擁有最小絕對值權重的特征被踢出特征集。如此往復遞歸,直至剩余的特征數量達到所需的特征數量。
RFECV 通過交叉驗證的方式執行RFE,以此來選擇最佳數量的特征:對於一個數量為d的feature的集合,他的所有的子集的個數是2的d次方減1(包含空集)。指定一個外部的學習算法,比如SVM之類的。通過該算法計算所有子集的validation error。選擇error最小的那個子集作為所挑選的特征。
from sklearn.feature_selection import RFE from sklearn.linear_model import LogisticRegression #遞歸特征消除法,返回特征選擇后的數據 #參數estimator為基模型 #參數n_features_to_select為選擇的特征個數 RFE(estimator=LogisticRegression(), n_features_to_select=2).fit_transform(iris.data, iris.target)
3) Embedded(包裝法)
單變量特征選擇方法獨立的衡量每個特征與響應變量之間的關系,另一種主流的特征選擇方法是基於機器學習模型的方法。有些機器學習方法本身就具有對特征進行打分的機制,或者很容易將其運用到特征選擇任務中,例如回歸模型,SVM,決策樹,隨機森林等等。
-
基於懲罰項的特征選擇法
之前我寫的一篇文章對比了L1、L2正則化的區別,L1正則化具有截斷性,L2正則化具有縮放效應,所以我們可以很好的利用線性模型的兩種正則化選擇特征、
使用L1范數作為懲罰項的線性模型(Linear models)會得到稀疏解:大部分特征對應的系數為0。當你希望減少特征的維度以用於其它分類器時,可以通過 feature_selection.SelectFromModel
來選擇不為0的系數。特別指出,常用於此目的的稀疏預測模型有 linear_model.Lasso
(回歸), linear_model.LogisticRegression 和 svm.LinearSVC(分類):
from sklearn.feature_selection import SelectFromModel from sklearn.linear_model import LogisticRegression #帶L1懲罰項的邏輯回歸作為基模型的特征選擇 SelectFromModel(LogisticRegression(penalty="l1", C=0.1)).fit_transform(iris.data, iris.target)
-
基於樹模型的特征選擇法
GBDT在計算每個節點的重要程度時可以同時用來做特征選擇,RF可以用他的OOB估計來評價特征的重要程度
樹模型中GBDT也可用來作為基模型進行特征選擇,使用feature_selection庫的SelectFromModel類結合GBDT模型,來選擇特征的代碼如下:
from sklearn.feature_selection import SelectFromModel from sklearn.ensemble import GradientBoostingClassifier #GBDT作為基模型的特征選擇 SelectFromModel(GradientBoostingClassifier()).fit_transform(iris.data, iris.target)
4. 特征評估
前面寫了很多特征構造和處理的方法,可能更多時間我們更想知道一個特征是否真的靠譜,在時間有限的情況下,用貪心的思想,每次選擇表現最好的特征加入到模型訓練中,這個時候就會特征評估這個東西了,特征評估可能會從幾個維度進行衡量:
1、特征自身的質量
-
- 特征覆蓋度,這個指標是衡量某個特征能夠影響的樣本量,一般情況下,會排查覆蓋度特別低的
- 特征的准確性,也就是說特征值是否考慮,會不會存在太多錯誤數據
- 特征方差,衡量特征是否有區分度,比如 100 個訓練樣本,有 99 個是 0,那么這個特征方差就特別低,肯定有問題。
2、特征與目標值的相關性
-
- 相關系數
- 單特征 AUC
5. 降維
當特征選擇完成后,可以直接訓練模型了,但是可能由於特征矩陣過大,導致計算量大,訓練時間長的問題,因此降低特征矩陣維度也是必不可少的。常見的降維方法除了以上提到的基於L1懲罰項的模型以外,另外還有主成分分析法(PCA)和線性判別分析(LDA),線性判別分析本身也是一個分類模型。PCA和LDA有很多的相似點,其本質是要將原始的樣本映射到維度更低的樣本空間中,但是PCA和LDA的映射目標不一樣:PCA是為了讓映射后的樣本具有最大的發散性;而LDA是為了讓映射后的樣本有最好的分類性能。所以說PCA是一種無監督的降維方法,而LDA是一種有監督的降維方法。
from sklearn.decomposition import PCA #主成分分析法,返回降維后的數據 #參數n_components為主成分數目 PCA(n_components=2).fit_transform(iris.data)
參考鏈接:
https://cloud.tencent.com/developer/article/1005443
http://www.cnblogs.com/jasonfreak/p/5448385.html
https://www.cnblogs.com/lianyingteng/p/7792693.html
http://blog.csdn.net/sangyongjia/article/details/52440063
https://www.cnblogs.com/iloveai/p/word2vec.html
https://www.cnblogs.com/stevenlk/p/6543628.html
寒小陽-特征工程