特征預處理--長尾分布的處理方案


聲明:版權所有,轉載請聯系作者並注明出處  http://blog.csdn.net/u013719780?viewmode=contents
 
0x00 前言

數據預處理包含數據探索、數據清洗和特征預處理三部分,《特征工程系列:特征預處理(上)》介紹了無量綱化和特征分桶相關的處理方法,本章將繼續介紹特征預處理中的統計變換和類別特征編碼相關內容。

0x01 統計變換

數據分布的傾斜有很多負面的影響。我們可以使用特征工程技巧,利用統計或數學變換來減輕數據分布傾斜的影響。使原本密集的區間的值盡可能的分散,原本分散的區間的值盡量的聚合。

這些變換函數都屬於冪變換函數簇,通常用來創建單調的數據變換。它們的主要作用在於它能幫助穩定方差,始終保持分布接近於正態分布並使得數據與分布的平均值無關。

1.Log變換

1)定義

Log變換通常用來創建單調的數據變換。它的主要作用在於幫助穩定方差,始終保持分布接近於正態分布並使得數據與分布的平均值無關。

Log 變換屬於冪變換函數簇。該函數用數學表達式表示為

自然對數使用 b=e,e=2.71828,通常叫作歐拉常數。你可以使用通常在十進制系統中使用的 b=10 作為底數。

當應用於傾斜分布時 Log 變換是很有用的,因為Log變換傾向於拉伸那些落在較低的幅度范圍內自變量值的范圍,傾向於壓縮或減少更高幅度范圍內的自變量值的范圍。從而使得傾斜分布盡可能的接近正態分布。  

2)作用

針對一些數值連續特征的方差不穩定,特征值重尾分布我們需要采用Log化來調整整個數據分布的方差,屬於方差穩定型數據轉換。比如在詞頻統計中,有些介詞的出現數量遠遠高於其他詞,這種詞頻分布的特征就會現有些詞頻特征值極不協調的狀況,拉大了整個數據分布的方差。這個時候,可以考慮Log化。尤其在分本分析領域,時間序列分析領域,Log化非常常見, 其目標是讓方差穩定,把目標關注在其波動之上。

3)變換效果

4)實現代碼

fcc_survey_df['Income_log'] = np.log((1+fcc_survey_df['Income']))

2.Box-Cox變換

1)定義

Box-Cox 變換是另一個流行的冪變換函數簇中的一個函數。該函數有一個前提條件,即數值型值必須先變換為正數(與 log 變換所要求的一樣)。萬一出現數值是負的,使用一個常數對數值進行偏移是有幫助的。

Box-Cox 變換函數:

生成的變換后的輸出y是輸入 x 和變換參數的函數;當 λ=0 時,該變換就是自然對數 log 變換,前面我們已經提到過了。λ 的最佳取值通常由最大似然或最大對數似然確定。

2)作用

Box-Cox變換是Box和Cox在1964年提出的一種廣義冪變換方法,是統計建模中常用的一種數據變換,用於連續的響應變量不滿足正態分布的情況。Box-Cox變換之后,可以一定程度上減小不可觀測的誤差和預測變量的相關性。Box-Cox變換的主要特點是引入一個參數,通過數據本身估計該參數進而確定應采取的數據變換形式,Box-Cox變換可以明顯地改善數據的正態性、對稱性和方差相等性,對許多實際數據都是行之有效的。

3)變化效果

 

4)實現代碼

import scipy.stats as spstats
# 從數據分布中移除非零值
income = np.array(fcc_survey_df['Income'])
income_clean = income[~np.isnan(income)]
# 計算最佳λ值
l, opt_lambda = spstats.boxcox(income_clean)
print('Optimal lambda value:', opt_lambda)

# 進行Box-Cox變換
fcc_survey_df['Income_boxcox_lambda_opt'] = spstats.boxcox(fcc_survey_df['Income'],lmbda=opt_lambda)

0x02 分類特征(類別特征)編碼

在統計學中,分類特征是可以采用有限且通常固定數量的可能值之一的變量,基於某些定性屬性將每個個體或其他觀察單元分配給特定組或名義類別。

1.標簽編碼(LabelEncode)

1)定義

LabelEncoder是對不連續的數字或者文本進行編號,編碼值介於0和n_classes-1之間的標簽。

2)優缺點

優點:相對於OneHot編碼,LabelEncoder編碼占用內存空間小,並且支持文本特征編碼。

缺點:它隱含了一個假設:不同的類別之間,存在一種順序關系。在具體的代碼實現里,LabelEncoder會對定性特征列中的所有獨特數據進行一次排序,從而得出從原始輸入到整數的映射。所以目前還沒有發現標簽編碼的廣泛使用,一般在樹模型中可以使用。
例如:比如有[dog,cat,dog,mouse,cat],我們把其轉換為[1,2,1,3,2]。這里就產生了一個奇怪的現象:dog和mouse的平均值是cat。

3)實現代碼

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit(["paris", "paris", "tokyo", "amsterdam"])

print('特征:{}'.format(list(le.classes_)))
# 輸出 特征:['amsterdam', 'paris', 'tokyo']

print('轉換標簽值:{}'.format(le.transform(["tokyo", "tokyo", "paris"])))
# 輸出 轉換標簽值:array([2, 2, 1]...)

print('特征標簽值反轉:{}'.format(list(le.inverse_transform([2, 2, 1]))))
# 輸出 特征標簽值反轉:['tokyo', 'tokyo', 'paris']

2.獨熱編碼(OneHotEncode)

1)定義

OneHotEncoder用於將表示分類的數據擴維。最簡單的理解就是與位圖類似,設置一個個數與類型數量相同的全0數組,每一位對應一個類型,如該位為1,該數字表示該類型。

OneHotEncode只能對數值型變量二值化,無法直接對字符串型的類別變量編碼。

2)為什么要使用獨熱編碼

獨熱編碼是因為大部分算法是基於向量空間中的度量來進行計算的,為了使非偏序關系的變量取值不具有偏序性,並且到圓點是等距的。使用one-hot編碼,將離散特征的取值擴展到了歐式空間,離散特征的某個取值就對應歐式空間的某個點。將離散型特征使用one-hot編碼,會讓特征之間的距離計算更加合理。  

為什么特征向量要映射到歐式空間?
將離散特征通過one-hot編碼映射到歐式空間,是因為,在回歸、分類、聚類等機器學習算法中,特征之間距離的計算或相似度的計算是非常重要的,而我們常用的距離或相似度的計算都是在歐式空間的相似度計算。

3)例子

假如有三種顏色特征:紅、黃、藍。

在利用機器學習的算法時一般需要進行向量化或者數字化。那么你可能想令 紅=1,黃=2,藍=3。那么這樣其實實現了標簽編碼,即給不同類別以標簽。然而這意味着機器可能會學習到“紅<黃<藍”,但這並不是我們的讓機器學習的本意,只是想讓機器區分它們,並無大小比較之意。

所以這時標簽編碼是不夠的,需要進一步轉換。因為有三種顏色狀態,所以就有3個比特。即紅色:1 0 0 ,黃色: 0 1 0,藍色:0 0 1 。如此一來每兩個向量之間的距離都是根號2,在向量空間距離都相等,所以這樣不會出現偏序性,基本不會影響基於向量空間度量算法的效果。

4)優缺點

優點:獨熱編碼解決了分類器不好處理屬性數據的問題,在一定程度上也起到了擴充特征的作用。它的值只有0和1,不同的類型存儲在垂直的空間。

缺點:當類別的數量很多時,特征空間會變得非常大。在這種情況下,一般可以用PCA來減少維度。而且one hot encoding+PCA這種組合在實際中也非常有用。

5)實現代碼

使用sklearn實現
注:當特征是字符串類型時,需要先用 LabelEncoder() 轉換成連續的數值型變量,再用 OneHotEncoder() 二值化 。

from sklearn.preprocessing import OneHotEncoder
enc = OneHotEncoder()
enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]]) # fit來學習編碼
enc.transform([[0, 1, 3]]).toarray() # 進行編碼
# 輸出:array([[ 1., 0., 0., 1., 0., 0., 0., 0., 1.]])

使用pandas實現

import pandas as pd
import numpy as np

sex_list = ['MALE', 'FEMALE', np.NaN, 'FEMALE', ]
df = pd.DataFrame({'SEX': sex_list})
display(df)
# 輸出
SEX
0 MALE
1 FEMALE
2 NaN
3 FEMALE

df = pd.get_dummies(df['SEX'],prefix='IS_SEX')
display(df)
# 輸出
IS_SEX_FEMALE IS_SEX_MALE
0 0 1
1 1 0
2 0 0
3 1 0

3.標簽二值化(LabelBinarizer)

1)定義

功能與OneHotEncoder一樣,但是OneHotEncode只能對數值型變量二值化,無法直接對字符串型的類別變量編碼,而LabelBinarizer可以直接對字符型變量二值化。

2)實現代碼

from sklearn.preprocessing import LabelBinarizer
lb = LabelBinarizer()
lb.fit([1, 2, 6, 4, 2])

print(lb.classes_)
# 輸出 array([1, 2, 4, 6])

print(lb.transform([1, 6]))
# 輸出 array([[1, 0, 0, 0],
[0, 0, 0, 1]])

print(lb.fit_transform(['yes', 'no', 'no', 'yes']))
# 輸出 array([[1],
[0],
[0],
[1]])

4.多標簽二值化(MultiLabelBinarizer)

1)定義

用於label encoding,生成一個(n_examples * n_classes)大小的0~1矩陣,每個樣本可能對應多個label。

2)適用情況

  • 每個特征中有多個文本單詞;


     用戶興趣特征(如特征值:

    ”健身 電影 音樂”)適合使用多標簽二值化,因為每個用戶可以同時存在多種興趣愛好。

  • 多分類類別值編碼的情況。


     電影分類標簽中(如:

    [action, horror]和[romance, commedy])需要先進行多標簽二值化,然后使用二值化后的值作為訓練數據的標簽值。

3)實現代碼

from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
print(mlb.fit_transform([(1, 2), (3,)]))
# 輸出
array([[1, 1, 0],
[0, 0, 1]])

print(mlb.classes_)
# 輸出:array([1, 2, 3])

print(mlb.fit_transform([{'sci-fi', 'thriller'}, {'comedy'}]))
# 輸出:array([[0, 1, 1],
[1, 0, 0]])

print(list(mlb.classes_))
# 輸出:['comedy', 'sci-fi', 'thriller']

5.平均數編碼(Mean Encoding)

1)定義

平均數編碼(mean encoding),針對高基數類別特征的有監督編碼。當一個類別特征列包括了極多不同類別時(如家庭地址,動輒上萬)時,可以采用。

平均數編碼(mean encoding)的編碼方法,在貝葉斯的架構下,利用所要預測的應變量(target variable),有監督地確定最適合這個定性特征的編碼方式。在Kaggle的數據競賽中,這也是一種常見的提高分數的手段。

算法原理詳情可參考:平均數編碼:針對高基數定性特征(類別特征)的數據預處理/特征工程。

2)為什么要用平均數編碼

如果某一個特征是定性的(categorical),而這個特征的可能值非常多(高基數),那么平均數編碼(mean encoding)是一種高效的編碼方式。在實際應用中,這類特征工程能極大提升模型的性能。

因為定性特征表示某個數據屬於一個特定的類別,所以在數值上,定性特征值通常是從0到n的離散整數。例子:花瓣的顏色(紅、黃、藍)、性別(男、女)、地址、某一列特征是否存在缺失值(這種NA 指示列常常會提供有效的額外信息)。

一般情況下,針對定性特征,我們只需要使用sklearn的OneHotEncoder或LabelEncoder進行編碼,這類簡單的預處理能夠滿足大多數數據挖掘算法的需求。定性特征的基數(cardinality)指的是這個定性特征所有可能的不同值的數量。在高基數(high cardinality)的定性特征面前,這些數據預處理的方法往往得不到令人滿意的結果。

3)優點

和獨熱編碼相比,節省內存、減少算法計算時間、有效增強模型表現。

4)實現代碼

MeanEnocodeFeature = ['item_city_id','item_brand_id'] #聲明需要平均數編碼的特征
ME = MeanEncoder(MeanEnocodeFeature) #聲明平均數編碼的類
trans_train = ME.fit_transform(X,y)#對訓練數據集的X和y進行擬合
test_trans = ME.transform(X_test)#對測試集進行編碼

MeanEncoder實現源碼詳情可參考:平均數編碼:針對高基數定性特征(類別特征)的數據預處理/特征工程。

0x0FF 總結

  1. 特征預處理是數據預處理過程的重要步驟,是對數據的一個的標准的處理,幾乎所有的數據處理過程都會涉及該步驟。

  2. 由於樹模型(Random Forest、GBDT、xgboost等)對特征數值幅度不敏感,可以不進行無量綱化和統計變換處理;

    同時,由於樹模型依賴於樣本距離來進行學習,所以也可以不進行類別特征編碼(但字符型特征不能直接作為輸入,所以需要至少要進行標簽編碼)。

  3. 依賴樣本距離來學習的模型(如線性回歸、SVM、深度學習等)

    • 對於數值型特征需要進行無量綱化處理;

    • 對於一些長尾分布的數據特征,可以做統計變換,使得模型能更好優化;

    • 對於線性模型,特征分箱可以提升模型表達能力;

  4. 對數值型特征進行特征分箱可以讓模型對異常數據有很強的魯棒性,模型也會更穩定。

    另外,分箱后需要進行特征編碼。

如有錯誤歡迎指正~

參考文獻

[1] sklearn中的數據預處理. http://d0evi1.com/sklearn/preprocessing/
[2] 歸一化與標准化. https://ssjcoding.github.io/2019/03/27/normalization-and-standardization/
[3] Preprocessing Data : 類別型特徵_OneHotEncoder & LabelEncoder 介紹與實作. https://medium.com/ai%E5%8F%8D%E6%96%97%E5%9F%8E/preprocessing-data-onehotencoder-labelencoder-%E5%AF%A6%E4%BD%9C-968936124d59
[4] 平均數編碼:針對高基數定性特征(類別特征)的數據預處理/特征工程. https://zhuanlan.zhihu.com/p/26308272
[5] 特征工程之分箱. https://blog.csdn.net/Pylady/article/details/78882220
[6] https://www.leiphone.com/news/201801/T9JlyTOAMxFZvWly.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM