目錄
引言
在機器學習和深度學習中,經常會用到信息熵(entropy)這個概念,可以理解爲熵表示的是隨機變量不確定度的衡量。例如概率0.5比概率0.3的不確定度要高。
原理
信息熵
設X是一個取值有限的離散隨機變量,其概率分佈爲:,則隨機變量X的熵定義爲
通常log取2或者3,得到的熵的單位分別稱作比特或納特。從這就可以知道,熵依賴X的分佈,和X的取值無關,所以也可以把X的熵記做:
當隨機變量只有兩個取值的時候,例如0,1,那麼X的分佈爲:
那麼X的熵爲:
的變化曲線如下:
從上圖中可以看出,當p=0或者1的時候,熵爲0,這個時候不確定度最低,因爲p=0或1已經決定x屬於什麼了。
同理,當p=0.5的時候不確定度最高,此時很難分清x到底是什麼。
條件熵
設隨機變量(X,Y)的聯合概率分佈爲:
條件熵表示在已知隨機變量X的條件下,Y的不確定度,因此
這裏
當熵和條件熵是有訓練數據估計而來的,那麼對應的熵和條件熵稱爲經驗熵和經驗條件熵。
信息增益
信息增益是表示數據集中某個特徵X的信息使類Y的信息的不確定性減少的程度,即特徵X讓類Y不確定度降低。
特徵A對訓練數據集D的信息的信息增益,定義爲集合D的熵與特徵A給定條件下D的條件熵之差
其中和之差成爲互信息
信息增益算法流程
數據集爲D;樣本容量爲,即樣本個數。
K爲分類個數,表示屬於類別的樣本個數,。
特徵A取值有,根據A的取值,把D劃分成n個子集,是的樣本個數,。
子集中屬於的樣本的集合爲,是的樣本個數。
輸入:訓練數據集D和特徵A
輸出:特徵A對數據集D的信息增益
- 計算數據D的經驗熵
- 計算特徵A對數據集D的經驗條件熵
- 計算信息增益
信息增益比
有時候以信息增益來劃分訓練數據集的特徵,會存在偏向於選擇取值較多的特徵問題,使用信息增益比可以對這一個問題進行校正,成文一種更加權衡的選擇標準。
特徵A對訓練數據D的信息增益比定義爲信息增益與訓練數據D關於特徵A的值的熵之比:
,其中,n是特徵A取值的個數。
案例
表中是貸款申請表,最後的類別代表是否給予貸款的分類,求訓練集信息熵、信息增益和信息增益比。
信息熵求解
從類別中可以知道,是有9個,否有6個,所以信息熵爲0.971:
信息增益求解
這裏需要對每個特徵分別單獨求解,例如信貸特徵,有三類。一般、好和非常好分別是:5,6,4。
在一般中,是有1個,否有4個;
在好中,是有4個,否有2個;
在非常好中,是有4個,否有0個。所以計算如下:
信息增益比求解
上面已經計算過信息增益了,因此只需計算特徵熵即可,計算如下:
結果分析
如果以信息增益爲特徵選擇標準,可以知道房子的權重最大,因此優先選擇房子作爲首要特徵,信貸特徵其次。
信息增益比則是對信息增益進行了校正,從結果中可以知道,房子特徵依舊是首要特徵,但是工資特徵其次,而不是信息增益中的信貸。
案例的代碼實現
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from collections import Counter
import math
from math import log
import pprint
def create_data():
datasets = [['青年', '否', '否', '一般', '否'],
['青年', '否', '否', '好', '否'],
['青年', '是', '否', '好', '是'],
['青年', '是', '是', '一般', '是'],
['青年', '否', '否', '一般', '否'],
['中年', '否', '否', '一般', '否'],
['中年', '否', '否', '好', '否'],
['中年', '是', '是', '好', '是'],
['中年', '否', '是', '非常好', '是'],
['中年', '否', '是', '非常好', '是'],
['老年', '否', '是', '非常好', '是'],
['老年', '否', '是', '好', '是'],
['老年', '是', '否', '好', '是'],
['老年', '是', '否', '非常好', '是'],
['老年', '否', '否', '一般', '否'],
]
labels = [u'年齡', u'有工作', u'有自己的房子', u'信貸情況', u'類別']
# 返回數據集和每個維度的名稱
return datasets, labels
# 熵
def calc_ent(datasets):
data_length = len(datasets)
label_count = {}
for i in range(data_length):
label = datasets[i][-1]
if label not in label_count:
label_count[label] = 0
label_count[label] += 1
ent = -sum([(p / data_length) * log(p / data_length, 2) for p in label_count.values()])
return ent
# 經驗條件熵
def cond_ent(datasets, axis=0):
data_length = len(datasets)
feature_sets = {}
for i in range(data_length):
feature = datasets[i][axis]
if feature not in feature_sets:
feature_sets[feature] = []
feature_sets[feature].append(datasets[i])
cond_ent = sum([(len(p) / data_length) * calc_ent(p) for p in feature_sets.values()])
return cond_ent
# 信息增益
def info_gain(ent, cond_ent):
return ent - cond_ent
def info_gain_train(datasets):
count = len(datasets[0]) - 1
ent = calc_ent(datasets)
best_feature = []
for c in range(count):
c_info_gain = info_gain(ent, cond_ent(datasets, axis=c))
best_feature.append((c, c_info_gain))
print('特徵({}) - info_gain - {:.3f}'.format(labels[c], c_info_gain))
# 比較大小
best_ = max(best_feature, key=lambda x: x[-1])
return '特徵({})的信息增益最大,選擇爲根節點特徵'.format(labels[best_[0]])
datasets, labels = create_data()
train_data = pd.DataFrame(datasets, columns=labels)
print(train_data)
print('特徵信息增益爲:', info_gain_train(np.array(datasets)))
結果如下:(值計算了信息增益)
程序運算結果與手動計算結果一致。