天天看點

機器學習 - [源碼實作決策樹小專題]決策樹中混雜度數值度量的Python程式設計實作(資訊熵和基尼系數的計算)1.資訊熵(entropy)2.基尼系數小結

混雜度數值度量的Python程式設計實作

JackLee

CSDN使用者名:jcLee95

如需糾錯或想參與讨論的小夥伴,可以給我寫郵件。

郵箱:[email protected]

顧名思義,所謂混雜度就是指無序程度,一般使用“資訊熵”(香濃熵)或者“及逆序數進行度量”。

閱讀本文後推薦:資訊增益與資訊增益率計算的Python實作

1.資訊熵(entropy)

資訊熵的計算步驟為:

  • 先确定目前特征有多少取值(i=1,2,3,…),計算每種不同取值的機率pi
  • 在依據公式計算資訊熵:

    H ( X ) = − ∑ i = 1 n p i ⋅ l o g 2 p i . H(X) = -\sum_{i=1}^n{pi·log_2{pi}}. H(X)=−i=1∑n​pi⋅log2​pi.

from math import log

def entropy1(anArray):
    """
    計算資訊熵(香濃熵)
    """
    entropy = 0.0                      # 資訊熵(香農熵)

    feature_dict = {}                  # 用字典鍵擷取不重複的取值
    for i in list(anArray):
        feature_dict.update({i:None,})
    
    # 計算所有不同特征值取值的機率進而計算資訊熵
    for i in feature_dict:                              # 這裡每一個i是不重複的特征取值(每個特征出現一次)
        ct = list(anArray).count(i)                     # 計算某個特征取值為i的頻數
        pi = ct / len(anArray)                          # 計算出特征值i在該特征中出現的機率 pi
        if pi == 0:                                     # 這個條件相當于人為定義log0=1
            entropy = entropy - 1
        else:
            entropy = entropy - pi * log(pi,2)          # 以2位底求熵
    return entropy
           

以上是自己實作對不同元素地頻率進行統計以求取資訊熵,了解起來難度略大。Python有個好處就是,很多子產品都有人給你寫好了,你隻要import一下就可以通過更加便捷的方式完成你想要的功能。

使用Python内模組化塊

collections

中的

Counter

對象能友善地對數組中的不同元素出現次數進行統計以簡化以上代碼。

collections.Counter

可以參見另外一篇博文的

1.1 節

實作代碼如下:

import numpy as np

def entropy2(anArray):
    '''
    計算資訊熵(香濃熵)
    '''
    cnt = Counter(anArray)
    data_length = len(anArray)
    pis = []
    for i in cnt:
        pis.append(cnt[i]/data_length)
    hi = []
    for pi in pis:
        if pi > 0:
            hi.append(pi * np.log2(pi))
    return -np.sum(hi)
           

2.基尼系數

基尼系數也可以用于度量資料的混亂程度,比起資訊熵而言基尼系數比較穩定,因為熵的值将随着所有取值情況的增多而呈現發散态勢,但基尼系數最大為1,最小為0。這使得基尼系數在有些情況下用于混雜度的度量以實作某種算法時顯得比基于資訊熵的度量更友善。比如在決策樹算法中,使用基于資訊熵的資訊增益總是會偏向于選取取值類型更多的特征,而這卻不是我們所期待的。

基尼系數的計算步驟為:

  • 确定目前特征有多少取值(i=1,2,3,…),計算每種不同取值的機率Pk
  • 由以下公式計算基尼系數

    G i n i = ∑ i = 1 n p k ( 1 − p k ) = 1 − ∑ i = 1 n ( p k ) 2 Gini = \sum_{i=1}^n{pk(1-pk)}=1-\sum_{i=1}^n{(pk) ^2} Gini=i=1∑n​pk(1−pk)=1−i=1∑n​(pk)2

我們采用等式右邊的式子,即Gini = 1-∑(k=1,n)|(Pk)^2實作求解如下:

import numpy as np

def Gini(anArray):
    '''
    計算基尼系數
    '''
    cnt = Counter(anArray)
    data_length = len(anArray)
    
    Pks = []                           # 先計算每種不同取值的機率Pk,裝入清單Pks 
    for i in cnt:
        Pks.append(cnt[i]/data_length)
    
    Pk2s = [Pk**2 for Pk in Pks]       # 再計算 1-∑(k=1,n)|(Pk)^2
    return 1 - np.sum(Pk2s)
           

小結

from math import log
import numpy as np

def impurity(anArray, impurity_t="entropy"):
    """
    計算混雜度
    
    Parameters
    ----------
    anArray:     an Array like object,由某特征依次對應每條資料下的取值構成。
    impurity_t:  str,表示混雜度的度量方式,隻能是{"entropy","gini"}中的一個。

    Return
    result: float
        為計算得到的impurity的數值。
    """
    
    cnt = Counter(anArray)
    data_length = len(anArray)
    pis = [cnt[i]/data_length for i in cnt]
    
    if impurity_t == "entropy":         # 資訊熵:Entropy = -∑(i=1,n)|(pi·logpi)
        return -np.sum([pi * np.log2(pi) for pi in pis if pi > 0])
    elif impurity_t == "gini":          # 基尼系數:Gini = 1-∑(k=1,n)|(Pk)^2
        return 1 - np.sum([Pi**2 for Pi in pis])
    else:
        raise ValueError("impurity_t can only be one of {'entropy','gini'}")
           

如果喜歡,記得一贊三連噢!