k近鄰演算法的思想很簡單,然而,再簡單的概念如果碰上高維度加上海量資料,就變得很麻煩,如果按照常規思想,將每個測試樣本和訓練樣本的距離算出來,在進行排序查詢,無疑效率十分低下,這也就是為什麼要介紹kd樹的原因。kd樹是一種二叉樹,kd樹的每個結點對應乙個k維超矩形區域。kd樹的k是k維空間,k近鄰演算法的k是k個最近值,不是一樣的!看文字很抽象,其實很好理解,看圖
每一次分割都需要確定乙個軸和乙個值,然後分割時只看該軸的資料,小於等於分割值就放到該結點的左子樹里,大於分割值就放到右子樹中。那麼每個結點裡面需要儲存哪些內容呢?
我的實現裡面,每個結點有如下內容:
struct kdtreenode ;
};
用kd樹實現的k近鄰演算法(還有其它的方法),訓練過程實際上就是樹的建造過程,我們用遞迴建立kd樹。
首先,我們需要建立並儲存根節點
kdtreenode* root = new kdtreenode();//類中用這個儲存根節點
void knn::setroot() else
}cout<
stackaxisvec;//用棧儲存分割軸,棧頂軸方差最大。
void knn::createsplitaxis()
}auto varc = submean[0];
for(unsigned long i=1;i(i, var[i]));
}std::sort(variancevec.begin(), variancevec.end(), (pair&left, pair&right) );
for(const auto& variance:variancevec)
cout<
root->left = buildtree(root, root->lefttreeval, axisvec);
root->right = buildtree(root, root->righttreeval, axisvec);
來看一下buildtree**:
kdtreenode* knn::buildtree(kdtreenode*root, vector>& data, stack& axisstack) else}}
if(!node->lefttreeval.empty())
if(!node->righttreeval.empty())
return node;
}
建立好子樹後可以通過showtree函式前序遍歷樹來檢視,這裡就不演示了,**中有這一步。
對於用kd樹實現的knn演算法來說,**的過程就是查詢的過程,這裡我們給出查詢k個最近鄰的**,中間用到了stl標準模板庫的priority_queue和pair的組合,用priority_queue實現大頂堆,對於由pair構成的priority_queue來說,預設的比較值是first,也就是說裡面的元素會根據pair的第乙個元素從大到小排序,即用.top()得到的是最大值(預設比較函式的情況下)。在搜尋 k-近鄰時,設定乙個有k
個元素的大頂堆,建立樹時,當堆不滿時,將結點和距離放入,堆滿時,只需比較當前搜尋點的dis
是否小於堆頂點的dis
,如果小於,堆頂出堆,並將當前搜尋點壓入。
priority_queue> maxheap;
下面給出查詢**
void knn::findknearest(vector& testd)}}
}double knn::computedis(const vector& v1, const vector& v2)
k近鄰演算法雖然概念簡單,但是實現由於要用到樹結構,編寫起來還是挺具有挑戰性的,以後還會進行效能的優化,慢慢來。 統計學習方法 k近鄰法
k近鄰法 knn 是一種基本的分類與回歸方法 分類這種需求,滲透到我們生活的方方面面 分類演算法可以幫助我們完成這些繁瑣的操作,並根據我們的要求不斷修正分類結果。分類演算法其實蠻多的,這裡順著書本順序,詳細講解knn演算法,再與k means k means 演算法進行簡單對比。k近鄰法是這樣乙個過...
統計學習方法 K近鄰法
k近鄰演算法簡單 直觀給定乙個訓練資料集,對新的輸入例項,在訓練資料集中找到與該例項最鄰近的k個例項,這k個例項的多數屬於某個類,就把該輸入例項分為這個類.下面先敘述k近鄰演算法,然後再討論其細節。近鄰法的特殊情況 k 1情形,稱為最近鄰演算法.對於輸入的例項點 特徵向量 x xx,最近鄰法將訓練資...
《統計學習方法》 k近鄰法
k近鄰法是一種基本分類與回歸方法。在這裡我們只討論分類問題中的k近鄰法。三要素 k值的選擇 距離度量 分類決策規則 最後會引入一種k近鄰的實現方法 kd樹。輸入 訓練資料集t 輸出 例項x所屬的類y 根據給定的距離度量,在訓練集中找到和x最近的k個點 在這k個點中根據分類決策規則,決定x的類別 注意...