Python-深度學習--2信息熵,條件熵(ID3決策樹),KL散度

一、信息熵(Entropy)的計算與應用

信息熵用于衡量一個概率分布的不確定性,值越大表示分布越分散(不確定性越高)。

1. 數學定義

對于離散概率分布?P,信息熵公式為:

(通常以 2 為底單位是比特,以 e 為底單位是納特,實際使用中可統一底數)

import numpy as np
from scipy.stats import entropy  # scipy內置熵計算函數def manual_entropy(p):"""手動計算信息熵(確保p是歸一化的概率分布)"""# 過濾0概率(避免log(0)無意義)p = p[p > 0]return -np.sum(p * np.log(p))  # 以e為底,若需以2為底可改用np.log2# 示例1:均勻分布(不確定性最高)
p_uniform = np.array([0.25, 0.25, 0.25, 0.25])  # 4個事件等概率
print("均勻分布手動計算熵:", manual_entropy(p_uniform))  # 輸出:1.386...(ln4)
print("均勻分布scipy計算熵:", entropy(p_uniform))  # 與手動計算一致# 示例2:極端分布(確定性最高)
p_deterministic = np.array([1.0, 0.0, 0.0, 0.0])  # 只有第一個事件有概率
print("極端分布熵:", entropy(p_deterministic))  # 輸出:0.0(無不確定性)# 示例3:實際應用(文本字符分布的熵)
text = "hello world"
char_counts = np.array([text.count(c) for c in set(text)])
char_probs = char_counts / len(text)  # 字符概率分布
print("文本字符分布的熵:", entropy(char_probs))  # 衡量文本字符多樣性

運行結果 :

均勻分布手動計算熵: 1.3862943611198906
均勻分布scipy計算熵: 1.3862943611198906
極端分布熵: 0.0
文本字符分布的熵: 1.5607104090414068
2. Python 實現(手動計算 + 庫函數)
import numpy as np
from scipy.stats import entropy  # scipy內置熵計算函數def manual_entropy(p):"""手動計算信息熵(確保p是歸一化的概率分布)"""# 過濾0概率(避免log(0)無意義)p = p[p > 0]return -np.sum(p * np.log(p))  # 以e為底,若需以2為底可改用np.log2# 示例1:均勻分布(不確定性最高)
p_uniform = np.array([0.25, 0.25, 0.25, 0.25])  # 4個事件等概率
print("均勻分布手動計算熵:", manual_entropy(p_uniform))  # 輸出:1.386...(ln4)
print("均勻分布scipy計算熵:", entropy(p_uniform))  # 與手動計算一致# 示例2:極端分布(確定性最高)
p_deterministic = np.array([1.0, 0.0, 0.0, 0.0])  # 只有第一個事件有概率
print("極端分布熵:", entropy(p_deterministic))  # 輸出:0.0(無不確定性)# 示例3:實際應用(文本字符分布的熵)
text = "hello world"
char_counts = np.array([text.count(c) for c in set(text)])
char_probs = char_counts / len(text)  # 字符概率分布
print("文本字符分布的熵:", entropy(char_probs))  # 衡量文本字符多樣性
3. 應用場景
  • 特征選擇:計算特征值的熵,熵越高表示特征越分散,可能包含更多信息。
  • 決策樹:ID3/C4.5 算法用信息熵計算 “信息增益”,選擇最優分裂特征。
  • 文本分析:通過字符 / 詞頻分布的熵衡量文本復雜度(熵越高,字符分布越均勻)。

補充:

步驟 1:計算數據集的總信息熵?H(D)

以經典的 “天氣與是否打球” 數據集為例(共 14 條樣本):

編號天氣(A)溫度(B)濕度(C)風速(D)是否打球(標簽)
1hot
2hot
3hot
..................
14cool

標簽 “是否打球” 中,“是” 有 9 條,“否” 有 5 條,總熵:H(D)=?149?log2?(149?)?145?log2?(145?)≈0.940

步驟 2:對每個特征計算信息增益

以特征 “天氣(A)” 為例,其取值為 “晴、陰、雨”:

  • 晴(5 條):2 條 “是”,3 條 “否” →?晴
  • 陰(4 條):4 條 “是”,0 條 “否” →?陰(確定無不確定性)
  • 雨(5 條):3 條 “是”,2 條 “否” →?雨

條件熵:H(D∣A)=145?×0.971+144?×0+145?×0.971≈0.693

信息增益:Gain(D,A)=H(D)?H(D∣A)=0.940?0.693=0.247

同理計算其他特征(溫度、濕度、風速)的信息增益,假設結果為:

  • 濕度(C)的信息增益最大(約 0.151),則 ID3 選擇 “濕度” 作為根節點的分裂特征。
步驟 3:遞歸構建決策樹

對每個特征取值的子集(如 “濕度 = 高”“濕度 = 正常”),重復步驟 1-2,計算子數據集的信息增益,選擇下一個分裂特征,直到所有樣本屬于同一類別或無特征可分。

三、C4.5 算法步驟(改進 ID3 的信息增益比)

C4.5 的核心是用信息增益比替代信息增益,避免 ID3 偏向取值多的特征(如 “日期” 這類取值多的特征可能信息增益高,但無實際意義)。

步驟 1:計算信息增益(同 ID3)

沿用 ID3 中 “天氣(A)” 的計算,Gain(D,A)=0.247。

步驟 2:計算特征的熵?HA?(D)

特征 “天氣” 有 3 個取值,樣本占比分別為?5/14,4/14,5/14:HA?(D)=?145?log2?145??144?log2?144??145?log2?145?≈1.577

步驟 3:計算信息增益比

Gain_ratio(D,A)=1.5770.247?≈0.156

對所有特征計算信息增益比,選擇增益比最大的特征作為分裂節點(C4.5 通常先篩選信息增益高于平均的特征,再從中選增益比最大的,避免增益接近 0 的特征)。

四、Python 代碼實現(ID3 算法示例)

以下用 Python 手動實現 ID3 算法,核心包括信息熵計算、信息增益計算和決策樹構建:

import numpy as np
from math import log2   #導入對數函數,用于計算信息熵
import pprint           #導入格式化打印工具,使決策樹更易讀# 1. 計算信息熵(輸入:標簽列表,如 ['是', '否', '是', ...])
def entropy(labels):"""計算標簽列表的信息熵"""# 統計每個類別的數量   字典儲存 :鍵 = 標簽, 值 = 出現次數label_counts = {}for label in labels:        #遍歷所有標簽#如果標簽在字典中,次數+1,否則初始化為1label_counts[label] = label_counts.get(label, 0) + 1ent = 0.0                   #初始化信息熵為0total = len(labels)         #總樣本數for count in label_counts.values():  #遍歷每個類別的數量p = count / total                #計算該類別的概率ent -= p * log2(p)  # 信息熵公式return ent              # 返回計算好的信息熵#作用:衡量數據集的不確定性,值越大表示越混亂
#關鍵邏輯:用字典統計標簽出現次數,帶入熵公式計算# 2. 計算信息增益(輸入:特征值列表、標簽列表)
def information_gain(feature_values, labels):"""計算某一特征的信息增益"""total_ent = entropy(labels)  # 計算總熵total_samples = len(labels)  # 總樣本數# 按特征值分組,統計每個取值對應的標簽feature_groups = {}  # key: 特征值, value: 該取值對應的標簽列表for f_val, label in zip(feature_values, labels):#同時遍歷特征值和標簽if f_val not in feature_groups:             #如果特征值未記錄,初始化列表feature_groups[f_val] = []feature_groups[f_val].append(label)# 計算條件熵 H(D|A):已知特征A的取值后,數據集的不確定性cond_ent = 0.0for group_labels in feature_groups.values():   # 遍歷每個特征值對應的標簽列表group_size = len(group_labels)             # 該特征值的樣本數# 條件熵 = 求和(該組樣本占比 * 該組信息熵)cond_ent += (group_size / total_samples) * entropy(group_labels)return total_ent - cond_ent  # 信息增益 = 總熵 - 條件熵# 3. 選擇信息增益最大的特征(輸入:特征列表、標簽列表)
def choose_best_feature(features, labels):"""選擇最佳分裂特征features: 特征列表,格式為 [[f1_val, f1_val, ...], [f2_val, ...], ...]每個子列表對應一個特征的所有取值labels: 標簽列表"""best_gain = -1best_feature_idx = 0  # 最佳特征的索引# 遍歷每個特征計算信息增益for i in range(len(features)):feature_values = features[i]gain = information_gain(feature_values, labels)if gain > best_gain:  #如果當前增益更大,更新最佳增益和索引。best_gain = gainbest_feature_idx = ireturn best_feature_idx, best_gain  #返回最佳的索引和對應的增益# 4. 遞歸構建ID3決策樹
def build_tree(features, labels, feature_names, depth=0, max_depth=5):"""構建決策樹features: 特征列表(格式同上)labels: 標簽列表feature_names: 特征名稱列表(用于樹結構的可讀性)"""# 終止條件1:所有標簽相同,返回該類別if len(set(labels)) == 1:return labels[0]# 終止條件2:無特征可分或達到最大深度,返回多數類if len(features) == 0 or depth >= max_depth:# 統計多數類label_counts = {}for label in labels:label_counts[label] = label_counts.get(label, 0) + 1return max(label_counts, key=label_counts.get)  # 多數類標簽# 選擇最佳特征best_idx, _ = choose_best_feature(features, labels)best_feature_name = feature_names[best_idx]best_feature_values = features[best_idx]  # 最佳特征的所有取值# 初始化樹結構:以最佳特征為根節點tree = {best_feature_name: {}}# 移除已選擇的特征(剩余特征用于子樹)remaining_features = [features[i] for i in range(len(features)) if i != best_idx]remaining_feature_names = [feature_names[i] for i in range(len(feature_names)) if i != best_idx]# 按最佳特征的取值分組,遞歸構建子樹unique_values = set(best_feature_values)  # 最佳特征的所有 unique 取值for val in unique_values:# 篩選出該特征值對應的樣本索引sample_indices = [i for i, f_val in enumerate(best_feature_values) if f_val == val]# 提取子樣本的特征和標簽sub_labels = [labels[i] for i in sample_indices]sub_features = []for f in remaining_features:  #遍歷剩余特征#提取該特征在子樣本中的取值sub_f = [f[i] for i in sample_indices]sub_features.append(sub_f)# 遞歸構建子樹,深度+1 ,并將結果存入當前樹結構tree[best_feature_name][val] = build_tree(sub_features, sub_labels, remaining_feature_names, depth + 1, max_depth)return tree# 5. 測試:用天氣數據集構建決策樹
if __name__ == "__main__":# 構造天氣數據集(不依賴pandas,用列表存儲)# 特征名稱列表feature_names = ['天氣', '溫度', '濕度', '風速']# 特征值列表:每個子列表對應一個特征的所有取值features = [['晴', '晴', '陰', '雨', '雨', '雨', '陰', '晴', '晴', '雨', '晴', '陰', '陰', '雨'],  # 天氣['hot', 'hot', 'hot', 'mild', 'cool', 'cool', 'cool', 'mild', 'cool', 'mild', 'mild', 'mild', 'hot', 'mild'],# 溫度['高', '高', '高', '高', '正常', '正常', '正常', '高', '正常', '正常', '正常', '高', '正常', '高'],  # 濕度['弱', '強', '弱', '弱', '弱', '強', '強', '弱', '弱', '弱', '強', '強', '弱', '強']  # 風速]# 標簽列表 (是否打球)labels = ['否', '否', '是', '是', '是', '否', '是', '否', '是', '是', '是', '是', '是', '否']  # 是否打球# 構建ID3決策樹 (最大深度為3)id3_tree = build_tree(features, labels, feature_names, max_depth=3)# 打印決策樹結構 (用pprint格式化輸出,更易讀)print("ID3決策樹結構:")pprint.pprint(id3_tree)

二、KL 散度(Kullback-Leibler Divergence)的計算與應用

KL 散度用于衡量兩個概率分布的差異,值越小表示分布越接近(非對稱度量)。

1. 數學定義

對于兩個離散概率分布?P(真實分布)和?Q(近似分布),KL 散度公式為:

import numpy as np
from scipy.stats import kl_div  # scipy內置KL散度計算def manual_kl_divergence(p, q):"""手動計算KL散度(確保p和q是同維度的歸一化概率分布)"""# 過濾0概率(避免log(0)和除以0)p = p[p > 0]q = q[p > 0]  # 只保留p有概率的位置q = np.clip(q, 1e-10, 1.0)  # 防止q為0導致除零錯誤return np.sum(p * np.log(p / q))# 示例1:兩個相似分布的KL散度
p = np.array([0.4, 0.3, 0.3])
q_similar = np.array([0.35, 0.35, 0.3])
print("相似分布手動KL散度:", manual_kl_divergence(p, q_similar))  # 輸出:0.014...
print("相似分布scipy KL散度:", np.sum(kl_div(p, q_similar)))  # 與手動計算一致(scipy返回每個元素的KL值,需求和)# 示例2:兩個差異大的分布的KL散度
q_different = np.array([0.1, 0.1, 0.8])
print("差異分布KL散度:", np.sum(kl_div(p, q_different)))  # 輸出:0.396...(值更大)# 示例3:KL散度的非對稱性(P到Q與Q到P的散度不同)
print("D(P||Q):", np.sum(kl_div(p, q_similar)))
print("D(Q||P):", np.sum(kl_div(q_similar, p)))  # 結果不同,體現非對稱性
3. 應用場景
  • 模型評估:衡量預測分布與真實分布的差異(如生成模型中,評估生成數據分布與真實數據分布的差距)。
  • 分布對齊:在遷移學習中,用 KL 散度最小化源域與目標域的分布差異。
  • 變分自編碼器(VAE):用 KL 散度約束潛在變量分布接近標準正態分布。
  • 正則化:在半監督學習中,用 KL 散度限制模型對未標記數據的預測分布熵(如一致性正則化)。

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92493.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92493.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92493.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

國產化Word處理控件Spire.Doc教程:Python提取Word文檔中的文本、圖片、表格等

在現代辦公場景中,Word文檔已成為信息存儲與交流的重要載體,承載著關鍵的業務數據、結構化表格、可視化圖表以及協作批注等重要內容。面對日益增長的文檔處理需求,傳統的人工操作方式已難以滿足效率與準確性的雙重標準。采用Python實現Word文…

Spring IOC 原理

Spring IoC(控制反轉)是Spring框架的核心機制,其原理是通過容器管理對象生命周期和依賴關系,實現解耦。 1. 控制反轉(IoC)核心思想 傳統模式:對象主動創建依賴(如new Service()&…

VSCode:基礎使用 / 使用積累

官網 Visual Studio Code - Code Editing. Redefined 記錄一、更新依賴 嘗試刪除yarn.lock文件 記錄二、“解決沖突”的方式變了 更新后,“解決沖突”的方式變了,有的時候能選中兩者,有的時候不能 現在又更新了,回復到了原來…

tcp 確認應答和超時時間

1. 確認應答之間的時間(RTT)這是指 從發送方發送數據到接收方返回確認(ACK)之間的時間。它反映的是數據傳輸的 往返延遲。例如,發送方發送一個數據包,接收方收到后,回傳一個確認包(A…

圖的應用-最短路徑

最短路徑的典型用途:交通網絡的問題——從甲地到乙地之間是否有公路連通?在有多條通路的情況下,哪一條路最短?交通網絡用有向網來表示:頂點——表示地點,弧——表示兩個地點有路連通,弧上的權值…

【qt5_study】1.Hello world

模板 作為初學者我們選擇第一個Application(Qt)和 Qt Widgets Application,所謂的模板就是 Qt為了方便開發程序,在新建工程時可以讓用戶基于一種模板來編寫程序,包括 cpp文件, ui文件都已經快速的創建,而不用用戶手動創建這些文件。 基類 這里默認選擇的基類為 QMainWin…

項目構想|文生圖小程序

Date: August 4, 2025項目介紹 👋,我們通過 Vibe Coding 做一個文字生成圖片的小程序。 我們會從需求分析、技術選型、UI設計、項目構筑到最后打包,一路嘗試 Vibe Coding 實現。 創建項目 創建文件夾:ai-pic-mini-app 采用 Git 進…

TiDB/MongoDB/Taosdb存儲引擎概覽

數據庫類型存儲引擎數據結構源碼位置tidbRockDBLSM樹https://github.com/facebook/rocksdbmongodbWiredTigerB 樹/LSM樹https://github.com/wiredtiger/wiredtigerTDengineTSDBBRINhttps://github.com/taosdata/TDengine 1、tidb存儲引擎概覽 LSM樹數據結構描述LSM樹(Log Str…

qt窗口--01

文章目錄qt窗口--01窗口概覽菜單欄工具欄狀態欄浮動窗口子窗口對話框model結語很高興和大家見面,給生活加點impetus!!開啟今天的編程之路!! 作者:?( ‘ω’ )?260 我的專欄:qt,Li…

Neo4j 社區版 Mac 安裝教程

最近用到了nebulagraph圖數據庫做金融反欺詐項目,雖然nebula屬于分布式架構,但依然感覺nebula使用不太順手,這里順便研究一下neo4j這款數據庫如何,這里先從安裝開始? 一、 準備工作 確認 Java 版本要求: N…

Android Studio(2025.1.2)Gemini Agent 使用指南

Android Studio(2025.1.2)Gemini Agent 使用指南 文章目錄Android Studio(2025.1.2)Gemini Agent 使用指南1. 什么是 Gemini Agent?2. 如何啟用和配置 Gemini Agent2.1 獲取 API Key2.2 在 Android Studio 中配置3. 實…

計算機視覺--opencv(代碼詳細教程)

在計算機視覺的廣袤領域中,OpenCV 是一座極為關鍵的里程碑。無論是在前沿的學術研究,還是在蓬勃發展的工業界,OpenCV 憑借其強大的功能與高效的性能,為開發者提供了豐富的圖像處理和計算機視覺算法,助力無數項目落地。…

Centos6停止服務后yum改用阿里云

環境: OS:Centos 6.9 1.進入到yum配置目錄 cd /etc/yum.repos.d 2.備份 cp CentOS-Base.repo CentOS-Base.repo.bk 3.下載 wget -O CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-6.repo 問題1: 因為Centos-6早就停止了更新維護,阿里云鏡像網站將其倉庫…

putty+Xming(XLaunch) 遠程登錄VirtualBox中的Ubuntu24.04,顯示圖形化(GUI)界面

測試環境:VirtualBox 7,Ubuntu24.04 desktop,Ubuntu24.04 Server(no desktop),均測試成功。 一、先測試putty遠程登錄VirtualBox中的Ubuntu,可以使用ssh、Telnet 等協議。參見拙文《ssh連接VirtualBox中的Ubuntu24.04(win11、put…

SpringBoot微頭條實戰項目

一、項目概述 微頭條是一個基于現代技術棧構建的新聞發布和瀏覽平臺,旨在為用戶提供便捷的新聞閱讀體驗和高效的新聞管理功能。該項目通過前后端分離的架構設計,實現了用戶注冊、登錄、新聞瀏覽、搜索、發布、修改和刪除等功能,同時通過JWT技…

如何給電腦換個ip地址?電腦換ip幾種方法

更換電腦的IP地址的方法取決于你的具體需求和網絡環境(是換本地局域網IP還是換對外公網IP)。以下是幾種常見的方法: 一、更換本地局域網IP地址(在同一個網絡內) 這個IP地址通常由你的路由器(或公司的網絡管…

Pytest項目_day04(Python做接口請求)

Requests包 在python中,可以使用requests包,用于做接口請求和接口測試request支持http和https簡單的get函數調用如下:r.jsonr.status_coder.textget函數的帶params用法post函數的帶params用法 post也可以和get一樣在url中傳入參數在requests包…

Flink與Kafka核心源碼詳解-目錄

Flink是Apache軟件基金會下開源的分布式流批一體計算框架,具備實時流計算和高吞吐批處理計算的大數據計算能力。本專欄內容為Flink源碼解析的記錄與分享。 本文解析的Flink源碼版本為:flink-1.19.0 以下為Flink-1.19.0-完整源碼詳解的目錄導航。 Flink-…

【VLLM篇】:原理-實現

1、VLLM vLLM是一個建立在【PagedAttention】之上的高吞吐的【分布式服務引擎】,目標是【提高吞吐量】、【提高內存利用率】(kv-cache內存利用率高達96%),它的內存管理分配方式從【固定分配】改進為【分頁管理】,類似操…

什么是 TcpCommunicationSpi

&#x1f9e9; 一、核心定位&#xff1a;什么是 TcpCommunicationSpi&#xff1f; /*** <tt>TcpCommunicationSpi</tt> is default communication SPI which uses* TCP/IP protocol and Java NIO to communicate with other nodes.*/翻譯&#xff1a;TcpCommunicat…