【學習筆記】機器學習之特徵工程
特徵工程
從資料中抽取出來的對預測結果有用的資訊,通過專業的技巧進行資料處理,是的特徵能在機器學習演算法中發揮更好的作用。優質的特徵往往描述了資料的固有結構。 最初的原始特徵資料集可能太大,或者資訊冗餘,因此在機器學習的應用中,一個初始步驟就是選擇特徵的子集,或構建一套新的特徵集,減少功能來促進演算法的學習,提高泛化能力和可解釋性。
特徵工程是將原始資料轉換為更好地代表預測模型的潛在問題的特徵的過程,從而提高了對未知資料的模型準確性。
特徵工程的意義:
- 更好的特徵意味著更強的魯棒性
- 更好的特徵意味著只需用簡單模型
- 更好的特徵意味著更好的結果
特徵處理:
特徵工程中最重要的一個環節就是特徵處理,特徵處理包含了很多具體的專業技巧
- 特徵預處理
- 單個特徵
- 歸一化
- 標準化
- 缺失值
- 多個特徵
- 降維
- 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.50.50.61.]]
注意在特定場景下最大值最小值是變化的,另外,最大值與最小值非常容易受異常點影響,所以這種方法魯棒性較差,只適合傳統精確小資料場景。
標準化
通過對原始資料進行變換把資料變換到均值為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.358732440.98058068] [-0.267261240.339683110.39223227] [ 1.336306211.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-153.82970843e+00] [ 5.74456265e+00 -1.91485422e+00] [-5.74456265e+00 -1.91485422e+00]]