轉自:https://zhuanlan.zhihu.com/p/23966698
導語:在上一篇《kd 樹算法之思路篇》中,我們介紹瞭如何用二叉樹格式記錄空間內的距離,並以其爲依據進行高效的索引。在本篇文章中,我們將詳細介紹 kd 樹的構造以及 kd 樹上的 kNN 算法。
作者:肖睿
編輯:宏觀經濟算命師
本文由JoinQuant量化課堂推出,本文的難度屬於進階(下),深度爲 level-1
kd 樹的結構
kd樹是一個二叉樹結構,它的每一個節點記載了【特徵座標,切分軸,指向左枝的指針,指向右枝的指針】。
其中,特徵座標是線性空間中的一個點。
切分軸由一個整數表示,這裏,是我們在 n 維空間中沿第 r 維進行一次分割。
節點的左枝和右枝分別都是 kd 樹,並且滿足:如果 y 是左枝的一個特徵座標,那麼並且如果 z 是右枝的一個特徵座標,那麼。
給定一個數據樣本集 和切分軸 r , 以下遞歸算法將構建一個基於該數據集的 kd 樹,每一次循環制作一個節點:
−− 如果 ,記錄 S 中唯一的一個點爲當前節點的特徵數據,並且不設左枝和右枝。( 指集合 S 中元素的數量)
−− 如果 :
∙∙ 將 S 內所有點按照第 r 個座標的大小進行排序;
∙∙ 選出該排列後的中位元素(如果一共有偶數個元素,則選擇中位左邊或右邊的元素,左或右並無影響),作爲當前節點的特徵座標,並且記錄切分軸 r;
∙∙ 將 設爲在 S 中所有排列在中位元素之前的元素; 設爲在 S 中所有排列在中位元素後的元素;
∙∙ 當前節點的左枝設爲以 爲數據集並且 r 爲切分軸製作出的 kd 樹;當前節點的右枝設爲以 爲數據集並且 r 爲切分軸製作出的 kd 樹。再設 。(這裏,我們想輪流沿着每一個維度進行分割; 是因爲一共有 n 個維度,在沿着最後一個維度進行分割之後再重新回到第一個維度。)
構造 kd 樹的例子
上面抽象的定義和算法確實是很不好理解,舉一個例子會清楚很多。首先隨機在 中隨機生成 13 個點作爲我們的數據集。起始的切分軸;這裏 對應 xx 軸,而 對應 y 軸。
首先先沿 x 座標進行切分,我們選出 x 座標的中位點,獲取最根部節點的座標
並且按照該點的x座標將空間進行切分,所有 x 座標小於 6.27 的數據用於構建左枝,x座標大於 6.27 的點用於構建右枝。
在下一步中 對應 y 軸,左右兩邊再按照 y 軸的排序進行切分,中位點記載於左右枝的節點。得到下面的樹,左邊的 x 是指這該層的節點都是沿 x 軸進行分割的。
空間的切分如下
下一步中 r≡1+1≡0 mod 2,對應 x 軸,所以下面再按照 x 座標進行排序和切分,有
最後每一部分都只剩一個點,將他們記在最底部的節點中。因爲不再有未被記錄的點,所以不再進行切分。
就此完成了 kd 樹的構造。