機器學習中的特征工程(四)---- 特征離散化處理方法

簡介

特征離散化指的是將連續特征劃分離散的過程:將原始定量特征的一個區間一一映射到單一的值。離散化過程也被表述成分箱(Binning)的過程。特征離散化常應用于邏輯回歸和金融領域的評分卡中,同時在規則提取,特征分類中也有對應的應用價值。本文主要介紹幾種常見的分箱方法,包括等寬分箱、等頻分箱、信息熵分箱、基于決策樹分箱、卡方分箱等。

分箱原理介紹

數據分箱是一種數據預處理技術,用于減少次要觀察誤差的影響,是一種將多個連續值分為相對較少的若干分組的方法。下面舉個例子來具體說明一下,假設我們有下面一組數據,表示花瓣的寬度,分布如下:
花瓣寬度分布

可以看到花瓣寬度范圍區間是0.1~2.5,看起來劃分的有點細了,有的時候我們不需要那么精細,比如我們希望將花瓣寬度劃分到(‘很窄’,‘窄’、‘正常’、‘寬’、‘很寬’)這5個范圍里,那么我們可以將花瓣寬度重新劃分為5個區間,將落在對應區間的花瓣寬度映射到之前指定的5個范圍內,如下如所示。
分箱
可以看到在分箱之后,數據被規約和簡化,有利于理解和解釋。總來說特征離散化,即 分箱之后會帶來如下優勢:
  • 有助于模型部署和應用,加快模型迭代
  • 增強模型魯棒性
  • 增加非線性表達能力:連續特征不同區間對模型貢獻或者重要程度不一樣時,分箱后不同的權重能直接體現這種差異,離散化后的特征再進行特征 交叉衍生能力會進一步加強。
  • 提升模型的泛化能力
  • 擴展數據在不同各類型算法中的應用范圍

當然特征離散化也有其缺點,總結如下:

  • 分箱操作必定會導致一定程度的信息損失
  • 增加流程:建模過程中加入了額外的的離散化步驟
  • 影響模型穩定性: 當一個特征值處于分箱點的邊緣時,此時微小的偏差會造成該特征值的歸屬從一箱躍遷到另外一箱,影響模型的穩定性。

特征離散化(分箱)可以從不同的角度來進行劃分。當分箱方法使用了目標y的信息,那么該分箱方法就屬于有監督的分箱方法,反之為無監督的分箱方法。
這里選擇sklearn中自帶的乳腺癌數據集,下文提及的分箱方法大多是基于此數據集,主要是取其中的‘mean radius’字段,如下:

import seaborn as sns
from sklearn.datasets import load_breast_cancer

bc = load_breast_cancer()
df = pd.DataFrame.from_records(data=bc.data, columns=bc.feature_names)
df['target'] = bc.target
sns.distplot(df['mean radius'], kde=False)
原始特征分布

等寬分箱(Equal-Width Binning)

等寬分箱指的是每個分隔點或者劃分點的距離一樣,即等寬。實踐中一般指定分隔的箱數,等分計算后得到每個分隔點。例如將數據序列分為n份,則 分隔點的寬度計算公式為:
w = \frac {max - min} {n}
這樣就將原始數據劃分成了n個等寬的子區間,一般情況下,分箱后每個箱內的樣本數量是不一致的。使用pandas中的cut函數來實現等寬分箱,代碼如下:

value, cutoff = pd.cut(df['mean radius'], bins=4, retbins=True, precision=2)
cutoff
分隔點

可以輕易計算得出任意兩個相鄰分隔點之間的距離為5.30。按照上述分隔點對數據進行劃分后,數據的分布如下:

df1 = value.to_frame()
df1.columns = ['bins']
sns.countplot(df1['bins'])
特征分箱后數據分布

等寬分箱計算簡單,但是當數值方差較大時,即數據離散程度很大,那么很可能出現沒有任何數據的分箱,這個問題可以通過自適應數據分布的分箱方法--等頻分箱來避免

等頻分箱(Equal-Frequency Binning)

顧名思義,等頻分箱理論上分隔后的每個箱內得到數據量大小一致,但是當某個值出現次數較多時,會出現等分邊界是同一個值,導致同一數值分到不同的箱內,這是不正確的。具體的實現可以去除分界處的重復值,但這也導致每箱的數量不一致。如下代碼:

s1 = pd.Series([1,2,3,4,5,6])
value, cutoff = pd.qcut(s1, 3, retbins=True)
sns.countplot(value)
等頻分箱

每個區間分別是2個數,這沒有問題,但是如果某個數字出現的次數較多,則可能出現下面的情況:

s1 = pd.Series([1,2,3,4,5,6,6,6,6])
value, cutoff = pd.qcut(s1, 3, duplicates='drop', retbins=True)
sns.countplot(value)
等頻分箱合并

本來是要分成3個箱子的,但是由于出現同一個數值被分到了不同的箱子里,因此被合并了,所以最后只有2個箱子。
同樣,我們對乳腺癌數據進行等頻分箱,該數據分布正常,等頻分箱后每箱數量基本一致。

value, cutoff = pd.qcut(df['mean radius'], 4, duplicates='drop', retbins=True)
sns.countplot(value)
等頻分箱

上述的等寬和等頻分箱容易出現的問題是每箱中信息量變化不大。例如,等寬分箱不太適合分布不均勻的數據集、離群值;等頻方法不太適合特定的值占比過多的數據集,如長尾分布。

信息熵分箱

上面介紹的分箱方法對建模的優化有限。如果分箱后箱內樣本對y的區分度好,那么這是一個好的分箱。通過信息論理論,我們可知信息熵衡量了這種區分能力。當特征按照某個分隔點劃分為上下兩部分后能達到最大的信息增益,那么這就是一個好的分隔點。由上可知,信息熵分箱是有監督的分箱方法。其實決策樹的節點分裂原理也是基于信息熵。
首先我們需要明確信息熵和信息增益的計算方式,分別如下:
Entropy(y) = - \sum_{i=1}^m p_i log_2{p_i} \\ Gain(x) = Entropy(y) - Info_{split}(x)
在二分類問題中,m=2
信息增益的物理含義表達為:x的分隔帶來的信息對y的不確定性帶來的增益。
對于二值化的單點分隔,如果我們找到一個分隔點將數據一分為二,分成P_1P_2兩部分,那么劃分后的信息熵的計算方式為:
Info_{split}(x) = P1_{ratio}Entropy(x_{p1}) + P2_{ratio}Entropy(x_{p2})
下面以一個實例來介紹一下信息熵分箱的計算過程,假如我們有以下數據,我們以特征'x=3'來作為特征x的分隔點,則其帶來的信息增益為0.420,如下:

data = [[1,0],[2,1],[3,0],[4,1],[5,1]]
df = pd.DataFrame(data, columns=['x','y'])
df

原始數據
接下來我們來計算信息增益,先計算分隔前的信息熵,如下:
Entroy(y) = -\lbrace \frac {2}{5} * log_2 \frac {2}{5} + \frac {3}{5} * log_2 \frac {3}{5} \rbrace = 0.971
接下來計算劃分后的信息熵:
Info_{split}(x) = P_1Entropy(x < 3) + P_2Entropy(x \ge 3) \\ P_1Entropy(x < 3) = \frac {3}{5} * -\lbrace \frac {2}{3} * log_2 \frac {2}{3} + \frac {1}{3} * log_2 \frac {1}{3} \rbrace = 0.551\\ P_2Entropy(x \ge 3) = \frac {2}{5} * -\lbrace \frac {2}{2} * log_2 \frac {2}{2} + \frac {0}{2} * log_2 \frac {0}{2} \rbrace = 0
故信息增益為:
Gain(x) = 0.971 - 0.551 = 0.420
類似的可以計算其他分隔點的信息增益,最終選取信息增益最大時對應的分隔點。同時也可以看出,當分箱后,某個箱中的標簽y的類別(0或者1)的比例相等時,其熵值最大,表明此特征劃分幾乎沒有區分度。而當某個箱中的數據的標簽y為單個類別時,那么該箱的熵值達到最小的0,即純度最純,最具區分度。從結果上來看,最大信息增益對應分箱后的總熵值最小。

決策樹分箱

其實上一節中已經說到,由于決策樹的結點選擇和劃分也是根據信息熵來計算的,因此我們其實可以利用決策樹算法來進行特征選擇,具體做法如下:
還是以乳腺癌數據為例,首先取其中‘mean radius’字段,和標簽字段‘target’來擬合一棵決策樹,代碼如下:

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(criterion='entropy', max_depth=3) # 樹最大深度為3
dt.fit(df['mean radius'].values.reshape(-1, 1), df['target'])

接著我們取出這課決策樹的所有葉節點的分割點的閾值,如下:

qts = dt.tree_.threshold[np.where(dt.tree_.children_left > -1)]
qts = np.sort(qts)
res = [np.round(x, 3) for x in qts.tolist()]
res
決策樹分割點閾值

注意這里只給出了6個點,但是相當于分了7個箱子,分別設為a-g,我們可以將劃分后的效果繪制出來:

l = df['mean radius'].values.tolist()

r = []
for i in l:
    if i < res[0]:
        r.append('a')
    elif i >= res[-1]:
        r.append('g')
    else:
        for j in range(0, 5):
            if i > res[j] and i <= res[j+1]:
                r.append(chr(98+j))
                break
ax = sns.countplot(r)
ax
劃分后的數據分布

卡方分箱

在了解卡方分箱之前,我們需要先了解幾個關鍵概念,比如卡方分布,卡方檢驗等。
卡方分布是概率統計常見的一種概率分布,是卡方檢驗的基礎。
卡方分布定義為:若n個獨立的隨機變量Z_1, Z_2, ...,Z_k滿足標準正態分布N(0,1),則n個隨機變量的平方和X=\sum_{i=0}^k Z_i^2為服從自由度為k的卡方分布,記為X \sim \chi^2。參數n稱為自由度(樣本中獨立或能自由變化的自變量的個數),不同的自由度是不同的分布。例如,一個標準正態分布的平方就是自由度為1的卡方分布。卡方分布的概率密度函數如下:

卡方分布
卡方檢驗 :卡方檢驗屬于非參數假設檢驗的一種,其本質都是度量頻數之間的差異。其假設為:觀察頻數與期望頻數無差異或者兩組變量相互獨立不相關。
\chi^2 = \sum \frac {(O-E)^2}{E}

  • 卡方擬合 優度檢驗:用于檢驗樣本是否來自于某一個分布,比如檢驗某樣本是否為正態分布
  • 獨立性卡方檢驗,查看兩組類別變量分布是否有差異或者相關,以列聯表的形式比較。以列聯表形式的卡方檢驗中,卡方統計量由上式給出。

其中,O表示觀察到的頻數(即實際出現的次數),E表示期望的頻數。很明顯,越小的卡方值,表明兩者相差越小,反之,越大的卡方值表明兩者差異越大。下面以一個具體的例子來說明卡方值的計算方式。
下面是觀察到的兩組樣本分布:

觀察 bad good 合計
組一 25 50 75
組二 30 15 45
合計 55 65 120

接著是期望頻數的計算過程:

期望 bad good
組一 55*(75/120)=34.375 65*(75/120)=40.625
組二 55*(45/120)=20.625 65*(45/120)=24.375

最后是卡方值的計算過程:

a = [25, 50, 30, 15]
b = [34.375, 40.625, 20.625, 24.375]
r= []
for i in zip(a,b):
    r.append((i[0]-i[1])**2 / i[1])
np.sum(r)
卡方值

科學計算庫SciPy中包含了卡方檢驗的實現,例子如下:

from scipy.stats import chi2_contingency
obs = np.array([[25,50],[30,15]])
chi2, p, dof, ex = chi2_contingency(obs, correction=False)
chi2
卡方值

其中dof代表自由度,ex代表期望概率。在得到卡方值以后查詢卡方分布表并比較p_value值,繼而做出接受或者拒絕原假設的判斷。下段代碼是輸出卡方分布表的實現:

from scipy.stats import chi2

def chi2_table(freedom=10, alpha=None):
    if alpha is None:
        alpha = [0.99, 0.95, 0.9, 0.5, 0.1, 0.05, 0.025, 0.01, 0.005]
    df = pd.DataFrame([chi2.isf(alpha, df=i) for i in range(1, freedom)])
    df.columns = alpha
    df.index = df.index + 1
    return df
chi2_table()
卡方分布表

由表可知,當自由度為1、置信水平為0.05時,對應的卡方值為3.84,而上述例子計算出來的卡方值為12.587,大于3.841。說明在0.05的顯著性水平是可以拒絕原假設的,即觀察頻數與期望頻數有差異。換個角度描述卡方檢驗的物理含義:當兩個分箱中,好壞(正負)分布是一致時,卡方為0,相似是接近0,對應到卡方分箱算法中,應該合并這兩個分箱。

卡方分箱步驟

卡方分箱是自底向上的(即基于合并的)數據離散化方法。它依賴于卡方檢驗:具有最小卡方值的相鄰區間合并在一起,直到滿足確定的停止準則。基本思想: 對于精確的離散化,相對類頻率在一個區間內應當完全一致。因此,如果兩個相鄰的區間具有非常類似的類分布,則這兩個區間可以合并;否則,它們應當保持分開。而低卡方值表明它們具有相似的類分布。
卡方檢驗可以用來評估兩個分布的相似性,因此可以將這個特性用到數據分箱的過程中。

理想的分箱是在同一個區間內標簽的分布是相同的。卡方分箱就是不斷的計算相鄰區間的卡方值(卡方值越小表示分布越相似),將分布相似的區間(卡方值最小的)進行合并,直到相鄰區間的分布不同,達到一個理想的分箱結果。下面用一個例子來解釋:
由上圖,第一輪中初始化是5個區間,分別計算相鄰區間的卡方值。找到1.2是最小的,合并2、3區間,為了方便,將合并后的記為第2區間,因此得到4個區間。第二輪中,由于合并了區間,影響該區間與前面的和后面的區間的卡方值,因此重新計算1和2,2和4的卡方值,由于4和5區間沒有影響,因此不需要重新計算,這樣就得到了新的卡方值列表,找到最小的取值2.5,因此該輪會合并2、4區間,并重復這樣的步驟,一直到滿足終止條件。

參考

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容