1. 程式人生 > >機器學習:資訊熵,基尼係數,條件熵,條件基尼係數,資訊增益,資訊增益比,基尼增益,決策樹程式碼實現(一)

機器學習:資訊熵,基尼係數,條件熵,條件基尼係數,資訊增益,資訊增益比,基尼增益,決策樹程式碼實現(一)

文章目錄

初始化,涉及到使用的變數:

# =============================================================================
# 計算資訊量的相關演算法 # ============================================================================= import math import numpy as np class Cluster: def __init__(self,x,y,sample_weight=None,base=2): # 記錄資料集的變數為numpy陣列 self._x,self._y = x.T,y # 利用樣本權重對類別向量計數,self._counters樣本各個類別的計數
if sample_weight is None: self._counters = np.bincount(self._y) else: self._counters = np.bincount(self._y,weights = sample_weight*len(sample_weight)) # 記錄樣本權重的屬性 self._sample_weight = sample_weight # 記錄中間結果的屬性 self._con_chaos_cache =
self._ent_cache = self._gini_cache = None # 記錄對數的底的屬性 self._base = base

資訊熵

定義公式,經驗公式

在這裡插入圖片描述
在這裡插入圖片描述

程式碼:

    # 定義計算資訊熵的函式,預設計算整個樣本資訊熵,self._ent_cache就是樣本資訊熵
    # 子樣本資訊熵需要給出每個類別的數量
    def ent(self,ent=None,eps = 1e-12):
        # 如果已經計算過,且呼叫時沒有額外給各類別樣本的個數,就直接返回呼叫結果
        if self._ent_cache is not None and ent is None:
            return self._ent_cache
        
        _len = len(self._y)
        # 如果沒有給出各類別樣本的個數,就是用結構本身的計數器來獲取相應的個數
        if ent is None:
            ent = self._counters
        
        # eps使演算法的穩定性更好
        _ent_cache = max(eps,-sum(
                [_c / _len*math.log(_c / _len,self._base) if _c !=0 else 0 for _c in ent]))
        
        # 如果呼叫時沒有給出各個類別樣本數量,就將計算的資訊熵儲存下來
        if ent is None:
            self._ent_cache = _ent_cache
        return _ent_cache

基尼係數

定義公式,經驗公式

在這裡插入圖片描述
在這裡插入圖片描述

程式碼:

    # 計算基尼係數,p為各個分類數量
    def gini(self,p=None):
        if self._gini_cache is not None and p is None:
            return self._gini_cache
        _len = len(self._y)
        # 如果沒有給出各類別樣本的個數,就是用結構本身的計數器來獲取相應的個數
        if p is None:
            p = self._counters
        _gini_cache = 1-np.sum((p/_len)**2)
        
        if p is None:
            self._gini_cache = _gini_cache
        
        return _gini_cache

條件熵,條件基尼係數

條件熵定義公式,經驗公式

在這裡插入圖片描述

在這裡插入圖片描述

條件基尼係數定義公式,經驗公式

在這裡插入圖片描述
在這裡插入圖片描述

程式碼:

# =============================================================================
#     定義計算H(y|A)和 Gini(y|A)
# =============================================================================
    def con_chaos(self,idx,criterion="ent",features=None):
        # 根據不同的準則呼叫不同的方法, lambda input:output
        if criterion == "ent":
            _meghod = lambda Cluster: Cluster.ent()
        elif criterion == "gini":
            _meghod = lambda Cluster: Cluster.gini()
        
        # 獲取相應緯度的向量,也就是feathure A ,是一個[N]的行向量
        # data為feature = idx的N個數據的feathureValue
        data = self._x[idx]
        # 如果沒有給出該feathure的取值空間,就呼叫set函式自己算出來
        # 呼叫set比較耗時,決策實現儘量傳入features
        # features為該feature的取值空間
        if features is None:
            features = set(data)
            
        # 獲取這個feature下的各個featureValue在data中的位置
        # 返回的是[featureValue,對應的mask]
        tmp_labels = [data == feature for feature in features]
        # 在這個函式裡沒有使用,記錄下來後面會用
        # [featureValue,對應的它的樣本數量]
        self._con_chaos_cache =[np.sum(_label) for _label in tmp_labels]
        # 利用mask獲取每個featureValue對應的y樣本
        # [featureValue,對應他的y樣本]
        label_lst = [self._y[label] for label in tmp_labels]
        
        # 上面的操作就是為了獲取mask,從而獲取:在feature=idx,取m個不同featureValue
        # 時,這個時候的x樣本和y樣本,利用這些樣本求資訊增益的後半部分
        
        # 記錄H(y|A)最後計算結果
        rs =0
        # 記錄每一個featureValue對應的資訊增益的後半部分,
        # 也就是條件不確定度,後面決策樹生成會用到
        chaos_lst =[]
        
        for data_label,tar_label in zip(tmp_labels,label_lst):
            # 獲取對應的x樣本,mask使用條件row=column,所以需要轉置,
            # 匹配的y樣本就是tar_label,名字取得有點問題,應該叫tar_data
            tmp_data = self._x.T[data_label]
            
            if self._sample_weight is None:
                # 恕我直言這個地方沒必要用_meghod,有點炫耀技術,應該可以直接呼叫吧
                _chaos = _meghod(Cluster(tmp_data,tar_label,base=self._base))
            else:
                _new_weights = self._sample_weight[data_label]
                _chaos = _meghod(Cluster(tmp_data,tar_label,_new_weights/np.sum(
                        _new_weights),base=self._base))
            # 計算資訊增益外面的那個求和,注意負號在裡面計算互資訊裡計算過了
            # 把m個featureValue遍歷完畢,就計算出了H(y|A)
            rs +=len(tmp_data)/len(data)*_chaos
            # 記錄各部分條件不確定度,後面決策樹生成會用到
            chaos_lst.append(_chaos)
            
        return rs,chaos_lst

資訊增益,資訊增益比,基尼增益

資訊增益

在這裡插入圖片描述

資訊增益比

在這裡插入圖片描述
H A ( y ) H_A(y) 的定義和經驗求法:
在這裡插入圖片描述
在這裡插入圖片描述
可以看出也可以使用熵的函式求解。

基尼增益

在這裡插入圖片描述

程式碼:

# =============================================================================
#     計算資訊增益
# =============================================================================
    # get_chaos_lst用於控制輸出
    def info_gain(self,idx,criterion="ent",get_chaos_lst=False,features=None):
        # 依據不同的準則,獲取相應的條件不確定度
        if criterion in ("ent","ratio"):
            _con_chaos,_chaos_lst =self.con_chaos(idx,"ent",features)
            _gain = self.ent() - _con_chaos
            
            # 我們知道g_ratio(y,A) = g(y,A)/H_A(y)
            # self._con_chaos_cache :[featureValue,對應的它的樣本數量]
            # H_A(y)如何求?根據他的經驗熵公式,只要把[featureValue,對應的它的樣本數量]
            # 帶入計算就可以了
            if criterion == "ratio":
                _gain /= self.ent(self._con_chaos_cache)
                
        elif criterion == "gini":
            _con_chaos,_chaos_lst =self.con_chaos(idx,"gini",features)
            _gain = self.gini() - _con_chaos
        
        return (_gain,_chaos_lst) if get_chaos_lst else _gain