【從零開始學機器學習06】kNN 模型的幾個超參數: Algorithm、n_neighbors、明科夫斯基距離

摘要:介紹 kNN 模型的幾個重要的超參數。

上一篇文章我們說到了 kNN 模型中的超參數,今天來介紹幾個重要的超參數。簡而言之,超參數就是在模型運行前就要先確定的參數。之前指定的 k 個近鄰值 k 就是一個超參數,我們在建立模型時就指定了它。

與超參數相對應的一個概念是模型參數,二者區別是:

  • 超參數是在模型運行前確定的
  • 模型參數是在算法運行過程自己學習的參數

kNN 是最簡單的機器學習算法,模型中只有超參數沒有模型參數,之後我們會介紹的線性迴歸、邏輯迴歸等算法有模型參數,建立模型也會更加複雜。

第一個超參數:algorithm

algorithm 即算法,意思就是建立 kNN 模型時採用什麼算法去搜索最近的 k 個點,有四個選項:

  • brute(暴力搜索)
  • kd_tree(KD樹)
  • ball_tree(球樹)
  • auto(默認值,自動選擇上面三種速度最快的)

我們之前建立模型時沒有設置這個參數,模型默認使用了 auto 方法,不過還是有必要了解一下這幾種方法的區別。

首先,我們知道 KNN 模型的核心思想是計算大量樣本點之間的距離。

第一種算法 brute 暴力搜索。意思就是計算預測樣本和全部訓練集樣本的距離,最後篩選出前 K 個最近的樣本,這種方法很蠻力,所以叫暴力搜索。當樣本和特徵數量很大的時候,每計算一個樣本距離就要遍歷一遍訓練集樣本,很費時間效率低下。有什麼方法能夠做到無需遍歷全部訓練集就可以快速找到需要的 k 個近鄰點呢?這就要用到 KD 樹和球樹算法。

第二種算法 KD 樹(K-dimension tree縮寫)。簡單來說 KD 樹是一種「二叉樹」結構,就是把整個空間劃分爲特定的幾個子空間,然後在合適的子空間中去搜索待預測的樣本點。採用這種方法不用遍歷全部樣本就可以快速找到最近的 K 個點,速度比暴力搜索快很多(稍後會用實例對比一下)。至於什麼是二叉樹,這就涉及到數據結構的知識,稍微有些複雜,就目前來說暫時不用深入瞭解,sklearn 中可以直接調用 KD 樹,很方便。之後會單獨介紹二叉樹和 KD 樹,再來手寫 KD 樹的 Python 代碼。

目前只需要知道,什麼樣的數據集適合使用 KD 樹算法

假設數據集樣本數爲 m,特徵數爲 n,則當樣本數量 m 大於 2 的 n 次方時,用 KD 樹算法搜索效果會比較好。比如適合 1000 個樣本且特徵數不超過 10 個(2 的 10 次方爲 1024)的數據集。一旦特徵過多,KD 樹的搜索效率就會大幅下降,最終變得和暴力搜索差不多。通常來說 KD 樹適用維數不超過 20 維的數據集,超過這個維數可以用球樹這種算法。

第三種算法是球樹(Ball tree)。對於一些分佈不均勻的數據集,KD 樹算法搜索效率並不好,爲了優化就產生了球樹這種算法。同樣的,暫時先不用具體深入瞭解這種算法。

下面,我們製造一個分類數據集,使用不同的算法來直觀感受一下各自算法的運行速度。

使用 datasets.make_classification 這種方法可以創建隨機的分類數據集。第一個數據集是樣本數 m 大於樣本 2 的 n 次方,依次建立 kNN 模型並計算運行時間:

可見當數據集樣本數量 m > 2 的 n 次方時,kd_tree 和 ball_tree 速度比 brute 暴力搜索快了一個量級,auto 採用其中最快的算法。

第二個數據集是樣本數 m 小於樣本 2 的 n 次方時,各:

當數據集樣本數量 m 小於 2 的 n 次方 時,KD 樹和球樹的搜索速度大幅降低,暴力搜索算法相差無幾。

我們介紹了第一個超參數 algorithm,就 kNN 算法來說通常只需要設置 auto 即可,讓模型自動爲我們選擇合適的算法。


第二個超參數:n_neighbors

n_neighbors 即要選擇最近幾個點,默認值是 5(等效 k )。

回憶一下此前我們在建立 kNN 模型時傳入的參數 n_neighbors 是隨機選了一個 3,但這個 3 建立的模型不一定是最好的。

舉個例子,看下面一組對比圖。

紅綠兩種圓點代表不同類別,黃色點是待預測的點。左圖中,k =3 時紅綠點比例是 2:1,所以黃色點大概率屬於紅色類別。

右圖中 k =5 時,黃色點大概率又屬於綠色類別了。到底應該選擇哪一個 k 值,黃色才能正確分類呢?

再以之前的葡萄酒數據集實際測試下,k 值分別選擇 3 和 5 時的模型得分:

加載、劃分數據集和建模相信你已經很熟悉了,不再多說,重點看紅色箭頭處的模型得分。k = 3 時,模型得分 0.76,k=5 時模型得分只有 0.68。所以 k =3 是更好的選擇,但可能還存在其他 k 值比 3 效果更好,怎麼才能找到最好的 k 值呢?

最簡單的方式就是遞歸搜索,從中選擇得分最高的 k 值。

下面,我們設置一個 k 值範圍,把剛纔的代碼封裝到 for 循環中來嘗試下:

可以看到,當 k 取 1-10,建立的 10 個模型中,k =3 時的模型得分最高。這樣我們就找到了合適的超參數 k。


第三個超參數:距離權重 weights

剛纔在劃分黃色點分類時,最近的 3 個點中紅綠色點比例是 2:1,所以我們就把黃色點劃分爲紅色點了。

這樣做忽略了點與點之間的距離問題:雖然紅點數量多於綠點,但顯然綠點距離黃點更近,把黃點劃分爲綠色類可能更合適。因此,之前的模型效果可能並不好。

所以,在建立模型時,還可以從距離出發,將樣本權重與距離掛鉤,近的點權重大,遠的點權重小。怎麼考慮權重呢,可以用取倒數這個簡單方法實現。

以上圖爲例,綠點距離是 1,取倒數權重還爲 1;兩個紅點的距離分別是 3 和 4,去倒數相加後紅點權重和爲 7/12。綠點的權重大於紅點,所以黃點屬於綠色類。

在 Sklearn 的 kNN 模型中有專門考慮權重的超參數:weights,它有兩個選項:

  • uniform 不考慮距離權重,默認值

  • distance 考慮距離權重

從這兩個維度,我們可以再次循環遍歷找到最合適的超參數:


第四個超參數:p

說到距離,還有一個重要的超參數 p。

如果還記得的話,之前的模型在計算距離時,採用的是歐拉距離:

\sqrt{\sum_{i=1}^{n}\left(X_{i}^{(a)}-X_{i}^{(b)}\right)^{2}}\\

變形後:\\ \left(\sum_{i=1}^{n}\left|X_{i}^{(a)}-X_{i}^{(b)}\right|^{2}\right)^{\frac{1}{2}}

除了歐拉距離,還有一種常用的距離,曼哈頓距離

\sum_{i=1}^{n}\left|X_{i}^{(a)}-X_{i}^{(b)}\right|

這兩種距離很好理解,舉個例子,從家到公司,歐拉距離就是二者的直線距離,但顯然不可能以直線到公司,而只能按着街道線路過去,這就是曼哈頓距離,俗稱出租車距離。

這兩種格式很像,其實他們有一個更通用的公式:
\left(\sum_{i=1}^{n}\left|X_{i}^{(a)}-X_{i}^{(b)}\right|^{p}\right)^{\frac{1}{p}}

這就是明可夫斯基距離(Minkowski Distance),曼哈頓距離和歐拉距離分別是 p 爲 1 和 2 的特殊值。

使用不同的距離計算公式,點的分類很可能不一樣導致模型效果也不一樣。

在 Sklearn 中對應這個距離的超參數是 p,默認值是 2,也就是歐拉距離,下面我們嘗試使用不同的 p 值建立模型,看看哪個 p 值得到的模型效果最好, 這裏因爲考慮了 p,那麼 weights 超參數需是 distance,外面嵌套一個 for 循環即可:

可以看到,找出的最好模型,超參數 k 值爲 15 ,p 值爲 1 即曼哈頓距離,模型得分 0.81。

比我們最初採用的超參數: k=3、weights = uniform 得到的 0.76 分要好。但這裏要注意 k=15 很可能是過擬合了,這樣即使得分高這個模型也是不好的,以後會說。

小結一下,本文介紹了 algorithm、n_neighbors、weights、p 等超參數,通過循環搜索超參數(也就是調參)獲得了得分更高的模型。這種循環搜索的方式,有一個專門的名稱叫:網格搜索(Grid Search),以 k 和 p 兩個超參數爲例,循環遍歷就像是在網格中搜索參數組合。

網格搜索是一個各種模型都很常用的模型調參方法,在 Sklearn 中專門封裝了這樣一個函數,只需要把想要調整的超參數都加進去運算之後,它會返回最好的一組超參數組合。比我們自己手寫去找方便地多,我們在下一篇文章就來介紹一下網格搜索。

本文的 jupyter notebook 代碼,可以在我公衆號:「高級農民工」後臺回覆「kNN6」得到,加油!

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