【量化課堂】一隻兔子幫你理解 kNN 【1001 後期跟着敲一下理解】

 

 

導語 :商業哲學家 Jim Rohn 說過一句話,“你,就是你最常接觸的五個人的平均。” 那麼,在分析一個人時,我們不妨觀察和他最親密的幾個人。同理的,在判定一個未知事物時,可以觀察離它最近的幾個樣本,這就是 kNN(k 最近鄰)的方法。

作者:肖睿
編輯:宏觀經濟算命師

本文由 JoinQuant 量化課堂推出,本文的難度屬於進階(上),深度爲 level-1

 

簡介

kNN(k-Nearest Neighbours)是機器學習中最簡單易懂的算法,它的適用面很廣,並且在樣本量足夠大的情況下準確度很高,多年來得到了很多的關注和研究。kNN 可以用來進行分類或者回歸,大致方法基本相同,本篇文章將主要介紹使用 kNN 進行分類。

舉個例子跟你講

kNN 還真是直接講例子最好懂。大家都喜歡兔子,所以就來說一說兔子的事情吧。

有一種兔子叫作 悲傷(Grief),它們的平均身高是 505050 釐米,平均體重 555 公斤。我們拿來一百個悲傷,分別測量它們的身高和體重,畫在座標圖上,用綠色方塊表示。
圖 1.png

還有一種兔子呢,叫作 痛苦(Agony)。它們體型比較小,平均身高是 303030 釐米,平均體重是 444 公斤。我們將一百個痛苦的身高和體重畫在同一個座標圖上,用藍色三角表示。
圖 2.png

最後一種兔子叫 絕望(Despair)。它們的平均身高 45 釐米,但體重較輕,平均只有 2.5 公斤。一百隻絕望的數據用黃色圓圈表示。
圖 3.png

在這些數據中,(身高 , 體重)(身高 , 體重)(身高 , 體重) 的二元組叫做 特徵(features),兔子的品種則是分類 標籤(class label)。我們想解決的問題是,給定一個未知分類的新樣本的所有特徵,通過已知數據來判斷它的類別。

北京十八環外有一個小樹林裏經常出現這三種兔子。爲了瞭解它們的生態環境,某研究團隊想知道三種兔子的數量比例;可是這些兔子又太過危險,不能讓人親自去做,所以要設計一個全自動的機器人,讓它自己去樹林裏識別它遇到的每一個兔子的種類。啊,爲了把故事講圓,還要假設他們經費不足,所以機器只有測量兔子的身高和體重的能力。

那麼現在有一迷之兔子,我們想判斷它的類別,要怎麼做呢?按照最普通的直覺,應該在已知數據裏找出幾個和我們想探究的兔子最相似的幾個點,然後看看那些兔子都是什麼個情況;如果它們當中大多數都屬於某一類別,那麼迷之兔子大概率也就是那個類別了。

於是乎,我們給機器人預設一個整數 kkk,讓它去尋找距離最近的 k 個數據樣本進行分析。好,機器發現了一隻兔子,它長着八條腿,三十二隻眼睛,毛茸茸的小尾巴,齊刷刷的八十六顆獠牙,面相猙獰,散發着噩夢般的腐臭,發出來自地獄底處的咆哮… 差不多就是這個樣子(作者手繪):
未知的兇猛兔子.png

可我們的機器才識別不了那麼多,它只測量出這隻兔子身長 404040 釐米,體重 2.72.72.7 公斤,就是下面圖中那顆閃閃發亮的紅星
圖 4.png

kNN 算法如何對這次觀測進行分類要取決於 k 的大小。直覺告訴我們迷之兔像是一隻絕望,因爲除了最近的藍色三角外,附近其他都是黃色圓圈。的確,如果設 k=15k=15k=15,算法會判斷這隻兔子是一隻絕望。但是如果設 k=1k=1k=1,那麼由於距離最近的是藍色三角,會判斷迷之兔子是一隻痛苦。

如果按照 15NN 和 1NN 的方法對這個二維空間上的每一個點進行分類,會形成以下的分割
15NN 分類有星.png
1NN 分類有星.png

在兩組分類中,1NN 的分類邊界明顯更 “崎嶇”,但是對歷史樣本沒有誤判;而 15NN 的分類邊界更平滑,但是對歷史樣本有發生誤判的現象。選擇 k 的大小取決於對偏差和方差之間的權衡,本篇不進行更深探討,讀者在使用 kNN 時憑感覺選一個 kkk 就好。

距離函數

我們在上面的例子中把一個很重要的概念隱藏了起來,在
選擇一個數量 k 還只是小問題,更重要的是距離的計算方法。畢竟,當我們說 “最近的 k 個點” 時,這個 “近” 是怎麼衡量的?

在數學中,一個空間上距離的嚴格定義如下:
設 MMM 爲一個空間,MMM 上的一個距離函數是一個函數 d:M×M→ℝd:M×M→ℝd:M×M→R,滿足

∙ d(x,y)≥0 ∀x,y∈M∙ d(x,y)≥0 ∀x,y∈M∙ d(x,y)≥0 ∀x,y∈M
∙ d(x,y)=0⟺x=y∙ d(x,y)=0⟺x=y∙ d(x,y)=0⟺x=y
∙ d(x,y)=d(y,x) ∀x,y∈M∙ d(x,y)=d(y,x) ∀x,y∈M∙ d(x,y)=d(y,x) ∀x,y∈M
∙ d(x,z)≤d(x,y)+d(y,z) ∀x,y,z∈M∙ d(x,z)≤d(x,y)+d(y,z) ∀x,y,z∈M∙ d(x,z)≤d(x,y)+d(y,z) ∀x,y,z∈M
兩個點 x,yx,yx,y 之間的距離就是 d(x,y)d(x,y)d(x,y)。

我們一般最常用的距離函數是歐氏距離,也稱作 L2L2L2 距離。如果 x=(x1,x2,…,xn)x=(x1,x2,…,xn)x=(x1,x2,…,xn) 和 y=(y1,y2,…,yn)y=(y1,y2,…,yn)y=(y1,y2,…,yn) 是 nnn 維歐式空間 ℝnℝnRn 上的兩個點,那它們之間的 L2L2L2 距離是

d2(x,y)=∑i=1n(xi−yi)2‾‾‾‾‾‾‾‾‾‾‾‾⎷.

d2(x,y)=∑i=1n(xi−yi)2‾‾‾‾‾‾‾‾‾‾‾‾⎷.d2(x,y)=∑i=1n(xi−yi)2.


L2L2L2 是更普遍的 LpLpLp 距離在 p=2p=2p=2 時的特列。LpLpLp 距離的函數 dpdpdp 定義如下:對於 1≤p<∞1≤p<∞1≤p<∞,有
dp(x,y)=(∑i=1n|xi−yi|p)1/p.

dp(x,y)=(∑i=1n|xi−yi|p)1/p.dp(x,y)=(∑i=1n|xi−yi|p)1/p.


還有 L∞L∞L∞ 距離
d∞(x,y)=maxi=1,…,n|xi−yi|.

d∞(x,y)=maxi=1,…,n|xi−yi|.d∞(x,y)=maxi=1,…,n|xi−yi|.


在實際應用中,距離函數的選擇應該根據數據的特性和分析的需要而定,本篇就不進行更深入的探討,一般情況下使用最常用的 L2L2L2 函數即可。

 

但是!注意!使用 kNN 時需要根據特徵數據的取值區間來調整座標軸的比例,這個做法叫作標準化或者歸一化。爲什麼要這麼做呢?拿上面的例子來說,一隻兔子的身長(cm)數值平均是它的體重(kg)的 101010 倍左右,如果我們在這組數值上直接使用 L2L2L2 距離函數的話就會導致橫軸的距離比重明顯放大,分類結果也不合理,如下圖所示
15NN 距離未歸一.png

如果把座標軸成其他的單位,比如毫米和噸,並用相應的新數值來計算距離,又會得到完全不同的分類標準。甚至,在極端情況下,如果身高用納米並且體重用噸計量,那麼相比之下身高的數值會奇高無比,以至於兩點之間的距離是完全由身高決定的,體重則沒有任何權重。爲了解決這個問題,我們應該在計算距離時把所有座標軸進行歸一化。

在之前的例子中,由於橫軸數值大約是豎軸的 101010 倍左右,所以我們將橫軸(身高)的數值壓縮 101010 倍,即計算距離時使用

d((x1,x2),(y1,y2))=(x110−y110)2+(x2−y2)2‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾√

d((x1,x2),(y1,y2))=(x110−y110)2+(x2−y2)2‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾√d((x1,x2),(y1,y2))=(x110−y110)2+(x2−y2)2


就可以得出合理的 kNN 分類。

 

一般來說,假設進行 kNN 分類使用的樣本的特徵是 {(xi1,xi2,…,xin)}mi=1{(xi1,xi2,…,xin)}mi=1{(xi1,xi2,…,xin)}i=1m,取每一軸上的最大值減最小值

Mj=maxi=1,…,mxij−mini=1,…,mxij,

Mj=maxi=1,…,mxij−mini=1,…,mxij,Mj=maxi=1,…,mxij−mini=1,…,mxij,


並且在計算距離時將每一個座標軸除以相應的 MjMjMj 以進行歸一化,即
d((y1,…,yn),(z1,…,zn))=∑j=1n(yjMj−zjMj)2‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾⎷

d((y1,…,yn),(z1,…,zn))=∑j=1n(yjMj−zjMj)2‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾⎷d((y1,…,yn),(z1,…,zn))=∑j=1n(yjMj−zjMj)2


便可以規避座標軸比例失衡的問題。

 

概率 KNN

上面的 kNN 算法返回的是對一組特徵的絕對分類,告訴我們這隻兔子被判斷爲哪一個類別。可有時我們並不想知道一個確切地分類,而想知道它屬於某個分類的概率是多大。比如我們發現一隻身長 373737 體重 4.84.84.8 的小兔兔,在下圖五角星的位置。
圖 5.png

這隻兔子的特徵數據在悲傷和痛苦的分界處,機器不論判斷它屬於哪個類別都很有可能是錯的。這時,類似 “它有一半可能性是痛苦,一半可能性是悲傷” 的反饋會更有意義。

爲了這個目的,我們同樣找找出距離問題特徵最近的 kkk 個樣本,但與其尋找數量最多的分類,我們統計其中每個類別的分別有多少個,再除以 kkk 得到一個屬於每一個類別概率值。比如在上面的圖裏,距離五角星最近的 151515 個樣本中,有 888 只悲傷和 777 只痛苦,由此判斷:它有 53%53%53% 的可能性是悲傷,47%47%47% 的可能性是痛苦,0%0%0% 的可能性是絕望。

在整個二維空間中的每一個點上進行概率 kNN 算法,可以得到每個特徵點是屬於某個類別的概率熱力圖,圖中顏色越深代表概率越大。

綠的.png
藍的.png
黃的.png

相比於絕對的分類,這些概率的計算會給我們更有效的表述以及更多的應用空間。比如說,我們知道悲傷兔子喜歡向我們的機器人上噴灑奇怪的粘液,毫無作用毫無意義的綠色的粘液,就像這樣(作者手繪):
粘液兔子.png

倒不是因爲別的,我們就是覺得這種粘液很噁心,清洗起來也很麻煩,所以我們想讓機器人在測量並發現是悲傷之後馬上掉頭逃跑。但是如果機器發現了一隻體型接近痛苦的悲傷,並且普通的 kNN 算法發生誤判,沒有馬上逃跑,那麼最後就會被噴了。所以我們使用概率 kNN 的算法並且使用以下風控原則:只要發現兔子有 30%30%30% 以上的概率是悲傷,就馬上逃跑。從此之後,機器人就再也沒被噴過。

結語

不知你有沒有發現,我跟你講了這麼多關於兔子的事,卻絲毫沒有提及如何用代碼計算 kNN。這是因爲 kNN 雖然思路簡單,但實現起來有一個問題,那就是計算量很大;當數據量很多時,拿一組特徵來和所有樣本依次計算距離並選取最近的 kkk 個,是非常耗費時間的。所以,在量化課堂接下來的文章中,我們將講解 kNN 的一個高效算法 —kd 樹。

本文由 JoinQuant 量化課堂推出,版權歸 JoinQuant 所有,商業轉載請聯繫我們獲得授權,非商業轉載請註明出處。

文章迭代記錄
v1.2,2016-09-14,修正公式,感謝 zhouzhizz16 指出
v1.1,2016-08-17,添加研究模塊
v1.0,2016-08-16,文章上線

https://www.joinquant.com/view/community/detail/a98b7021e7391c62f6369207242700b2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章