1. 程式人生 > 實用技巧 >.NET 開源專案 StreamJsonRpc 介紹[中篇]

.NET 開源專案 StreamJsonRpc 介紹[中篇]

本文始發於個人公眾號:TechFlow,原創不易,求個關注

今天是機器學習專題的第27文章,我們一起來聊聊資料處理領域的降維(dimensionality reduction)演演算法。

我們都知道,圖片格式當中有一種叫做svg,這種格式的圖片無論我們將它放大多少倍,也不會失真更不會出現邊緣模糊的情況。原因也很簡單,因為這種圖片是向量圖,一般的圖片儲存的是每一個畫素點的顏色值,而在向量圖當中,我們儲存的是向量,也就是起點終點以及顏色。由於向量圖只記錄起點終點,所以無論我們如何放大,圖片都不會失真,而傳統的圖片就做不到這一點。

其實svg就相當於圖片的降維,我們將上百萬的畫素點簡化成了若干個向量

完成了圖片的儲存,大大減少了資料的規模。機器學習領域中的降維演演算法其實也是差不多的原理。

背景與原理

現在降維演演算法這個詞已經越來越少聽到了,在面試當中也很少被提及,這是有時代因素的。因為現在的計算資源以及儲存資源越來越廉價了,在以前很難承擔的計算量,現在變得越來越輕鬆。所以相對而言,降維演演算法沒有之前熱門了,也越來越少在面試當中出現。

從現狀倒推回從前,我們大概可以猜到,在若干年以前,當我們面臨海量無法承擔的資料的時候,降維演演算法是多麼的重要。因為,我們都知道,機器學習訓練的速度和它使用的資料量有這非常密切的關係,使用10維特徵和使用100維特徵的模型的收斂速度至少是10倍以上的差距。那麼,自然而然地我們就會想到,如果有某種方法可以將100維的資料”壓縮“成10維,該有多好?

但問題來了,資料不是實體,我們真的可以隨意壓縮嗎,這其中的原理是什麼呢?

最根本的原理是既然特徵可以用來訓練模型,那麼特徵的分佈和label的分佈必然是有一定的內在聯絡的。也就是說資料並不是隨意分散的,而是彼此之間有聯絡的。我們各種各樣的壓縮演演算法,本質上都是利用了資料之間的關聯。

舉個不是非常恰當,但是很直觀的例子。假設說我們現在有三個特徵,分別是一個人的考試成績、智商以及努力程度。我們會很明顯地發現,考試成績和智商以及努力程度這兩個特徵高度相關。如果我們能夠找到它們之間的關聯,我們完全可以去掉考試成績這個特徵,而通過智商、努力程度和它的這種關聯來推算出這個值來。當然既然是推算出來的,顯然會和原本的值有一定的誤差,這也是不可避免的。

從這個例子當中,我們可以明確兩點,首先,壓縮資料是利用的資料分佈的關聯或者是特性,如果是完全隨機的資料是無法降維壓縮的。其次,降維壓縮必然會帶來資訊損失,也就是誤差,這是不可避免的。

降維演演算法

降維壓縮的演演算法有好幾種,常見的有PCA、ICA和FA,下面我們來簡單介紹一下。

首先是PCA,PCA的英文全稱是Principal Component Analysis即主成分分析。這種方法的主要原理是對資料進行座標變換,即將資料從原來的座標系更換到新的座標系。新的座標軸是通過最大方差理論推導得到的,即新的座標軸包含了原始資料中大部分的方差,這裡的方差可以理解成資訊。

ICA的英文是Independent Component Analysis即獨立成分分析,在這個演演算法當中它假設資料是通過N個資料來源生成的。假設資料是這N個資料來源資料混合觀察的結果。這些資料來源在統計上是互相獨立的,如果資料來源的數目少於原始特徵的數目,也可以完成降維。

最後是FA即Factor Analysis即因子分析。在因子分析當中,我們假設樣本當中存在一些隱變數,我們假設樣本是這些隱變數和一些噪音的線性組合。那麼只要這些隱變數的數量少於原始特徵的數量,我們就可以用這些隱變數來作為新的資料從而實現降維。

這三種降維演演算法雖然各不相同,但是核心的思路都是一致的。都是假設資料的分佈滿足某一種特性,通過利用這一種特性來對資料進行壓縮。這其中使用範圍最廣的是PCA,所以我們著重來瞭解一下PCA的原理以及實現。

理論推導

關於PCA演演算法有兩種通俗的解釋,一種是最大方差理論,另外一種是最小化降維損失,這兩個思路推匯出的結果是一樣的。相比之下,最大方差理論更加容易理解一些,所以我們就選擇最大方差理論來做個簡單的解釋。

在訊號系統當中,我們普遍認為訊號具有較大的方差,而噪音擁有較小的方差。信噪比就是訊號與噪聲的方差比,這個比值越大越好,越大說明噪音越小,訊號的質量越高。比如下圖當中的這個資料分佈,我們可以在原始資料當中找到兩個正交軸,根據方差最大理論,我們會把方差大的那個軸看成是訊號,方差小的看成是噪音。

根據這個思路,最好的k維特徵是將n維的樣本轉換成k維座標之後,擁有最大方差的k個

協方差

到這裡,我們雖然知道了要獲取方差最大的方向作為新的座標軸,但是如果我們直接去計算的話是會有問題的。最大的問題在於我們沒辦法選出K個來,如果只是選擇類似的K個方向,這K個軸的資訊都差不多,會丟失大量的資訊。所以我們不僅要選擇K個軸,而且要保證這K個軸儘可能線性無關

要做到線性無關,也就是說這K個軸應該是彼此正交的。如果兩個軸正交,可以進一步得到這兩個軸的協方差為零。為了簡化運算,我們可以先讓原始資料全部減去各自特徵的均值。在去除均值之後,兩個特徵的協方差可以表示為:

兩個特徵正交等價於它們的協方差為0,我們假設去除了均值之後的矩陣為X,我們來寫出它的協方差矩陣。

協方差矩陣

對於去除了均值的矩陣X而言,有一個性質是它的協方差矩陣。我們可以來簡單證明一下,假設矩陣當中只有兩個特徵a和b,那麼我們將它按行寫成矩陣:

我們假設X的協方差矩陣為C,那麼C是一個對稱矩陣,它的對角線上的元素表示各個特徵的方差,其他的元素則表示特徵之間的協方差。我們的目標是希望能夠得到一個類似形式的對角矩陣,也就是說除了對角線之外的其餘元素全為0,這樣這些特徵之間就是正交矩陣,我們根據對角線上的值挑選出方差最大的K個特徵即可。

我們的目的和方向已經很明確了,距離終點只有一步之遙,但是這一步怎麼邁過去呢?

對角化

這裡我們採用逆向思維來思考,假設我們已經找到了矩陣P,通過P對X進行線性變換的結果是Y,那麼Y=PX,我們假設Y的協方差矩陣為D,那麼根據剛才我們推導的結論可以得到:

我們希望D是一個對角矩陣,所以我們要尋找的就是P,P找到之後一切都迎刃而解。因為D是一個對角矩陣,我們將它對角的元素從大到小排列之後,對應P的行組成的矩陣就是我們尋找的基。我們用P的前K行組成的新矩陣對原始資料X進行線性變換,就將它從n維降低到了K維。

所以問題就只剩下了一個,這個P矩陣要怎麼求呢?我們幹想是很困難的,其實資料家們已經給了我們答案,就是C矩陣的特徵向量

由於C是對稱矩陣,根據線性代數的原理,它有如下兩條性質:

  1. 對稱矩陣不同的特徵值對應的特徵向量必然正交
  2. 特徵值是實數,K重特徵值對應的線性無關的特徵向量剛好有K個

根據這兩條性質,我們可以得到,對於n*n的矩陣C來說,我們可以找到n個特徵向量。我們將它們按列組成矩陣:

我們通過E可以將C對角化:

我們對中的特徵值從大到小排列,選出前K個特徵值對應的特徵向量組成矩陣即得到了最終的結果P。

最後,我們整理一下上述的整個過程。

  1. 每一維特徵減去平均值
  2. 計算協方差矩陣
  3. 求解協方差矩陣的特徵值和特徵向量
  4. 對特徵值降序排序,選擇其中最大的K個,然後將對應的K個特徵向量作為行向量組成特徵向量P
  5. 轉換之後的結果

我們把這個邏輯整理一下,寫成程式碼:

import numpy as np

def pca(df, k):
mean = np.mean(df, axis=0)
new_df = df - mean
# 計算協方差矩陣,也可以用公式自己算
cov = np.cov(new_df, rowvar=0)
# 求解矩陣特徵值和特徵向量
eigVals, eigVects = np.linalg.eig(np.mat(cov))
# 對特徵值排序,選最大的K個,由於是從小到大排,所以我們取反
eigValIndice = np.argsort(-eigVals)
# 構建變換矩陣
n_eigValIndice = eigValIndice[:k]
n_eigVect = eigVects[:, n_eigValIndice]
data_ret = new_df.dot(n_eigVect)
return data_ret

實戰驗證

為了驗證程式效果,我們找了一份經典的機器學習資料:http://archive.ics.uci.edu/ml/datasets/SECOM。

我們把它下載下來之後,用pandas讀入進來:

可以看到它的特徵有590維,展開看的話會發現特徵當中有許多空值:

我們對它進行一個簡單地預處理,將空值替換成特徵均值,並且再讀入label的值:

為了驗證PCA降維的效果,我們用同樣一份資料,用同樣的模型,比較一下做PCA之前和之後模型的效果

這裡我選擇的是隨機森林,其實不管用什麼模型都大同小異。我們將資料拆分成訓練資料與測試資料,並且呼叫skelarn庫當中的隨機森林完成訓練和預測,最後計算模型在測試集當中的表現。說起來挺複雜,但是由於sklearn替我們完成了大量的工作,所以用到的程式碼並不多:

我們可以看到,在PCA之前,隨機森林在測試集上的表現是92.3%的準確率。

接下來,我們用同樣的資料和模型來驗證PCA之後對於模型效能的影響。為了保證資料集的完全一致,我們把測試集的隨機種子也設定成一樣

可以看到模型在測試集上的準確率完全一樣,說明PCA並沒有過多降低模型的效能,和我們的預期一致。

總結

在今天的文章當中,我們詳細介紹並推導了PCA背後的原理,並採取實際資料集驗證了PCA演演算法的效果。從最後的結果上來看,雖然我們將590維的特徵縮減到了10維,但是模型的效果卻幾乎沒有多大影響,可見PCA的威力。

當然,這背後的因素很多,除了PCA本身的原理之外,和資料的分佈以及訓練測試樣本的數量也有關係。在極端場景下,可能特徵的數量非常多,含有大量的噪音,如果我們不做降維直接訓練的話,很有可能導致模型很難收斂。在這種情況下,使用降維演演算法是必要的,而且會帶來正向的提升。如果特徵數量不多,模型能夠收斂,使用降維演演算法可能沒什麼助益,而且會稍稍降低模型的效果。但在一般的情況下,資料集特徵的分佈也符合二八定律,即20%的特徵帶來80%以上的貢獻,大部分特徵效果不明顯,或者噪音很多。在這種情況下,使用PCA進行降維,幾乎是一定起到正向作用的。

當然在實際的應用場景當中,降維演演算法用的越來越少,除了計算能力提升之外,另外一個很重要的原因是深度學習的興起。深度神經網路本身就帶有特徵篩選的效果,它自己會選擇合適的特徵組合達到最好的效果,所以很多特徵處理和降維等操作顯得不是特別有必要了。雖然如此,但是演演算法本身的思想還是很有借鑑作用,PCA演演算法在Kaggle比賽當中使用頻率也很高,對它進行詳細地瞭解和學習還是很有必要的。

今天的文章就到這裡,如果喜歡本文,可以的話,請點個贊和關注吧,給我一點鼓勵,也方便獲取更多文章。

本文使用 mdnice 排版