資料分析中的降維方法初探

Andrew.Hann發表於2017-03-21

0. 引言

0x1:降維定義

降維是將高維資料對映到低維空間的過程,該過程與資訊理論中有失真壓縮概念密切相關。同時要明白的,不存在完全無損的降維。

有很多種演算法可以完成對原始資料的降維,在這些方法中,降維是通過對原始資料的線性變換實現的。即,如果原始資料是 d 維的,我們想將其約簡到 n 維(n < d),則需要找到一個矩陣使得對映。選擇 W 的一個最自然的選擇的是在降維的同時那能夠復原原始的資料 x,但通常這是不可能,區別只是損失多少的問題。

0x2:為什麼要降維

降維的原因通常有以下幾個:

1. 首先,高維資料增加了運算的難度
2. 其次,高維使得學習演算法的泛化能力變弱(例如,在最近鄰分類器中,樣本複雜度隨著維度成指數增長),維度越高,演算法的搜尋難度和成本就越大。
3. 最後,降維能夠增加資料的可讀性,利於發掘資料的有意義的結構

以一個具體的業務場景來說:

malware detection這種non-linear分類問題中,我們提取的feature往往是sparce high-dimension vector(稀疏高維向量),典型地例如對malware binary的code .text section提取byte n-gram,這個時候,x軸(程式碼段的byte向量)高達45w,再乘上y軸(最少也是256),直接就遇到了維數災難問題,導致神經網路求解速度極慢,甚至記憶體MMO問題。

這個時候就需要維度約簡技術,值得注意的是,深度神經網路CNN本身就包含“冗餘資訊剔除”機制,在完成了對訓練樣本的擬合之後,網路之後的權重調整會朝著剔除訓練樣本中的資訊冗餘目標前進,即我們所謂的資訊瓶頸。

Relevant Link:

http://www.tomshardware.com/news/deep-instinct-deep-learning-malware-detection,31079.html
https://www.computerpoweruser.com/article/18961/israeli-company-aims-to-be-first-to-apply-deep-learning-to-cybersecurity
https://www.technologyreview.com/s/542971/antivirus-that-mimics-the-brain-could-catch-more-malware/
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/MalwareRandomProjections.pdf
http://e-nns.org/
https://arxiv.org/pdf/1703.02244.pdf
http://www.dartmouth.edu/~gvc/
http://www.cs.toronto.edu/~gdahl/ 

 

1. PCA主成分分析(Principal components analysis)

0x1:PCA演算法模型

令 x1,....,xm 為 m 個 d 維向量,我們想利用線性變換對這些向量進行降維。給定矩陣,則存在對映,其中是 x 的低維表示。

另外,矩陣能夠將壓縮後的資訊(近似)復原為原始的訊號。即,對於壓縮向量,其中 y 在低維空間中,我們能夠構建,使得是 x 的復原版本,處於原始的高維空間中。

在PCA中,我們要找的壓縮矩陣 W 和復原矩陣 U 使得原始訊號和復原訊號在平方距離上最小,即,我們需要求解如下問題:

,即儘量無失真壓縮。

令(U,W)是上式的一個解,則 U 的列是單位正交的(即上的單位矩陣)以及

PCA(Principal Component Analysis)是一種常用的資料分析方法。PCA通過線性變換將原始資料變換為一組各維度線性無關(單位正交)的表示,可用於提取資料的主要特徵分量,常用於高維資料的降維。

其實“資訊瓶頸理論”的核心觀點也是認為:所有的資訊都是存在冗餘的,其需要抽取其中最核心關鍵的部分就可以大致代表該原始資訊。

降維當然意味著資訊的丟失,不過鑑於實際資料本身常常存在的相關性,我們可以想辦法在降維的同時將資訊的損失儘量降低

0x2: 在討論PCA約簡前先要討論向量的表示及基變換 - PCA低損壓縮的理論基礎

既然我們面對的資料被抽象為一組向量,那麼下面有必要研究一些向量的數學性質。而這些數學性質將成為後續匯出PCA的理論基礎

1. 內積與投影

向量運算內積。兩個維數相同的向量的內積被定義為,即向量對應的各維度元素兩兩相乘累加和。

(a1,a2,⋯,an)T⋅(b1,b2,⋯,bn)T=a1b1+a2b2+⋯+anbn

內積運算將兩個向量對映為一個實數。其計算方式非常容易理解,但是其意義並不明顯。

下面我們分析內積的幾何意義。假設A和B是兩個n維向量,我們知道n維向量可以等價表示為n維空間中的一條從原點發射的有向線段,為了簡單起見我們假設A和B均為二維向量,則A=(x1,y1)B=(x2,y2)。則在二維平面上A和B可以用兩條發自原點的有向線段表示。現在我們從A點向B所在直線引一條垂線。我們知道垂線與B的交點叫做A在B上的投影,再設A與B的夾角是a,如下圖所示:

則投影的向量長度為|A|cos(a),其中是向量A的模,也就是A線段的標量長度。注意這裡我們專門區分了向量長度和標量長度,標量長度總是大於等於0,值就是線段的長度;而向量長度可能為負,其絕對值是線段長度,而符號取決於其方向與標準方向相同或相反。

接著我們將內積表示為另一種我們熟悉的形式:。A與B的內積等於:A到B的投影長度乘以B的模。再進一步,如果我們假設B的模為1,即讓|B|=1,那麼就變成了,可以看到:設向量B的模為1,則A與B的內積值等於A向B所在直線投影的向量長度

這就是內積的一種幾何解釋!!

2. 基

上文說過,一個二維向量可以對應二維笛卡爾直角座標系中從原點出發的一個有向線段

在代數表示方面,我們經常用線段終點的點座標表示向量,例如上面的向量可以表示為(3,2),不過我們常常忽略,只有一個(3,2)本身是不能夠精確表示一個向量的。我們仔細看一下,這裡的3實際表示的是向量在x軸上的投影值是3,在y軸上的投影值是2。

也就是說我們其實隱式引入了一個定義:以x軸和y軸上正方向長度為1的向量為標準。那麼一個向量(3,2)實際是說在x軸投影為3而y軸的投影為2。注意投影是一個向量,所以可以為負。
更正式的說,向量(x,y)實際上表示線性組合 

所有二維向量都可以表示為一定數量的基的線性組合。此處(1,0)和(0,1)叫做二維空間中的一組基

所以,要準確描述向量,首先要確定一組基,然後給出在基所在的各個直線上的投影值,就可以了。只不過我們經常省略第一步,而預設以(1,0)和(0,1)為基

我們之所以預設選擇(1,0)和(0,1)為基,當然是比較方便,因為它們分別是x和y軸正方向上的單位向量,因此就使得二維平面上點座標和向量一一對應,非常方便。

但實際上任何兩個線性無關的二維向量都可以成為一組基(基不一定要正交,正交是一個更強的條件),所謂線性無關在二維平面內可以直觀認為是兩個不在一條直線上的向量(這個概念非常重要,因為PCA分析中用於降維投影的基常常就不是x/y軸單位向量)

這裡就引出了一個概念,座標是一個相對的概念,只是我們平時見標準的0-90.的座標軸看多了,其實所有的向量/座標都是一個相對於座標軸的概念值而已。

另外這裡要注意的是,我們列舉的例子中基是正交的(即內積為0,或直觀說相互垂直),但可以成為一組基的唯一要求就是線性無關,非正交的基也是可以的。不過因為正交基有較好的性質,所以一般使用的基都是正交的。

我們來繼續看上圖,(1,1)和(-1,1)也可以成為一組基。一般來說,我們希望基的模是1,因為從內積的意義可以看到,如果基的模是1,那麼就可以方便的用向量點乘基而直接獲得其在新基上的座標了!

實際上,對應任何一個向量我們總可以找到其同方向上模為1的向量,只要讓兩個分量分別除以模就好了。例如,上面的基可以變為,各個基的模為1

3. 基變換的矩陣表 - 基變換是有損的

在上一小節我們討論了一個非常重要的概念,即任意的一組線性無關的向量都可以表示為基,而不僅限於90°的 x-y 座標軸。

同時我們現在熟悉的(x,y)座標其實本質是在一組特定基上的表示方法,一旦我們的基發生概念,座標值也會發生改變,這個改變的過程就叫基變換。

我們換一種更簡便的方式來表示基變換,繼續以上圖的座標系為例:

將(3,2)變換為新基上的座標,就是用(3,2)與第新基的各分量分別做內積運算(將一個座標系上的點"轉換"到另一個座標系本質就是在投影),得到的結果作為第新的座標。實際上,我們可以用矩陣相乘的形式簡潔的表示這個變換,這裡是新基的向量,(3,2)是原基的向量。

其中矩陣的兩行分別為兩個基,乘以原向量,其結果剛好為新基的座標。

可以稍微推廣一下,如果我們有m個二維向量,只要將二維向量按列排成一個兩行m列矩陣,然後用“基矩陣”乘以這個矩陣,就得到了所有這些向量在新基下的值。例如(1,1),(2,2),(3,3),想變換到剛才那組基上,則可以這樣表示

於是一組向量的基變換被幹淨的表示為矩陣的相乘

一般的,如果我們有M個N維向量,想將其變換為由R個N維向量表示的新空間中,那麼首先將R個基按行組成矩陣A,然後將原始向量按列組成矩陣B,那麼兩矩陣的乘積AB就是變換結果,其中AB的第m列為A中第m列變換後的結果。

注意:

1. N維向量,必須有N維的基,否則無法投影。N 的作用可以理解為一個“接收器”,對原始向量的每一個維度都必須要有一個對應的維度去對應接收。

2. R代表基的個數,注意,這裡 R 的數量可以是任意多個,區別只是向多少個軸進行投影的區別而已,如果 R < N,則轉換後維數減少了;如果 R > N,則轉換後維數增加了。

3. M是原始向量的數量,數量在基變換前後是保持不變的。

數學表示為

(R x N). (N x M)=(R x M)

其中pi是一個行向量,表示第i個基;aj是一個列向量,表示第j個原始資料記錄

特別要注意的是,這裡R可以小於N,而R決定了變換後資料的維數。也就是說,我們可以將 N維資料變換到更低維度的空間中去,變換後的維度取決於基的數量。因此這種矩陣相乘的表示也可以表示"降維變換"

最後,上述分析同時給矩陣相乘找到了一種物理解釋:兩個矩陣相乘的意義是將右邊矩陣中的每一列列向量變換到左邊矩陣中每一行行向量為基所表示的空間中去。更抽象的說,一個矩陣可以表示一種線性變換。

0x3: 協方差矩陣及優化目標 - 如何找到損失最低的變換基

上面我們討論了選擇不同的基可以對同樣一組資料給出不同的表示,而且如果基的數量少於向量本身的維數,則可以達到降維的效果。

但是我們還沒有回答一個最最關鍵的問題:如何選擇基才是最優的。或者說,如果我們有一組N維向量,現在要將其降到K維(K小於N),那麼我們應該如何選擇K個基才能最大程度保留原有的資訊
假設我們的資料由五條記錄組成,將它們表示成矩陣形式:

其中每一列為一條資料記錄(列向量),而一行為一個欄位。為了後續處理方便,我們首先將每個欄位內所有值都減去欄位均值,其結果是將每個欄位都變為均值為0。我們看上面的資料,第一個欄位均值為2,第二個欄位均值為3,所以變換後:

我們可以看下五條資料在平面直角座標系內的樣子

現在問題來了:如果我們必須使用一組新的基來表示這些資料,又希望儘量保留原始的資訊(保留原始資料的概率分佈),我們應該如何選擇?

通過上一節對基變換的討論我們知道,這個問題實際上是要在二維平面中選擇一個方向,將所有資料都投影到這個方向所在直線上,用投影值表示原始記錄。這是一個實際的二維降到一維的問題。
那麼如何選擇這個方向(或者說基)才能儘量保留最多的原始資訊呢?一種直觀的看法是:希望投影后的投影值儘可能分散。資料越分散,可分性就越強,可分性越強,概率分佈儲存的就越完整
以上圖為例:

可以看出如果向x軸投影,那麼最左邊的兩個點會重疊在一起,中間的兩個點也會重疊在一起,於是本身四個各不相同的二維點投影后只剩下兩個不同的值了,這是一種嚴重的資訊丟失。

同理,如果向y軸投影最上面的兩個點和分佈在x軸上的兩個點也會重疊。

所以看來x和y軸都不是最好的投影選擇。我們直觀目測,如果向通過第一象限和第三象限的斜線投影,則五個點在投影后還是可以區分的。
下面,我們用數學方法表述和討論這個問題

1. 投影后的新座標點的方差 - 一種表徵資訊丟失程度的度量

上文說到,我們希望投影后投影值儘可能分散,而這種分散程度,可以用數學上的方差來表述。此處,一個欄位的方差可以看做是每個元素與欄位均值的差的平方和的均值,即

在使用應用中,在執行PCA之前需要對樣本進行“中心化”。即,我們首先計算,然後再進行PCA過程。

由於上面我們已經將每個欄位的均值都化為0了,因此方差可以直接用每個元素的平方和除以元素個數表示

於是上面的問題被形式化表述為:尋找一個一維基,使得所有資料變換為這個基上的座標表示後,方差值最大

2. 協方差

對於二維降成一維的問題來說,找到那個使得方差最大的方向就可以了。不過對於更高維,還有一個問題需要解決。

考慮三維降到二維問題。與之前相同,首先我們希望找到一個方向使得投影后方差最大,這樣就完成了第一個方向的選擇,繼而我們選擇第二個投影方向。如果我們還是單純只選擇方差最大的方向,很明顯,這個方向與第一個方向應該是“幾乎重合在一起”,顯然這樣的維度是沒有用的,因此,應該有其他約束條件。

從直觀上說,讓兩個欄位儘可能表示更多的原始資訊,我們是不希望它們之間存在(線性)相關性的,因為相關性意味著兩個欄位不是完全獨立,必然存在重複表示的資訊
數學上可以用兩個欄位的協方差表示其相關性,由於已經讓每個欄位均值為0,則

可以看到,在欄位均值為0的情況下,兩個欄位的協方差簡潔的表示為其內積除以元素數m
當協方差為0時,表示兩個欄位完全獨立。為了讓協方差為0,我們選擇第二個基時只能在與第一個基正交的方向上選擇。因此最終選擇的兩個方向一定是正交的。至此,我們得到了降維問題的優化目標

將一組N維向量降為K維(K大於0,小於N),其目標是選擇K個單位(模為1)正交基,使得原始資料變換到這組基上後,各欄位兩兩間協方差為0(各自獨立);
欄位的方差則儘可能大(投影后的點儘可能離散)。在正交的約束下,取最大的K個方差

3. 協方差矩陣 - 欄位內方差及欄位間協方差的統一數學表示

我們看到,最終要達到的目的與欄位內方差及欄位間協方差有密切關係。因此我們希望能將兩者統一表示,仔細觀察發現,兩者均可以表示為內積的形式,而內積又與矩陣相乘密切相關
假設我們只有a和b兩個欄位,那麼我們將它們按行組成矩陣X

然後我們用X乘以X的轉置,並乘上係數1/m

這個矩陣對角線上的兩個元素分別是兩個欄位的方差,而其它元素是a和b的協方差。兩者被統一到了一個矩陣的,根據矩陣相乘的運演算法則,這個結論很容易被推廣到一般情況

設我們有m個n維資料記錄,將其按列排成n乘m的矩陣X,設,則C是一個對稱矩陣,其對角線分別是各個欄位的方差,而第i行j列和j行i列元素相同,表示i和j兩個欄位的協方差

4. 協方差矩陣對角化

根據上述推導,我們發現要達到優化目前,等價於將協方差矩陣對角化:即除對角線(方差要儘可能大)外的其它元素化為0(協方差為0),並且在對角線上將元素按大小從上到下排列,這樣我們就達到了優化目的

設原始資料矩陣X對應的協方差矩陣為C,而P是一組基按行組成的矩陣,設Y=PX,則Y為X對P做基變換後的資料。設Y的協方差矩陣為D,我們推導一下D與C的關係:

現在事情很明白了!我們要找的P不是別的,而是能讓原始協方差矩陣對角化的P。換句話說:

優化目標變成了尋找一個矩陣P,滿足是一個對角矩陣,並且對角元素按從大到小依次排列,那麼P的前K行就是要尋找的基(因為要取儘可能大的方差),用P的前K行組成的矩陣乘以X就使得X從N維降到了K維並滿足上述優化條件

由上文知道,協方差矩陣C是一個是對稱矩陣,線上性代數上,實對稱矩陣有一系列非常好的性質

1)實對稱矩陣不同特徵值對應的特徵向量必然正交。
2)設特徵向量λλ重數為r,則必然存在r個線性無關的特徵向量對應於λλ,因此可以將這r個特徵向量單位正交化。

由上面兩條可知,一個n行n列的實對稱矩陣一定可以找到n個單位正交特徵向量,設這n個特徵向量為e1,e2,,en,我們將其按列組成矩陣

則對協方差矩陣C有如下結論

其中ΛΛ為對角矩陣,其對角元素為各特徵向量對應的特徵值。到這裡,我們發現我們已經找到了需要的矩陣P:

P是協方差矩陣的特徵向量單位化後按行排列出的矩陣,其中每一行都是C的一個特徵向量。如果設P按照ΛΛ中特徵值的從大到小,將特徵向量從上到下排列,則用P的前K行組成的矩陣乘以原始資料矩陣X,就得到了我們需要的降維後的資料矩陣Y

0x4:PCA優化問題的解 - 和協方差矩陣對角化的關係

我們上一小節討論了協方差矩陣的最小化問題,其實PCA演算法模型的優化策略和基變換降維的核心思想是一樣的。都是希望在儘可能不丟失資訊的前提下,讓維度儘可能地約簡。

在PCA中,我們要找的壓縮矩陣 W 和復原矩陣 U 使得原始訊號和復原訊號在平方距離上最小,即,我們需要求解如下問題:

,即儘量無失真壓縮。

令 x1,....,xm是中的任意向量,,以及 u1,....,un是 A 中最大的 n 個特徵值對應的特徵向量。那麼,上式PCA優化問題的解為:令 U 的列等於 u1,....,un,以及

1. 降維後的資訊損失儘可能小,儘可能保留原始樣本的概率分佈
2. 降維後的基之間是完全正交的

0x5: PCA演算法過程

1. PCA演算法過程公式化描述

總結一下PCA的演算法步驟

1. 設有m條n維資料

2. 將原始資料按列組成n行m列矩陣X

3. 將X的每一行(代表一個屬性欄位,即一個維度)進行零均值化,即減去這一行的均值

4. 求出協方差矩陣

5. 求出協方差矩陣的特徵值(矩陣特徵值)及對應的特徵向量(矩陣特徵向量)

6. 將特徵向量按對應特徵值大小從上到下按行排列成矩陣,取前k行組成矩陣P

7. 即為降維到k維後的資料。

總的來說,PCA降維的目的是讓降維後的向量方差最大(最離散),協方差最小(目標維的各個基之間的相關性最小)

2. 一個例子

我們用PCA方法將這組二維資料其降到一維。
因為這個矩陣的每行已經是零均值,這裡我們直接求協方差矩陣

然後求其特徵值和特徵向量。求解後特徵值為

其對應的特徵向量分別是

其中對應的特徵向量分別是一個通解,c1c2可取任意實數。那麼標準化後的特徵向量為

因此我們的矩陣P是

可以驗證協方差矩陣C的對角化

最後我們用P的第一行乘以資料矩陣,就得到了降維後的表示

降維投影結果如下圖

0x6:PCA的限制

PCA也存在一些限制

1. 它可以很好的解除線性相關,但是對於高階相關性就沒有辦法了

對於存在高階相關性的資料,可以考慮Kernel PCA,通過Kernel函式將非線性相關轉為線性相關

2. PCA假設資料各主特徵是分佈在正交方向上,如果在非正交方向上存在幾個方差較大的方向,PCA的效果就大打折扣了

3. PCA是一種無引數技術,無法實現個性優化

也就是說面對同樣的資料,如果不考慮清洗,誰來做結果都一樣,沒有主觀引數的介入,所以PCA便於通用實現,但是本身無法個性化的優化

0x7: 基於原生python+numpy實現PCA演算法

先對原始資料零均值化(在影象裡表現為白化處理,忽略各個影象不同的亮度),然後求協方差矩陣,接著對協方差矩陣求特徵向量和特徵值,這些特徵向量組成了新的特徵空間

1. 零均值化

假如原始資料集為矩陣dataMat,dataMat中每一行代表一個樣本,每一列代表同一個特徵。零均值化就是求每一列的平均值,然後該列上的所有數都減去這個均值。也就是說,這裡零均值化是對每一個特徵而言的

def zeroMean(dataMat):        
    meanVal=np.mean(dataMat,axis=0)     #按列求均值,即求各個特徵的均值  
    newData=dataMat-meanVal  
    return newData,meanVal  

用numpy中的mean方法來求均值,axis=0表示按列求均值

2. 求協方差矩陣

newData,meanVal=zeroMean(dataMat)  
covMat=np.cov(newData,rowvar=0)  

numpy中的cov函式用於求協方差矩陣,引數rowvar很重要!若rowvar=0,說明傳入的資料一行代表一個樣本,若非0,說明傳入的資料一列代表一個樣本。因為newData每一行代表一個樣本,所以將rowvar設定為0

3. 求特徵值、特徵矩陣

呼叫numpy中的線性代數模組linalg中的eig函式,可以直接由協方差矩陣求得特徵值和特徵向量

eigVals,eigVects=np.linalg.eig(np.mat(covMat))  

eigVals存放特徵值,行向量。
eigVects存放特徵向量,每一列帶別一個特徵向量。
特徵值和特徵向量是一一對應的

4. 保留主要的成分[即保留值比較大的前n個特徵]

第三步得到了特徵值向量eigVals,假設裡面有m個特徵值,我們可以對其排序,排在前面的n個特徵值所對應的特徵向量就是我們要保留的,它們組成了新的特徵空間的一組基n_eigVect。將零均值化後的資料乘以n_eigVect就可以得到降維後的資料

eigValIndice=np.argsort(eigVals)            #對特徵值從小到大排序  
n_eigValIndice=eigValIndice[-1:-(n+1):-1]   #最大的n個特徵值的下標  
n_eigVect=eigVects[:,n_eigValIndice]        #最大的n個特徵值對應的特徵向量  
lowDDataMat=newData*n_eigVect               #低維特徵空間的資料  
reconMat=(lowDDataMat*n_eigVect.T)+meanVal  #重構資料  
return lowDDataMat,reconMat 

5. 完整code

# 零均值化
def zeroMean(dataMat):
    meanVal = np.mean(dataMat, axis=0)  # 按列求均值,即求各個特徵的均值
    newData = dataMat - meanVal
    return newData, meanVal


def pca(dataMat, n):
    newData, meanVal = zeroMean(dataMat)
    covMat = np.cov(newData, rowvar=0)  # 求協方差矩陣,return ndarray;若rowvar非0,一列代表一個樣本,為0,一行代表一個樣本

    eigVals, eigVects = np.linalg.eig(np.mat(covMat))  # 求特徵值和特徵向量,特徵向量是按列放的,即一列代表一個特徵向量
    eigValIndice = np.argsort(eigVals)  # 對特徵值從小到大排序
    n_eigValIndice = eigValIndice[-1:-(n + 1):-1]  # 最大的n個特徵值的下標
    n_eigVect = eigVects[:, n_eigValIndice]  # 最大的n個特徵值對應的特徵向量
    lowDDataMat = newData * n_eigVect  # 低維特徵空間的資料
    reconMat = (lowDDataMat * n_eigVect.T) + meanVal  # 重構資料
    return lowDDataMat, reconMat

Relevant Link:

http://www.cnblogs.com/jerrylead/archive/2011/04/18/2020209.html
http://blog.codinglabs.org/articles/pca-tutorial.html

0x8: 對影象資料應用PCA演算法

為使PCA演算法能有效工作,通常我們希望所有的特徵都有相似的取值範圍(並且均值接近於0)。我們有必要單獨對每個特徵做預處理,即通過估算每個特徵的均值和方差,而後將其取值範圍規整化為零均值和單位方差。

但是,對於大部分影象型別,我們卻不需要進行這樣的預處理。在實踐中我們發現,大多數特徵學習演算法對訓練圖片的確切型別並不敏感,所以大多數用普通照相機拍攝的圖片,只要不是特別的模糊或帶有非常奇怪的人工痕跡,都可以使用。在自然影象上進行訓練時,對每一個畫素單獨估計均值和方差意義不大,因為(理論上)影象任一部分的統計性質都應該和其它部分相同,影象的這種特性被稱作平穩性(stationarity)。

具體而言,為使PCA演算法正常工作,我們通常需要滿足以下要求

1. 特徵的均值大致為0
2. 不同特徵的方差值彼此相似

對於自然圖片,即使不進行方差歸一化操作,條件(2)也自然滿足,故而我們不再進行任何方差歸一化操作(對音訊資料,如聲譜,或文字資料,如詞袋向量,我們通常也不進行方差歸一化)
實際上,PCA演算法對輸入資料具有縮放不變性,無論輸入資料的值被如何放大(或縮小),返回的特徵向量都不改變。更正式的說:如果將每個特徵向量x 都乘以某個正數(即所有特徵量被放大或縮小相同的倍數),PCA的輸出特徵向量都將不會發生變化

既然我們不做方差歸一化,唯一還需進行的規整化操作就是均值規整化,其目的是保證所有特徵的均值都在0附近。根據應用場景,在大多數情況下,我們並不關注所輸入影象的整體明亮程度。比如在物件識別任務中,影象的整體明亮程度並不會影響影象中存在的是什麼物體。

更為正式地說,我們對影象塊的平均亮度值不感興趣,所以可以減去這個值來進行均值規整化。

需要注意的是,如果你處理的影象並非自然影象(比如,手寫文字,或者白背景正中擺放單獨物體),其他規整化操作就值得考慮了,而哪種做法最合適也取決於具體應用場合。但對自然影象而言,對每幅影象進行上述的零均值規整化,是預設而合理的處理

1. 利用PCA進行人臉識別

接下來我們嘗試對一個影象進行PCA處理,這裡我們對一張影象進行PCA降維處理,進而基於降維後的低維度畫素圖進行人臉相似度檢測。

大致思路是,收集一個基準樣本集(標準人像),然後通過PCA降維提高運算效率,之後的測試過程就是拿待測試樣本影象和基準樣本集中的所有圖片依次計算"歐式距離",最後的判定結果以離基準樣本集歐式距離最近的那張影象為"人臉"

# -*- coding: utf-8 -*-

import numpy as np
import scipy.linalg as linA # 為了啟用線性代數庫mkl
from PIL import Image
from resizeimage import resizeimage
import os,glob

imageWidth = 230
imageHigth = 300
imageSize = imageWidth * imageHigth

def sim_distance(train,test):
    '''
    計算歐氏距離相似度
    :param train: 二維訓練集
    :param test: 一維測試集
    :return: 該測試集到每一個訓練集的歐氏距離
    '''
    return [np.linalg.norm(i - test) for i in train]


def resizeImage(filepath):
    img = Image.open(filepath)
    img = img.resize((imageWidth, imageHigth), Image.BILINEAR)
    img.save(filepath)


def resizeImages():
    picture_path = os.getcwd() + '/images/'
    for name in glob.glob(picture_path + '*.jpeg'):
        print name
        resizeImage(name)


def calcVector(arr1, arr2):
    distance1, distance2 = 0, 0
    for i in arr1:
        distance1 += i * i
    distance1 = distance1 / len(arr1)
    for i in arr2:
        distance2 += i * i
    distance2 = distance2 / len(arr2)

    return distance1 < distance2



def main():
    picture_path = os.getcwd() + '/images/'
    print "picture_path: ", picture_path
    array_list = []
    for name in glob.glob(picture_path + '*.jpeg'):
        print name
        # 讀取每張圖片並生成灰度(0-255)的一維序列 1*120000
        img = Image.open(name)
        # img_binary = img.convert('1') 二值化
        img_grey = img.convert('L')  # 灰度化
        array_list.append(np.array(img_grey).reshape((1, imageSize)))  # 拉長為1維

    mat = np.vstack((array_list))  # 將上述多個一維序列(每個序列代表一張圖片)合併成矩陣 3*69000
    P = np.dot(mat, mat.transpose())  # 計算P
    v, d = np.linalg.eig(P)  # 計算P的特徵值和特徵向量
    print 'P Eigenvalues'
    print v
    print "Feature vector"
    print d

    d = np.dot(mat.transpose(), d)  # 計算Sigma的特徵向量 69000 * 3
    train = np.dot(d.transpose(), mat.transpose())  # 計算訓練集的主成分值 3*3
    print '訓練集pca降維後的向量陣列'
    print train

    # 開始測試
    # 用於測試的圖片也需要resize為和訓練基準樣本集相同的size
    resizeImage('images/test_1.jpg')
    test_pic = np.array(Image.open('images/test_1.jpg').convert('L')).reshape((1, imageSize))
    # 計算測試集到每一個訓練集的歐氏距離
    result1 = sim_distance(train.transpose(), np.dot(test_pic, d))
    print 'test_1.jpg 降維後的向量'
    print result1

    resizeImage('images/test_2.jpg')
    test_pic = np.array(Image.open('images/test_2.jpg').convert('L')).reshape((1, imageSize))
    result2 = sim_distance(train.transpose(), np.dot(test_pic, d))
    print 'test_2.jpg 降維後的向量'
    print result2

    # 歐式距離最小的即為最接近訓練樣本集的測試樣本
    if calcVector(result1, result2):
        print 'test_1.jpg is a human'
    else:
        print 'test_2.jpg is a human'


if __name__ == '__main__':
    resizeImages()
    main()

訓練集的計算結果為

/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python /Users/zhenghan/PycharmProjects/littlehann/just4fun.py
/Users/zhenghan/PycharmProjects/littlehann/images/train_2.jpeg
/Users/zhenghan/PycharmProjects/littlehann/images/train_3.jpeg
/Users/zhenghan/PycharmProjects/littlehann/images/train_1.jpeg
picture_path:  /Users/zhenghan/PycharmProjects/littlehann/images/
/Users/zhenghan/PycharmProjects/littlehann/images/train_2.jpeg
/Users/zhenghan/PycharmProjects/littlehann/images/train_3.jpeg
/Users/zhenghan/PycharmProjects/littlehann/images/train_1.jpeg
P Eigenvalues
[ 444.76007266 -199.2827456    -8.47732705]
Feature vector
[[-0.557454   -0.7252759   0.40400484]
 [-0.69022539  0.1344664  -0.71099065]
 [-0.46133931  0.67519898  0.57556266]]
pca
[[ -2.94130809e+09  -2.81400683e+09  -2.27967171e+09]
 [ -4.53920521e+08   2.41231868e+07   4.49796574e+07]
 [  5.06334430e+08   1.43429000e+08   2.56660545e+08]]
test_1.jpg
[859150941.34167683, 507130780.35877681, 98296821.771007225]
test_2.jpg
[921097812.32432926, 784122768.95719075, 323861431.46721846]
test_1.jpg is a human

Process finished with exit code 0

利用如下圖片進行識別測試,首先右乘得到各自在三個主軸上的值(對測試樣本也同樣進行PCA化),然後計算出該圖片到訓練樣本中的三張圖片的歐式距離

test_1.jpg
[859150941.34167683, 507130780.35877681, 98296821.771007225]
test_2.jpg
[921097812.32432926, 784122768.95719075, 323861431.46721846]
test_1.jpg is a human

再用別的測試集類來測試

上述的程式碼中我們自己實現了PCA的程式碼,實際上這個邏輯可以用sklearn來完成

sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False)  

1. n_components: PCA演算法中所要保留的主成分個數n,也即保留下來的特徵個數n
    1) 預設時預設為None,所有成分被保留 
    2) 賦值為int,比如n_components=1,將把原始資料降到一個維度 
    3) 賦值為string,比如n_components='mle',將自動選取特徵個數n,使得滿足所要求的方差百分比。
2. copy: 表示是否在執行演算法時,將原始訓練資料複製一份。若為True,則執行PCA演算法後,原始訓練資料的值不會有任何改變,因為是在原始資料的副本上進行運算;若為False,則執行PCA演算法後,原始訓練資料的值會改,因為是在原始資料上進行降維計算
    1) 預設時預設為True 
3. whiten: 白化,使得每個特徵具有相同的方差(即去均值化)
    1) 預設時預設為False 

# -*- coding: utf-8 -*-

from sklearn.decomposition import PCA

data = [[ 1.  ,  1.  ],
       [ 0.9 ,  0.95],
       [ 1.01,  1.03],
       [ 2.  ,  2.  ],
       [ 2.03,  2.06],
       [ 1.98,  1.89],
       [ 3.  ,  3.  ],
       [ 3.03,  3.05],
       [ 2.89,  3.1 ],
       [ 4.  ,  4.  ],
       [ 4.06,  4.02],
       [ 3.97,  4.01]]

if __name__ == '__main__':
    pca = PCA(n_components=1)
    newData = pca.fit_transform(data)
    print newData

0x9: 選擇主成分個數

使用PCA降維技術進行了一個簡單的小實驗之後,我們來繼續思考一個更深入的問題,應用PCA的時候,對於一個1000維的資料,我們怎麼知道要降到幾維的資料才是合理的?即n要取多少,才能保留最多資訊同時去除最多的噪聲?一般,我們是通過方差百分比來確定n的

保留的方差越大,對應於特徵向量的離散程度就越大,就越容易被分類器進行有效分類

def percentage2n(eigVals,percentage):  
    sortArray=np.sort(eigVals)   #升序  
    sortArray=sortArray[-1::-1]  #逆轉,即降序  
    arraySum=sum(sortArray)  
    tmpSum=0  
    num=0  
    for i in sortArray:  
        tmpSum+=i  
        num+=1  
        if tmpSum>=arraySum*percentage:  
            return num  

def pca(dataMat,percentage=0.99):  
    newData,meanVal=zeroMean(dataMat)  
    covMat=np.cov(newData,rowvar=0)    #求協方差矩陣,return ndarray;若rowvar非0,一列代表一個樣本,為0,一行代表一個樣本  
    eigVals,eigVects=np.linalg.eig(np.mat(covMat))#求特徵值和特徵向量,特徵向量是按列放的,即一列代表一個特徵向量  
    n=percentage2n(eigVals,percentage)                 #要達到percent的方差百分比,需要前n個特徵向量  
    eigValIndice=np.argsort(eigVals)            #對特徵值從小到大排序  
    n_eigValIndice=eigValIndice[-1:-(n+1):-1]   #最大的n個特徵值的下標  
    n_eigVect=eigVects[:,n_eigValIndice]        #最大的n個特徵值對應的特徵向量  
    lowDDataMat=newData*n_eigVect               #低維特徵空間的資料  
    reconMat=(lowDDataMat*n_eigVect.T)+meanVal  #重構資料  
    return lowDDataMat,reconMat  

Relevant Link:

http://ufldl.stanford.edu/wiki/index.php/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90
http://blog.csdn.net/watkinsong/article/details/823476
http://www.cnblogs.com/theskulls/p/4925147.html
http://ufldl.stanford.edu/wiki/index.php/%E5%AE%9E%E7%8E%B0%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90%E5%92%8C%E7%99%BD%E5%8C%96
http://book.2cto.com/201406/43853.html
http://pythoncentral.io/resize-image-python-batch/
https://opensource.com/life/15/2/resize-images-python
https://pypi.python.org/pypi/python-resize-image
https://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.ndarray.resize.html
http://www.ctolib.com/topics-58310.html
http://www.cnblogs.com/chenbjin/p/4200790.html
http://blog.csdn.net/u012162613/article/details/42177327
http://blog.csdn.net/u012162613/article/details/42192293

 

2. Random Projection(隨機投影)

隨機投影的理論依據是J-L Lemma,公式的核心思想總結一句話就是:
在高維歐氏空間裡的點集對映到低維空間裡相對距離得到某誤差範圍內的保持
至於為什麼要保持,主要是很多機器學習演算法都是在以利用點與點之間的距離資訊(歐氏距僅是明氏距的特例)展開計算分析的。
也就是說,很多的機器學習演算法都作了一個假設:點集之間的距離,包含了資料集蘊含的概率分佈

0x1: Johnson–Lindenstrauss lemma

1. 問題定義

首先, JL要解決的問題非常簡單(只是陳述比較簡單而已), 在一個高維的歐式空間(距離用歐式距離表示) \mathbf{R}^d. 我們想要把這些點轉換到一個低維的空間\mathbf{R}^k, 當時要保證空間轉換後,沒兩兩個點之間的距離幾乎不變.

正規點說就是, 找到一個對映關係:f:\mathbf{R}^d\rightarrow\mathbf{R}^k,裡面任意兩個點u,v,使得\|f(u)-f(v)\|\|u-v\|只有一點點的不同,其中\|u-v\|=\sqrt{(u_1-v_1)^2+(u_2-v_2)^2+\ldots+(u_d-v_d)^2} ,\|u-v\|是兩點的歐式距離.

令 x1,x2 為上的兩個向量,如果接近1,則矩陣 W 沒有扭曲 x1,x2 之間的距離太多,或具有保距特性。

隨機投影不會扭曲歐式距離太多

2. 問題證明

JL理論證明了解決這個問題的可能性,即這種對映理論上是存在的。
Johnson-Lindenstrauss Theorem
For any 0 < ε < 1 and any positive integer n, let k be a positive integer such that
k\ge4(\epsilon^2/2-\epsilon^3/3)^{-1}\ln n
Then for any set V of n points in \mathbf{R}^d, there is a map f:\mathbf{R}^d\rightarrow\mathbf{R}^k such that for all u,v\in V,
(1-\epsilon)\|u-v\|^2\le\|f(u)-f(v)\|^2\le(1+\epsilon)\|u-v\|^2.
Furthermore, this map can be found in expected polynomial time.

對於任意一個樣本大小為m的集合,如果我們通過隨機投影將其維度降到一個合適的範圍內,那麼我們將以較高的概率保證投影后的資料點之間的距離資訊變化不大。

這樣我們在做K-mean之類的演算法時,就可以先將高維度的資料利用隨機投影進行降維處理,然後在執行演算法,且不會影響演算法的最終聚類效果太多。

0x2: Random projection演算法

隨機投影技術是一個理論框架,類似馬爾科夫性質理論一樣,具體實現隨機投影的演算法有很多

1. Gaussian random projection - 高斯隨機投影

要討論高斯隨機投影為什麼有效,我們需要先來討論下一個核心問題,高斯投影是否可以從理論上保證投影降維前後,資料點的空間分佈距離基本保持不變呢?這個問題其實可以等價於證明另一個問題,即高斯投影能否做到將高維空間的點均勻的投影到低維空間中,如果能做到這一點,那麼我們也可以證明其具備“投影降維前後,資料點的空間分佈距離基本保持不變”的能力。

1)考慮在二維情況下如何獲得均勻取樣?

首先,考慮二維的情況,即如何在球形的周長上取樣。我們考慮如下方法

1. 先在一個包含該圓形的外接正方形內均勻的取樣
2. 第二,將取樣到的點投影到圓形上
# 具體地說就是
1. 先獨立均勻的從區間[−1,1](我們假設圓形跟正方形的中心點都在原點)內產生兩個值組成一個二維的點(x1,x2)
2. 將該二維點投影到圓形上

例如,如下圖所示:

如果我們產生點是圖中的A,B兩點,那麼投影到圓形上就是C點;

如果產生的是點D,那麼投影到圓形上就是E點。

但是,用這樣的方法得到點在圓形上並不是均勻分佈的,比如產生C點的概率將大於產生E點概率,因為可以投影到C點對應的那條直線比E點對應的那條直線要長。

解決的辦法是去掉圓形外面的點,也就是如果我們首先產生的點在圓形外的話(比如點B),那麼我們就丟棄該點,重新在產生,這樣的話產生的點在圓形上是均勻分佈的,從這裡可以看出,降維的一個核心概念都是投影,投影是一種資料降維的通用方法。

那麼,我們能否將此方法擴充套件到高維的情況下呢?答案是不行的。

因為在高維的情況下球與正方體的體積比將非常非常小,幾乎接近於零。也就是我們在正方體內產生的點幾乎不可能落到球體內部,那麼也就無法產生有效的投射點。那麼,在高維的球體上,我們應該怎樣才能產生一個均勻分佈與球體表面的點呢?答案是利用高斯分佈

2)利用高斯分佈在高維球體表面產生均勻分佈點的方法

即將上述第一步改成:以均值為零方差為1的高斯分佈獨立地產生d個值,形成一個d維的點;然後第二步:將點x歸一化用這種方法產生點必定均勻分佈在高維球體表面。原因如下:

d個獨立的高斯分佈的密度函式為那麼,為常數,說明高斯分佈產生的每個投射點的概率都一樣,即均勻分佈

3)高維空間下的高斯分佈性質

高斯分佈是概率統計裡面最常見也是最有用的分佈之一,即使在高維情況下的也有一些非常有用的特:

對於低維高斯分佈來說,其概率質量主要集中在均值附近。在高維情況下,這樣的結論也同樣成立

# -*- coding: utf-8 -*-

import numpy as np
from sklearn import random_projection 

if __name__ == '__main__':
    X = np.random.rand(100, 10000)
    transformer = random_projection.GaussianRandomProjection()
    X_new = transformer.fit_transform(X)
    print X_new.shape

output:
(100, 3947)

Relevant Link:

http://blog.csdn.net/ljj583905183/article/details/47980169
http://cjbme.csbme.org/CN/abstract/abstract500.shtm

2. a uniform random k-dimensional subspace.

對映關係 f:\mathbf{R}^d\rightarrow\mathbf{R}^k是可以隨機構造的, 以下這種是JL在論文中用到的一種:

Let A be a random k\times d matrix that projects \mathbf{R}^d onto a uniform random k-dimensional subspace.
Multiply A by a fixed scalar \sqrt{\frac{d}{k}}. For every v\in\mathbf{R}^dv is mapped to \sqrt{\frac{d}{k}}Av.

 構造後的點\sqrt{\frac{d}{k}}Av 是 \mathbf{R}^k的其中一個向量.

引數 \sqrt{\frac{d}{k}} 是為了保證\mathbf{E}\left[\left\|\sqrt{\frac{d}{k}}Av\right\|^2\right]=\|v\|^2.

3. Sparse random projection

# -*- coding: utf-8 -*-

import numpy as np
from sklearn import random_projection

if __name__ == '__main__':
    X = np.random.rand(100, 10000)
    transformer = random_projection.SparseRandomProjection()
    X_new = transformer.fit_transform(X)
    print X_new.shape

output:
(100, 3947)

4. More computationally efficient random projections

the Gaussian distribution can be replaced by a much simpler distribution such as

0x3: Random projection在手寫影象識別裡的具體應用

1. 計算100%完全分類的baseline基線值

我們使用scikit-learn的手寫數字影象資料集,其中包含了1,797個影象樣本(0-9數字),每個影象是一個 8*8(總共64維)的畫素圖,我們將其展開為64bit的行向量。

我們使用random projection來訓練這批樣本,並且計算出一個基線值,即需要多少dimensions維度組成部分才能100%完全地對這批樣本進行分類。

# -*- coding: utf-8 -*-

from sklearn.random_projection import johnson_lindenstrauss_min_dim

if __name__ == '__main__':
    print johnson_lindenstrauss_min_dim(1797,eps=0.1)

Out[2]:
6423

實驗執行的結果是:對於1797個64維的樣本集來說,在0.1歐幾里德空間距離的離散容忍度(即至少樣本間距離要大於0.1歐幾里得距離)的前提下,需要6423個rp維度組成部分來進行有效分類。

同時,考察另一個引數,即離散容忍度:

>>> from sklearn.random_projection import johnson_lindenstrauss_min_dim
>>> johnson_lindenstrauss_min_dim(n_samples=1e6, eps=0.5)
663
>>> johnson_lindenstrauss_min_dim(n_samples=1e6, eps=[0.5, 0.1, 0.01])
array([    663,   11841, 1112658])
>>> johnson_lindenstrauss_min_dim(n_samples=[1e4, 1e5, 1e6], eps=0.1)
array([ 7894,  9868, 11841])

可以看到,對樣本集的離散容忍度越小(可分性要求越高),需要的維度components就指數增大,顯然這個理論值在工程化中不可接受的。在實際的應用場景中,往往需要我們去尋找一個折中值。

2. random projection的components個數是否和歐幾里德分類準確度是正相關的

scikit_learn給出的baseline是6423,這顯然太大了,我們的目的是降維,是為了提高運算效率的,為此,我們選取的components一定是小於64(原始8*8的影象維度)的。

但是,那麼如何判斷降維的程度呢,即至少需要多少components才能基本不影響原始樣本集的分類準確度呢,同時又儘可能地實現降維目錄呢?我們遍歷以下的components,逐個看它們的分類準確度表現

# -*- coding: utf-8 -*-

from sklearn.random_projection import SparseRandomProjection
from sklearn.svm import LinearSVC
from sklearn.cross_validation import train_test_split
from sklearn import metrics
from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as np

if __name__ == '__main__':
    #  initializes our lists of accuracies. We’ll be evaluating 20 different component sizes, equally spaced from 2 to 64.
    accuracies = []
    components = np.int32(np.linspace(2, 64, 20))
    print "components"
    print components
    '''
    components
    [ 2  5  8 11 15 18 21 24 28 31 34 37 41 44 47 50 54 57 60 64]
    '''

    # load the digits data set, perform a training and testing split, train a Linear SVM, and obtain a baseline accuracy:
    digits = datasets.load_digits()
    split = train_test_split(digits.data, digits.target, test_size=0.3, random_state=42)
    (trainData, testData, trainTarget, testTarget) = split

    model = LinearSVC()
    model.fit(trainData, trainTarget)
    baseline = metrics.accuracy_score(model.predict(testData), testTarget)

    # loop over the projection sizes
    '''
    1. We start looping over our number of components, equally spaced, in the range 2 to 64.
    2. Then we instantiate our SparseRandomProjection using the current number of components, fit our random projection to the data (which essentially means generating a sparse matrix of values), and then transforming our original training data by projecting the data.
    3. Now that we have obtained a sparse representation of the data, let’s train a Linear SVM on it.
    4. Our Linear SVM is now trained; it’s time to see how it performs on the testing data and update our list of accuracies.
    '''
    for comp in components:
        # create the random projection
        sp = SparseRandomProjection(n_components=comp)
        X = sp.fit_transform(trainData)

        # train a classifier on the sparse random projection
        model = LinearSVC()
        model.fit(X, trainTarget)

        # evaluate the model and update the list of accuracies
        test = sp.transform(testData)
        accuracies.append(metrics.accuracy_score(model.predict(test), testTarget))

    '''
    At this point all the hard work is done.
    We’ve evaluated a series of sparse random projections for varying numbers of components.
    Let’s plot our results and see what we have:
    '''
    # create the figure
    plt.figure()
    plt.suptitle("Accuracy of Sparse Projection on Digits")
    plt.xlabel("# of Components")
    plt.ylabel("Accuracy")
    plt.xlim([2, 64])
    plt.ylim([0, 1.0])

    # plot the baseline and random projection accuracies
    plt.plot(components, [baseline] * len(accuracies), color="r")
    plt.plot(components, accuracies)

    plt.show()


從結果上看,30維的稀疏降維就可以基本達到較高的分類準確度,同時又儘可能地實現了降維的目的。

Relevant Link:

http://forum.ai100.com.cn/blog/thread/py-2015-02-19-3811867870631018/
https://en.wikipedia.org/wiki/Johnson%E2%80%93Lindenstrauss_lemma
https://en.wikipedia.org/wiki/Random_projection
http://blog.yhat.com/posts/sparse-random-projections.html
http://scikit-learn.org/stable/auto_examples/datasets/plot_digits_last_image.html 
http://scikit-learn.org/stable/modules/random_projection.html
https://blog.csdn.net/luoyun614/article/details/39853259

 

3. 壓縮感知

https://www.cnblogs.com/Eufisky/p/7798767.html#commentform

https://blog.csdn.net/yq_forever/article/details/55271952

https://www.cnblogs.com/AndyJee/p/4988623.html

 

5. 降維在其他領域的應用

0x1: PHP SSDEEP模糊化HASH

看完了Random Projection的理論,突然想到以前用過的PHP裡面的SSDEEP模糊化HASH本質上也是一種資料降維方法,我們來看看SSDEEP的概念定義

模糊化HASH也叫"區域性不敏感HASH",如果用於對比的兩個資料集之間的區別只在一個很小的區域內,則模糊化HASH會忽略這種差別,的趨向於得到一個相等的Fuzzy HASH值

LSH演算法的基本思想是利用一個hash函式把集合中的元素對映成hash值,使得相似度越高的元素hash值相等的概率也越高。LSH演算法使用的關鍵是針對某一種相似度計算方法,找到一個具有以上描述特性的hash函式。LSH所要求的hash函式的準確數學定義比較複雜,以下給出一種通俗的定義方式:

對於集合S,集合內元素間相似度的計算公式為sim(*,*)。如果存在一個hash函式h(*)滿足以下條件:存在一個相似度s到概率p的單調遞增對映關係,使得S中的任意兩個滿足sim(a,b)>=s的元素a和b,h(a)=h(b)的概率大於等於p。那麼h(*)就是該集合的一個LSH演算法hash函式

一般來說在最近鄰搜尋中,元素間的關係可以用相似度或者距離來衡量。如果用距離來衡量,那麼距離一般與相似度之間存在單調遞減的關係。以上描述如果使用距離來替代相似度需要在單調關係上做適當修改

Relevant Link:

http://www.cnblogs.com/GarfieldEr007/p/5479401.html

Copyright (c) 2017 LittleHann All rights reserved

相關文章