機器學習與線性代數
自打我開始學習機器學習的相關知識以來,線性代數就一直是制約我讀懂算法的最大短板。儘管經過大概兩個月的學習,我的代數知識積累似乎已經足以讓我不害怕任何數學推導了,但是畢竟是將來要賴以生存的本領,如果有一天忘記了它們我會很沮喪的。所以這裏我還是決定整理一下與機器學習相關的所有數學知識,方便隨時查閱,杜絕忘卻。
筆記將以花書《深度學習》爲思維導向,從底到上梳理各種可能用到的數學知識。
代數的運算律
和標量類似的運算律有分配律、結合律,而一般不滿足交換律,因爲代數是有維度的。
此外代數可以轉置,也就是沿對角線反轉矩陣。代數乘積的轉置滿足
跡
只看這個定義看不出什麼,體驗它的作用還是在實踐中。它有着非常好用的交換律,即使兩個矩陣一個是nxn一個是mxm
範數
範數可以把向量映射爲非負標量
範數常用來評估高維空間中的距離,經典的應用就是正則化和聚類。常用的範數有L1範數,即曼哈頓距離,L2範數即歐幾里得距離,有時還會使用Linf範數,即計算向量中最大幅值元素的絕對值。
矩陣逆
單位矩陣一般寫成,是對角線元素爲1其他爲0的方陣。爲此我們有矩陣的逆矩陣的定義
做題和考試時求矩陣逆我們可能會採取手算的方法,就是通過多次基本矩陣變換把A變成I,這是同樣把這些操作施加於單位矩陣上,就得到逆矩陣。矩陣可逆的條件是矩陣正定,即矩陣中不存在線性相關項。同時,單位正交矩陣的逆矩陣就是它自己的轉置。
特徵值分解
應某些問題需要,我們經常會用到矩陣對角化的運算。對一個方陣B,我們希望得到
其中A是對角矩陣,即對角線上的元素非零其他爲零。而P是單位正交矩陣,單位正交矩陣的每一列對應的列向量都是單位向量,且兩兩正交。也就是滿足
這樣的矩陣分解方法也可以寫成多個向量外積的加和
這種分解得到的對角矩陣中的標量稱爲特徵值,每個特徵值都會對應一個特徵向量。一般的矩陣不一定能對角化,但是對稱矩陣一定可以對角化。正定矩陣的特徵值都是非負的。
行列式
計算大家都懂,它會得到矩陣所有特徵值的乘積。一個有用的性質是, 如果方陣線性相關, 行列式的值爲0.
SVD分解
我們不能對一般的矩陣(不一定是方陣)進行對角化,但是我們可以用一些運算構造出能分解的對稱矩陣。
爲對稱正定矩陣,因爲
很容易看出,M的轉置仍然是自己,且不論是用怎樣的特徵向量,得到的特徵值都是非負數。這樣我們就能對這個進行SVD分解
兩個矩陣分解得到的中間的對角矩陣,也就是得到的特徵值相同。
這樣就能對任意的矩陣進行奇異值的分解。得到的對角矩陣中的標量稱爲奇異值,左側矩陣的向量稱爲左奇異向量,右側稱爲右奇異向量。
SVD分解和特徵值分解都常被用作矩陣的壓縮保存,我們可以不保存所有特徵向量,只保存一部分特徵向量來重構原矩陣。
應用1:線性迴歸
我們在學習線性代數時知道用矩陣方法求解線性方程組,事實上對於一個線性方程組,我們完全可以用來計算線性方程組的解。當然A可逆的條件是A爲方陣且A中的每個行向量線性無關,也就是A正定。但是實際使用中我們並不會有那麼好的運氣,在做線性迴歸時,我們的數據集的有效數據個數rank和數據維度m不總是相等的。當rank大於m時線性方程組無解,當rank小於m時方程組有無窮個解。解決這個問題的簡單方法是使用僞逆。
我們將不追求得到盡善盡美的解,而是追求最小化均方誤差。這種凸優化問題,我們只需要對均方誤差求導就能得到最小化誤差的解。
這時得到的解是
當A矩陣像上面的列數m多於行數n,則上面的方法並不能得到好的解,因爲這時A的秩(最大線性無關行的個數)不會大於n,而n<m,對mxm的方陣我們是無法求逆的。這時我們需要引入L2正則化項讓A可逆,我們把上面的損失函數改成
這時就可以求逆了,可以直觀地理解,我們在每個向量的第m維加上了一點點的增量,這樣即使原本線性相關的向量也會被變成線性無關。這樣,我們就能對任意的A求解一個線性方程組近似解,也就是線性迴歸解。
上面的這個又叫僞逆,我們一般會用奇異值分解幫助我們計算僞逆。即,對角矩陣D的僞逆就是對D的非零元素取倒數再轉置。如果我們用僞逆在數據集上進行線性迴歸,得到的解會讓歐幾里得距離,也就是上面的損失函數最小。同時如果引入正則化項,還能在m多於rank時,從無窮個解中找到最小范數的解x。
實例:小車初速度與加速度測定
我們在物理實驗中會讓小車在光滑平面上運動, 通過記錄時間和路程構成的多個數據點並做數據分析, 得到小車實際的初速度和加速度. 這個過程實際上是一個線性迴歸, 我們知道路程-時間公式可以寫成
那麼問題實際上是一個三元的線性迴歸, 變量分別是, , , 我們把三元數據和路程做線性迴歸, 就能得到一個權值向量x, 它的三個維度的意義就是上面的.
import numpy as np
# 小車斜面下落實驗, 加速度爲4.9, 初速度2, 初始路程1
t = np.linspace(0, 5, 20)
s = 1 + 2*t + 4.9*t**2
# 加一些噪聲,可以理解爲實驗中的測量誤差
s += np.random.randn(*s.shape)*0.01
# 構造數據的三元矩陣
A = np.concatenate([np.ones(t.shape).reshape(1,-1),
t.reshape(1,-1),
(t**2).reshape(1,-1)]).T
# 計算線性迴歸的權值向量x
x = np.linalg.pinv(A).dot(s)
print("Displacement: %.4f"%(x[0]))
print("Initial velocity: %.4f"%(x[1]))
print("Acceleration: %.4f"%(x[2]))
Displacement: 0.9971
Initial velocity: 1.9972
Acceleration: 4.9009
應用2:主成分分析(PCA)
我們希望通過一個線性變換,把現有的數據集通過變換矩陣變換到d維,從而實現數據降維的需要。這個W要滿足正交基的性質,即,是單位正交矩陣。
爲了實現"變換後的數據丟失儘可能少的信息",我們會定義一個損失函數,讓這些降維後的數據點分得儘可能開。這個損失函數就設定爲變換後數據集的方差,我們希望最大化方差。爲了處理起來簡便,我們在一開始就把X標準化處理,讓它的均值爲零,那麼降維後的均值。
這個損失函數可以用上面跡的定義寫成非常好看的矩陣乘法形式
加上上面的W單位正交條件,這個問題是一個約束優化問題,最優解一定滿足KKT條件。構造出拉格朗日函數,設$\lambda $是拉格朗日乘子的d維行向量。我們有
這說明W中的每個向量都滿足的條件,也就是,W中的每個向量都是的特徵向量。但是特徵向量可能有很多,我們只需要d個,該選擇哪d個呢?讓我們回到上面的誤差函數E
我們會發現我們想最大化的誤差E就是w特徵向量對應的特徵值的乘積。如果我們要最大化這個誤差,只需要找最大的d個特徵值即可。
綜上,算法的流程爲,對X進行標準化,然後對進行特徵值分解,並取出前d個最大特徵值對應的特徵向量拼接成W,返回,算法結束。
實例:數據可視化
在數據科學中, 我們要處理的數據往往超過三個維度, 幾十維甚至上百維的數據是很常見的. 爲了直觀的觀察數據的分佈與它的特徵之間的關係, 我們常常要用降維手段把它降到2維平面, 再plot出來觀察. PCA可以勝任這個工作.
這裏我們用經典的乳腺癌數據集(30維特徵)做降維到2維, 並觀察數據的分佈和類別的關係. 在此之上判斷我們下一步該用什麼機器學習方法解決問題.
def PCA(X, dim):
'''
X, size(n,m), n個m維的數據點構成的數據集矩陣
dim, 目標降維維度, dim<m
'''
# 歸一化處理
means = np.mean(X,axis = 0)
X = X.copy()-means
# 計算要特徵值分解的協方差矩陣
Covs = X.T.dot(X)
# 特徵值分解
lamda,V = np.linalg.eigh(Covs)
index = np.argsort(-lamda)[:dim]
W = V[:,index]
return X.dot(W)
# 導入數據集
from sklearn import datasets
X,y = datasets.load_breast_cancer(return_X_y = True)
X_2dim = PCA(X, 2)
import matplotlib.pyplot as plt
import matplotlib
plt.figure(figsize=(8,6))
ec_list = ['b' if n==0 else 'r' for n in y]
plt.scatter(X_2dim[:,0],X_2dim[:,1],c = 'w', edgecolor = ec_list)
plt.show()
可以看見的是良性腫瘤(紅色)的分佈較爲集中, 表現出高斯簇的形狀, 而惡性腫瘤(蘭色)則比較發散
所以我們可以把這個問題用二分類模型來解, 也可以用無監督的多維高斯模型構造異常檢測系統
應用3:PageRank
page rank是google在世紀初使用的搜索引擎技術, 它是一種結合了線性代數, 圖論和數值計算的高效機器學習算法. 但究其原理其實並不複雜, 我們先構思一個圖模型, 它的每個頂點是一個獨立的網頁. 這些網頁之間被超鏈接互聯, 從而讓這個圖模型是一個有向圖. 這時我們就能給出一個假設, 網絡中的用戶流在頂點V時, 有等概率流向它的所有其他子頂點. 這樣的假設建立了網頁間的影響力關係線性方程組, 舉個例子, 下面的網頁圖模型.
也就是, 我們把每個頂點的分流因子1平均賦值到所有子結點, 形成一個nxn的矩陣M. 所有頂點的影響力滿足線性方程組
解一個這樣的線性方程組就能得到解x, 它就是所有網頁的影響力值, 可以通過排序被用在網頁的推薦上. 但是這樣的解法是有一定問題的, 一個是效率的問題, 我們的網頁數目通常會很多, 100k以上都是比較少的了, 這樣的線性方程組的系統不適合直接求解, 而且即使直接解, 也不能保證解是唯一的. 因此我們一般使用帶約束的迭代解法, 一般如下面的流程.
- 初始化x爲一個的向量
- 迭代計算
- x不再變化時, 停止迭代
這是不動點迭代的思想, 因爲M的每一列的所有元素和爲1, 迭代計算可以保證
始終成立, 而這樣的迭代計算會讓x向真正的解不斷靠近直至收斂. 這個迭代次數一般不會太多, 所以這種解法能適用於有一定特殊性的本問題, 而且效率比RREF的方法高效得多
這樣的解法可行, 但是我們仍然會面臨兩個很重要的問題, 它們會讓解變得無效化.
- 等級泄露(Rank Leak):如果一個網頁沒有出鏈,就像是一個黑洞一樣,吸收了其他網頁的影響力而不釋放,最終會導致其他網頁的 PR 值爲 0。
- 等級沉沒(Rank Sink):如果一個網頁只有出鏈,沒有入鏈(如下圖所示),計算的過程迭代下來,會導致這個網頁的 PR 值爲 0
爲此我們可以引入一個合理的另一個假設, 我們假設在瀏覽網頁時, 用戶不會老老實實跟着超鏈接走下去, 很有可能看到一半感覺無聊了, 就隨機跳到了一個另外的界面. 也就是, 我們引入這樣的隨機瀏覽因素, 把原來的M矩陣寫成新的PR矩陣
這樣的變化會讓我們的計算收斂到一個有意義的解, 避免了無效解的產生
實例: 網頁推薦
我們按照下面的網頁連接狀況進行建模, 並計算出網絡影響力, 以此作爲排序標準進行網頁推薦.
hyperlinks = [
(3, 0),
(3, 1),
(4, 3),
(4, 1),
(1, 2),
(2, 1),
(5, 1),
(4, 5),
(5, 4),
(6, 1),
(6, 4),
(7, 1),
(7, 4),
(8, 1),
(8, 4),
(9, 4),
(10, 4)
]
n = 11
hyperlinks = np.array(hyperlinks)
M = np.zeros((n,n))
M[hyperlinks[:,1],hyperlinks[:,0]] = 1
for i in range(n):
if np.sum(M[:,i])>0:
M[:,i] /= np.sum(M[:,i])
d = 0.175
PR = (1-d)*M + d*np.ones((n,n))/n
x = np.ones((n,1))/n
for iter in range(50):
x = PR.dot(x)
x /= np.sum(x)
x = x[:,0]
x *= 100
sorted_indices = np.argsort(-x)
for i in sorted_indices:
name = chr(ord('A')+i)
print("Page "+name+": Score: %5.3f"%(x[i]))
Page B: Score: 38.322
Page C: Score: 34.143
Page E: Score: 8.163
Page D: Score: 3.943
Page F: Score: 3.943
Page A: Score: 3.308
Page G: Score: 1.636
Page H: Score: 1.636
Page I: Score: 1.636
Page J: Score: 1.636
Page K: Score: 1.636
小結
線性代數和概率論給我的感覺是, 它們就是機器學習和深度學習的基石, 比起最優化理論還要重要. 早知如此大一就不聽我們的廢柴老師講的線代了, 自己看名校網課不是美滋滋? 我學線代時完全不知道這東西有什麼用, 直到自己開始接觸高級一點的機器學習問題或者物理建模, 才知道沒學好這東西是一個多大的短板.