統計學習方法筆記-k近鄰

統計學習方法-k近鄰

k近鄰方法是一種惰性學習算法,可以用於迴歸和分類,它的主要思想是投票機制,對於一個測試實例xjx_j, 我們在有標籤的訓練數據集上找到和最相近的k個數據,用他們的label進行投票,分類問題則進行表決投票,迴歸問題使用加權平均或者直接平均的方法。

算法和模型

由於這個模型很容易理解,我們直接給出kNN分類模型其算法僞代碼:
輸入:訓練數據
T={(x1,y1),(x2,y2),...,(xN,yn)}T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_n)\}
其中xiRnx_i \in R^n,是實例的特徵向量,yiY={c1,c2,...,cK}y_i \in Y = \{c_1,c_2,...,c_K\},表示類別,
輸出: 實例x所屬的類別

  1. 根據跟定的距離度量的方法,在T中找到和x最鄰近的k個點,記作x的鄰域,Nk(x)N_k(x)
  2. Nk(x)N_k(x)中使用多數表決規則,絕對x的類別y:
    y=argmaxcjxiNk(x)I(yi=cj)y=argmax_{c_j} \sum_{x_i \in N_k(x)}I(y_i=c_j)
  3. 對於迴歸問題,得到y
    y=1kxiNk(x)yiy= \frac{1}{k} \sum_{x_i \in N_k(x)}y_i
    其中i=1,2,...,N;j=1,2,...,Ki=1,2,...,N; j=1,2,...,K.

從上述算法中,我們可以看到,kNN沒有顯示的訓練和學習模型的過程,這是一個惰性的學習方法,主要有兩個點需要我們關注,一個是距離的度量,另一個是超參數k值的選擇,接下來我們就來考慮這兩個問題。

距離的度量

我們剛纔提到KNN的一個關鍵點就是如何度量距離,對於兩個向量(xi,xj)(x_i, x_j),一般使用LpL_p距離進行計算。

假設特徵空間XX是n維實數向量空間RnR^n, 其中,xi,xjXx_i,x_j \in X,
xi=(xi(1),xi(2),...,xi(n))xj=(xj(1),xj(2),...,xj(n))x_i=(x_i^{(1)},x_i^{(2)},...,x_i^{(n)}),x_j=(x_j^{(1)},x_j^{(2)},...,x_j^{(n)}), 則xi,xjx_i,x_j的L_p距離定義爲:
Lp(xi,xj)=(l=1nxi(l)xj(l)p)1pL_p(x_i,x_j) = \left( \sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}|^p \right) ^ {\frac{1}{p}}
這裏的p1p \geq 1. 當p=2時候,稱爲歐氏距離(Euclidean distance), 有
L2(xi,xj)=(l=1nxi(l)xj(l)2)12L_2(x_i,x_j) = \left( \sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}|^2 \right) ^ {\frac{1}{2}}
當p=1時候,稱爲曼哈頓距離(Manhattan distance), 有
L1(xi,xj)=l=1nxi(l)xj(l)L_1(x_i,x_j) = \sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}|
p=p=\infty時候,稱爲極大距離(infty distance), 表示各個座標的距離最大值, 有
Lp(xi,xj)=maxlnxi(l)xj(l)L_p(x_i,x_j) = \max_{l}{n}|x_i^{(l)}-x_j^{(l)}|

使用距離計算的時候,我們一般使用歐氏距離,一般情況下都是將數據轉化成實數向量的形式,使用距離度量方式,找到最近的k個值,進行投票打分.

k值的選擇

kNN中的k是一個超參數,需要我們進行指定,一般情況下這個k和數據有很大關係,都是交叉驗證進行選擇,但是建議使用交叉驗證的時候,k[2,20]k \in [2,20], 使用交叉驗證得到一個很好的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用四角星表示,


空間劃分圖
  1. 二叉樹搜索,依次到葉子節點D,路勁是A - B - D. 這個過程中最近的點是B,作爲最有候選集合.
  2. 我們以target爲圓心,target到B的距離爲半徑,畫圓,我們發現,B的另外的部分與圓相交,這表示,可能存在更近的候選點在另半部分,如果不存在相交,此時的候選點B就是最近點。
  3. 如果存在和其他空間相交,則將搜索空間上升爲其父節點,用target和其父節點距離作圓,如果依然和其他空間相交,繼續回溯搜索,直到不想交或者全部搜索完畢找到候選點.
  4. 上面介紹的是最近鄰查找,如何查找k近鄰?
  • 使用各最大堆數據結果,維護k大小的最大堆,從根節點開始如果堆的大小不足k,就候選集如果
  • 如果大小爲k,就比較堆頂元素和當前元素的距離大小,如果當前小於堆頂距離就進行替換,
  • 之後以堆頂元素爲中心,就編程了找最近鄰問題。最後返回結果

總結

kNN簡單好用,但是最主要的是這個思想,多數投票加權平均。kd樹只是一種加速的方法,還有kd平衡樹,ball tree等,這也是一種思想,並不是準則。KNN和kd tree的代碼稍後便到。

注:生活如此,問題不打。喵~

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