統計學習方法-k近鄰
k近鄰方法是一種惰性學習算法,可以用於迴歸和分類,它的主要思想是投票機制,對於一個測試實例, 我們在有標籤的訓練數據集上找到和最相近的k個數據,用他們的label進行投票,分類問題則進行表決投票,迴歸問題使用加權平均或者直接平均的方法。
算法和模型
由於這個模型很容易理解,我們直接給出kNN分類模型其算法僞代碼:
輸入:訓練數據
其中,是實例的特徵向量,,表示類別,
輸出: 實例x所屬的類別
- 根據跟定的距離度量的方法,在T中找到和x最鄰近的k個點,記作x的鄰域,
- 在中使用多數表決規則,絕對x的類別y:
- 對於迴歸問題,得到y
其中.
從上述算法中,我們可以看到,kNN沒有顯示的訓練和學習模型的過程,這是一個惰性的學習方法,主要有兩個點需要我們關注,一個是距離的度量,另一個是超參數k值的選擇,接下來我們就來考慮這兩個問題。
距離的度量
我們剛纔提到KNN的一個關鍵點就是如何度量距離,對於兩個向量,一般使用距離進行計算。
假設特徵空間是n維實數向量空間, 其中,,
, 則的L_p距離定義爲:
這裏的. 當p=2時候,稱爲歐氏距離(Euclidean distance), 有
當p=1時候,稱爲曼哈頓距離(Manhattan distance), 有
當時候,稱爲極大距離(infty distance), 表示各個座標的距離最大值, 有
使用距離計算的時候,我們一般使用歐氏距離,一般情況下都是將數據轉化成實數向量的形式,使用距離度量方式,找到最近的k個值,進行投票打分.
k值的選擇
kNN中的k是一個超參數,需要我們進行指定,一般情況下這個k和數據有很大關係,都是交叉驗證進行選擇,但是建議使用交叉驗證的時候,, 使用交叉驗證得到一個很好的k值。
k值還可以表示我們的模型複雜度,當k值越小意味着模型複雜度表達,更容易過擬合,(用極少樹的樣例來絕對這個預測的結果,很容易產生偏見,這就是過擬合)。我們有這樣一句話,k值越多學習的估計誤差越小,但是學習的近似誤差就會增大.
如何理解這句,估計誤差表示最後的結果,k值大,集百家所長,更可能得到準確的值,表示估計的準確,則誤差就小;但是我們的估計的時候,在學習過程中,使用最相近的k個實例進行估計,每一個值都會和預測的x有一個近似誤差,k越大則誤差的總和就越大。
這裏我們提一句,多數表決等價於經驗風險最小化。這個證明也很簡單,這裏就不給出了,有興趣的請看: 《統計學習方法》第40頁 分類決策規則. 多說一句,既然要求誤差,那就寫出誤差損失函數,剩下的就是公式恆等變化了.
kd 樹
kNN,從上述算法中,我們可以看到主要是從訓練數據中,知道k個相近實例,但是每次都要便利這個數據集合,主要的問題就是速度慢. 這時候就出現了加速查找的數據結構,其中之一就是kd 樹.
構造kd 樹
kd樹是一種對k維空間中的實例店進行存儲以便能夠進行快速檢索的數據結構. kd樹是一個二叉樹,表示對k維空間的一個劃分. 構造kd樹就是不斷用垂直於座標軸的超平面 (一般用每一個維度的中位數來表示) 將k維空間劃分,構成一系列的k維超矩形區域.
僞代碼: (from wikipedia)
function kdtree (list of points pointList, int depth)
{
// Select axis based on depth so that axis cycles through all valid values
var int axis := depth mod k;
// Sort point list and choose median as pivot element
select median by axis from pointList;
// Create node and construct subtree
node.location := median;
node.leftChild := kdtree(points in pointList before median, depth+1);
node.rightChild := kdtree(points in pointList after median, depth+1);
return node;
}
基於kd樹查找最近鄰
構造kd樹的目的就是快速查找最近鄰和k近鄰,這裏我們給出二維的列子,這裏例子來自與書中和
wiki百科,我嘗試說明百這幾張圖的運行原理.
數據 T = {(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)}
構造kd樹,二叉樹和空間角度的劃分圖,再次注意每一次用的這個維度對應的所有這個空間中的中位數.根據x維度有{2,4,5,7,8,9}: 中位數是7,因此(7,2)作爲根節點,x < 7,在左子樹,其他在右子樹。依次遞歸構造左右子樹,下一次根據維度y,之後根據維度x. 注意這裏的k是維度,n 可能大學k,故要每次對k取餘數. (這個k不是kNN中的k).
二叉樹劃分圖下面的空間劃分圖,表示空間上的顯示格式. 其實整體的搜索是在這個空間上進行的.
空間劃分圖
下面用一個gif圖來表示搜索最近鄰的過程,簡單來說就是一句話,根據構造過程,從頭到尾左右二分,在這個過程中記錄下來最近的點。從這個圖中,我們可以看到,我們目標實例target用四角星表示,
空間劃分圖
- 二叉樹搜索,依次到葉子節點D,路勁是A - B - D. 這個過程中最近的點是B,作爲最有候選集合.
- 我們以target爲圓心,target到B的距離爲半徑,畫圓,我們發現,B的另外的部分與圓相交,這表示,可能存在更近的候選點在另半部分,如果不存在相交,此時的候選點B就是最近點。
- 如果存在和其他空間相交,則將搜索空間上升爲其父節點,用target和其父節點距離作圓,如果依然和其他空間相交,繼續回溯搜索,直到不想交或者全部搜索完畢找到候選點.
- 上面介紹的是最近鄰查找,如何查找k近鄰?
- 使用各最大堆數據結果,維護k大小的最大堆,從根節點開始如果堆的大小不足k,就候選集如果
- 如果大小爲k,就比較堆頂元素和當前元素的距離大小,如果當前小於堆頂距離就進行替換,
- 之後以堆頂元素爲中心,就編程了找最近鄰問題。最後返回結果
總結
kNN簡單好用,但是最主要的是這個思想,多數投票加權平均。kd樹只是一種加速的方法,還有kd平衡樹,ball tree等,這也是一種思想,並不是準則。KNN和kd tree的代碼稍後便到。
注:生活如此,問題不打。喵~