天天看點

重磅!李航《統計學習方法》Python 代碼更新,适應第二版!

李航的《統計學習方法》可以說是機器學習的入門寶典,許多機器學習教育訓練班、網際網路企業的面試、筆試題目,很多都參考這本書。之前,紅色石頭在本公衆号上也發表過一些關于這本書的一些筆記和 Python 代碼,目的是給大家啃這本書帶來一些便利。剛剛,紅色石頭發現黃海廣博士在自己的 GitHub 上又更新了《統計學習方法》的 Python 代碼,就迫不及待地分享給大家。

緣由是《統計學習方法》第一版還是 2012 年出版的,包含了衆多主要的監督學習算法與模型。2019 年 5 月 1 日,《統計學習方法》第二版正式釋出,通過 6 年時間的努力,在第一版的基礎上又增加了無監督學習的主要算法與模型。

重磅!李航《統計學習方法》Python 代碼更新,适應第二版!

第二版的目錄為:

第1篇 監督掌習

第1章統計學習及監督學習概論

第2章感覺機

第3章k近鄰法

第4章樸素貝葉斯法

第5章決策樹

第6章邏輯斯谛回歸與優選熵模型

第7章支援向量機

第8章提升方法

第9章EM算法及其推廣

第10章隐馬爾可夫模型

第11章條件随機場

第12章監督學習方法總結

第2篇無監督學習

第13章無監督學習概論

第14章聚類方法

第15章奇異值分解

第16章主成分分析

第17章潛在語義分析

第18章機率潛在語義分析

第19章馬爾可夫鍊蒙特卡羅法

第20章  潛在狄利克雷配置設定

第21章  PageRank算法

第22章  無監督學習方法總結

    附錄A  梯度下降法

    附錄B  牛頓法和拟牛頓法

    附錄C  拉格朗日對偶性

    附錄D  矩陣的基本子空間

    附錄E  KL散度的定義和狄利克雷分布的性質

針對新增加的内容,黃海廣博士對原有的 GitHub 源碼進行新内容的更新,直接放上位址:

https://github.com/fengdu78/lihang-code

本次修改了部分錯誤,增加了每章概述,更新完前 12 章,今後将增加第二版的内容。

修改主要錯誤包括: 

  • 第3章 k近鄰法的max_count錯誤 
  • 第10章 隐馬爾可夫模型的viterbi索引錯誤 

增加的内容: 

  • 增加每章的概要

項目目前包含的内容截圖如下:

重磅!李航《統計學習方法》Python 代碼更新,适應第二版!

目前,該項目已經收獲 5000+ 的 star 了。

Python 代碼

下面,以支援向量機為例,我們可以查閱 SVM 的完整示例代碼:

class SVM:
def __init__(self, max_iter=100, kernel='linear'):
self.max_iter = max_iter
self._kernel = kernel
def init_args(self, features, labels):
self.m, self.n = features.shape
self.X = features
self.Y = labels
self.b = 0.0
# 将Ei儲存在一個清單裡
self.alpha = np.ones(self.m)
self.E = [self._E(i) for i in range(self.m)]
# 松弛變量
self.C = 1.0
def _KKT(self, i):
y_g = self._g(i) * self.Y[i]
if self.alpha[i] == 0:
return y_g >= 1
elif 0 < self.alpha[i] < self.C:
return y_g == 1
else:
return y_g <= 1
# g(x)預測值,輸入xi(X[i])
def _g(self, i):
r = self.b
for j in range(self.m):
r += self.alpha[j] * self.Y[j] * self.kernel(self.X[i], self.X[j])
return r
# 核函數
def kernel(self, x1, x2):
if self._kernel == 'linear':
return sum([x1[k] * x2[k] for k in range(self.n)])
elif self._kernel == 'poly':
return (sum([x1[k] * x2[k] for k in range(self.n)]) + 1)**2
return 0
# E(x)為g(x)對輸入x的預測值和y的差
def _E(self, i):
return self._g(i) - self.Y[i]
def _init_alpha(self):
# 外層循環首先周遊所有滿足0<a<C的樣本點,檢驗是否滿足KKT
index_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]
# 否則周遊整個訓練集
non_satisfy_list = [i for i in range(self.m) if i not in index_list]
index_list.extend(non_satisfy_list)
for i in index_list:
if self._KKT(i):
continue
E1 = self.E[i]
# 如果E2是+,選擇最小的;如果E2是負的,選擇最大的
if E1 >= 0:
j = min(range(self.m), key=lambda x: self.E[x])
else:
j = max(range(self.m), key=lambda x: self.E[x])
return i, j
def _compare(self, _alpha, L, H):
if _alpha > H:
return H
elif _alpha < L:
return L
else:
return _alpha
def fit(self, features, labels):
self.init_args(features, labels)
for t in range(self.max_iter):
# train
i1, i2 = self._init_alpha()
# 邊界
if self.Y[i1] == self.Y[i2]:
L = max(0, self.alpha[i1] + self.alpha[i2] - self.C)
H = min(self.C, self.alpha[i1] + self.alpha[i2])
else:
L = max(0, self.alpha[i2] - self.alpha[i1])
H = min(self.C, self.C + self.alpha[i2] - self.alpha[i1])
E1 = self.E[i1]
E2 = self.E[i2]
# eta=K11+K22-2K12
eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(
self.X[i2],
self.X[i2]) - 2 * self.kernel(self.X[i1], self.X[i2])
if eta <= 0:
# print('eta <= 0')
continue
alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (
E1 - E2) / eta #此處有修改,根據書上應該是E1 - E2,書上130-131頁
alpha2_new = self._compare(alpha2_new_unc, L, H)
alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (
self.alpha[i2] - alpha2_new)
b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (
alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(
self.X[i2],
self.X[i1]) * (alpha2_new - self.alpha[i2]) + self.b
b2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (
alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(
self.X[i2],
self.X[i2]) * (alpha2_new - self.alpha[i2]) + self.b
if 0 < alpha1_new < self.C:
b_new = b1_new
elif 0 < alpha2_new < self.C:
b_new = b2_new
else:
# 選擇中點
b_new = (b1_new + b2_new) / 2
# 更新參數
self.alpha[i1] = alpha1_new
self.alpha[i2] = alpha2_new
self.b = b_new
self.E[i1] = self._E(i1)
self.E[i2] = self._E(i2)
return 'train done!'
def predict(self, data):
r = self.b
for i in range(self.m):
r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i])
return 1 if r > 0 else -1
def score(self, X_test, y_test):
right_count = 0
for i in range(len(X_test)):
result = self.predict(X_test[i])
if result == y_test[i]:
right_count += 1
return right_count / len(X_test)
def _weight(self):
# linear model
yx = self.Y.reshape(-1, 1) * self.X
self.w = np.dot(yx.T, self.alpha)
return self.w      

其實,我看了下,項目中不僅包含 SVM 的示例代碼,同時也有對應的讀書筆記和概括總結。

《統計學習方法》課件

作者袁春:清華大學深圳研究所學生院,提供了第一版全書 12 章的 PPT 課件。

重磅!李航《統計學習方法》Python 代碼更新,适應第二版!
重磅!李航《統計學習方法》Python 代碼更新,适應第二版!

課件擷取位址:

連結:

https://pan.baidu.com/s/1_boHMIg6DqS7bgFuxlWF7Q

提取碼:ffxy

附加資源

總結整理我之前發表過的關于李航《統計學習方法》的相關資源,彙總如下,詳見文章:

李航《統計學習方法》讀書筆記 李航《統計學習方法》最新資源,筆記、Python 代碼一應俱全! 《統計學習方法》的 Python 代碼來了

參考資料:

https://github.com/wzyonggege/statistical-learning-method https://github.com/WenDesi/lihang_book_algorithm https://blog.csdn.net/tudaodiaozhale