特征工程
從數據中抽取出來的對預測結果有用的信息,通過專業的技巧進行數據處理,是的特征能在機器學習算法中發揮更好的作用。優質的特征往往描述了數據的固有結構。 最初的原始特征數據集可能太大,或者信息冗余,因此在機器學習的應用中,一個初始步驟就是選擇特征的子集,或構建一套新的特征集,減少功能來促進算法的學習,提高泛化能力和可解釋性。
特征工程是將原始數據轉換為更好地代表預測模型的潛在問題的特征的過程,從而提高了對未知數據的模型准確性。
特征工程的意義:
- 更好的特征意味着更強的魯棒性
- 更好的特征意味着只需用簡單模型
- 更好的特征意味着更好的結果
特征處理:
特征工程中最重要的一個環節就是特征處理,特征處理包含了很多具體的專業技巧
- 特征預處理
- 單個特征
- 歸一化
- 標准化
- 缺失值
- 多個特征
- 降維
- PCA
- 降維
- 單個特征
特征工程之特征抽取與特征選擇:
如果說特征處理其實就是在對已有的數據進行運算達到我們目標的數據標准。特征抽取則是將任意數據格式(例如文本和圖像)轉換為機器學習的數字特征。而特征選擇是在已有的特征中選擇更好的特征。后面會詳細介紹特征選擇主要區別於降維。
安裝Scikit-learn機器學習庫:
創建一個基於Python3的虛擬環境:
mkvirtualenv -p /usr/local/bin/python3.6 ml3
在ubuntu的虛擬環境當中運行以下命令
pip3 install Scikit-learn
數據的特征抽取
現實世界中多數特征都不是連續變量,比如分類、文字、圖像等,為了對非連續變量做特征表述,需要對這些特征做數學化表述,因此就用到了特征提取. sklearn.feature_extraction提供了特征提取的很多方法
字典特征抽取
sklearn.feature_extraction.DictVectorizer(sparse = True)
將映射列表轉換為Numpy數組或scipy.sparse矩陣
- sparse 是否轉換為scipy.sparse矩陣表示,默認開啟
方法:
fit_transform(X,y):應用並轉化映射列表X,y為目標類型
inverse_transform(X[, dict_type]):將Numpy數組或scipy.sparse矩陣轉換為映射列表
from sklearn.feature_extraction import DictVectorizer
# 字典特征抽取
d = DictVectorizer()
data = d.fit_transform([{'city': '北京', 'temperature': 100}, {'city': '上海', 'temperature': 60},
{'city': '深圳', 'temperature': 30}])
# 獲取特征名稱
print(d.get_feature_names())
print(d.inverse_transform(data))
# 特征結果數據
print(data)
輸出結果:
['city=上海', 'city=北京', 'city=深圳', 'temperature']
[{'city=北京': 1.0, 'temperature': 100.0}, {'city=上海': 1.0, 'temperature': 60.0}, {'city=深圳': 1.0, 'temperature': 30.0}]
(0, 1) 1.0
(0, 3) 100.0
(1, 0) 1.0
(1, 3) 60.0
(2, 2) 1.0
(2, 3) 30.0
如果按照數值來表示字典(例如1表示上海,2表示北京,3表示深圳),可能會對結果有較大的影響,上面的結果使用的是one-hot編碼,如下:
北京 | 上海 | 深圳 | temperature | |
---|---|---|---|---|
0 | 0 | 1 | 0 | 100.0 |
1 | 1 | 0 | 0 | 60.0 |
2 | 0 | 0 | 1 | 30.0 |
文本特征抽取
文本的特征提取應用於很多方面,比如說文檔分類、垃圾郵件分類和新聞分類。那么文本分類是通過詞是否存在、以及詞的概率(重要性)來表示。
(1)文檔的中詞的出現次數:
數值為1表示詞表中的這個詞出現,為0表示未出現
sklearn.feature_extraction.text.CountVectorizer():將文本文檔的集合轉換為計數矩陣(scipy.sparse matrices)
方法:fit_transform(raw_documents,y)
學習詞匯詞典並返回詞匯文檔矩陣
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()
data = cv.fit_transform(["life is short,i like python",
"life is too long,i dislike python"])
print(cv.get_feature_names())
print(data)
輸出結果:
['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']
(0, 5) 1
(0, 3) 1
(0, 6) 1
(0, 1) 1
(0, 2) 1
(1, 0) 1
(1, 4) 1
(1, 7) 1
(1, 5) 1
(1, 1) 1
(1, 2) 1
對於中文文本進行特征抽取結果不理想,從下面的結果可以看出對於中文,只用逗號分隔符進行了分隔。對於中文應該先使用分詞器進行分詞,然后再使用分隔符進行連接就行了。
from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()
data = cv.fit_transform(["人生苦短,我喜歡python",
"人生太長,我不用python"])
print(cv.get_feature_names())
print(data)
輸出結果:
['人生太長', '人生苦短', '我不喜歡python', '我不用python']
(0, 3) 1
(0, 1) 1
(1, 2) 1
(1, 0) 1
使用中文分詞器來處理
from sklearn.feature_extraction.text import CountVectorizer
import jieba
cv = CountVectorizer()
content = ["人生苦短,我喜歡python", "人生太長,我不用python"]
content = [" ".join(list(jieba.cut(i, cut_all=True))) for i in content]
data = cv.fit_transform(content)
print(cv.get_feature_names())
print(data)
輸出結果:
['python', '不用', '人生', '喜歡', '太長', '苦短']
(0, 0) 1
(0, 3) 1
(0, 5) 1
(0, 2) 1
(1, 1) 1
(1, 4) 1
(1, 0) 1
(1, 2) 1
(2)TF-IDF表示詞的重要性:
TF-IDF的主要思想是:如果某個詞或短語在一篇文章中出現的概率高,並且在其他文章中很少出現,則認為此詞或者短語具有很好的類別區分能力,適合用來分類。
TF-IDF作用:用以評估一字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。
TfidfVectorizer會根據指定的公式將文檔中的詞轉換為概率表示。
sklearn.feature_extraction.text.TfidfVectorizer()
方法:fit_transform(raw_documents,y),學習詞匯和idf,返回術語文檔矩陣。
from sklearn.feature_extraction.text import TfidfVectorizer
content = ["life is short,i like python","life is too long,i dislike python"]
vectorizer = TfidfVectorizer(stop_words='english')
print(vectorizer.fit_transform(content).toarray())
print(vectorizer.vocabulary_)
數據的特征預處理
特征處理是通過特定的統計方法(數學方法)將數據轉換成算法要求的數據。
歸一化
歸一化首先在特征(維度)非常多的時候,可以防止某一維或某幾維對數據影響過大,也是為了把不同來源的數據統一到一個參考區間下,這樣比較起來才有意義,其次可以程序可以運行更快。
特點:通過對原始數據進行變換把數據映射到(默認為[0,1])之間
注:作用於每一列,max為一列的最大值,min為一列的最小值,那么X’’為最終結果,mx,mi分別為指定區間值默認mx為1,mi為0。
MinMaxScalar(feature_range=(0, 1)
- 每個特征縮放到給定范圍(默認[0,1])
- 方法:fit_transform(X)
- X:numpy array格式的數據[n_samples,n_features]
- 返回值:轉換后的形狀相同的array
from sklearn.preprocessing import MinMaxScaler
mm = MinMaxScaler(feature_range=(0, 1))
data = mm.fit_transform([[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]])
print(data)
輸出結果:
[[1. 0. 0. 0. ]
[0. 1. 1. 0.83333333]
[0.5 0.5 0.6 1. ]]
注意在特定場景下最大值最小值是變化的,另外,最大值與最小值非常容易受異常點影響,所以這種方法魯棒性較差,只適合傳統精確小數據場景。
標准化
通過對原始數據進行變換把數據變換到均值為0,方差為1范圍內。
公式:
注:作用於每一列,mean為平均值,σ為標准差(考慮數據的穩定性)
std為方差,
對於歸一化來說:如果出現異常點,影響了最大值和最小值,那么結果顯然 會發生改變。對於標准化來說,如果出現異常點,由於具有一定數據量,少量的異常點對於平均值的影響並不大,從而方差改變較小。
StandardScaler(...):
- 處理之后每列來說所有數據都聚集在均值0附近方差為1
- StandardScaler.fit_transform(X,y)
- X:numpy array格式的數據[n_samples,n_features]
- 返回值:轉換后的形狀相同的array
from sklearn.preprocessing import StandardScaler
s = StandardScaler()
data = s.fit_transform([[1., -1., 3.], [2., 4., 2.], [4., 6., -1.]])
print(data)
輸出結果:
[[-1.06904497 -1.35873244 0.98058068]
[-0.26726124 0.33968311 0.39223227]
[ 1.33630621 1.01904933 -1.37281295]]
缺失值處理
由於各種原因,許多現實世界的數據集包含缺少的值,通常編碼為空白,NaN或其他占位符。然而,這樣的數據集與scikit的分類器不兼容,它們假設數組中的所有值都是數字,並且都具有和保持含義。使用不完整數據集的基本策略是丟棄包含缺失值的整個行和/或列。然而,這是以丟失可能是有價值的數據(即使不完整)的代價。更好的策略是估算缺失值,即從已知部分的數據中推斷它們。
填充缺失值 使用sklearn.preprocessing中的Imputer類進行數據的填充
from sklearn.preprocessing import Imputer
import numpy as np
im = Imputer(missing_values="NaN", strategy="mean", axis=0)
data = im.fit_transform([[1, 2], [np.nan, 4], [5, np.nan]])
print(data)
輸出結果:
[[1. 2.]
[3. 4.]
[5. 3.]]
特征選擇
特征選擇就是單純地從提取到的所有特征中選擇部分特征作為訓練集特征,特征在選擇前和選擇后可以改變值、也不改變值,但是選擇后的特征維數肯定比選擇前小,畢竟我們只選擇了其中的一部分特征。
特征選擇的原因:
-
冗余:部分特征的相關度高,容易消耗計算性能
-
噪聲:部分特征對預測結果有負影響
降維本質上是從一個維度空間映射到另一個維度空間,特征的多少並沒有減少,當然在映射的過程中特征值也會相應的變化。舉個例子,現在的特征是1000維,我們想要把它降到500維。降維的過程就是找個一個從1000維映射到500維的映射關系。原始數據中的1000個特征,每一個都對應着降維后的500維空間中的一個值。假設原始特征中有個特征的值是9,那么降維后對應的值可能是3。而對於特征選擇來說,有很多方法:
- Filter(過濾式):VarianceThreshold
- Embedded(嵌入式):正則化、決策樹
- Wrapper(包裹式)
其中過濾式的特征選擇后,數據本身不變,而數據的維度減少。而嵌入式的特征選擇方法也會改變數據的值,維度也改變。Embedded方式是一種自動學習的特征選擇方法,后面講到具體的方法的時候就能理解了。
特征選擇主要有兩個功能:
(1)減少特征數量,降維,使模型泛化能力更強,減少過擬合
(2)增強特征和特征值之間的理解
sklearn特征選擇API:sklearn.feature_selection.VarianceThreshold
刪除所有低方差特征:VarianceThreshold(threshold = 0.0)
方法:VarianceThreshold.fit_transform(X,y)
- X:numpy array格式的數據[n_samples,n_features]
- 返回值:訓練集差異低於threshold的特征將被刪除。
- 默認值是保留所有非零方差特征,即刪除所有樣本中具有相同值的特征。
from sklearn.feature_selection import VarianceThreshold
var = VarianceThreshold(threshold=1.0)
data = var.fit_transform([[0, 2, 0, 3], [0, 1, 4, 3], [0, 1, 1, 3]])
print(data)
輸出結果:
[[0]
[4]
[1]]
降緯
PCA(Principal component analysis),主成分分析。特點是保存數據集中對方差影響最大的那些特征,PCA極其容易受到數據中特征范圍影響,所以在運用PCA前一定要做特征標准化,這樣才能保證每維度特征的重要性等同。
本質:PCA是一種分析、簡化數據集的技術
目的:是數據維數壓縮,盡可能降低原數據的維數(復雜度),損失少量信息。
作用:可以削減回歸分析或者聚類分析中特征的數量
PCA語法:
PCA(n_components=None)
- 將數據分解為較低維數空間
- PCA.fit_transform(X)
- X:numpy array格式的數據[n_samples,n_features]
- 返回值:轉換后指定維度的array
from sklearn.decomposition import PCA
pca = PCA(n_components=0.9)
data = pca.fit_transform([[2, 8, 4, 5], [6, 3, 0, 8], [5, 4, 9, 1]])
print(data)
輸出結果:
[[ 1.28620952e-15 3.82970843e+00]
[ 5.74456265e+00 -1.91485422e+00]
[-5.74456265e+00 -1.91485422e+00]]