?
/*先把標題給寫了、這樣就能經常提醒自己*/
1. k近鄰算法
k臨近算法的過程,即對一個新的樣本,找到特征空間中與其最近的k個樣本,這k個樣本多數屬于某個類,就把這個新的樣本也歸為這個類。
算法?
輸入:訓練數據集
其中為樣本的特征向量,為實例的類別,i=1,2,…,N;樣本特征向量x(新樣本);
輸出:樣本x所屬的類y。
(1)根據給定的距離度量,在訓練集T中找出與x最相鄰的k個點,涵蓋這k個點的鄰域記作;
(2)在中根據分類決策規則(如多數表決)決定x的類別y:
??????????????????????????????????????????????????????????????????? (1)
式中I為指示函數,即當時I為1,否則為0。
由這個簡單的算法過程可以看出來,距離的選擇、以及k的選擇都是很重要的,這恰好對應的三個要素中的兩個,另一個為分類決策規則,一般來說是多數表決法。
?
2. k近鄰模型
k近鄰算法使用的模型實際上對應于特征空間的劃分,模型由三個基本要素——距離度量、k值的選擇和分類決策規則決定。
距離度量
? ? ? 特征空間中倆個實例的距離是倆個實例點相似程度的反映,k近鄰中一般使用歐氏距離,本文中主要只介紹這一種。
設特征空間
是
維實數向量空間
,
,
,
,
的
距離定義為
?
當p=2時,稱為歐氏距離(Euclidean distance).
==================在此吐槽一下,博客園的圖片插入好折騰人啊,已經搞出肩周炎了,明天再繼續碼第二要素了 2014-6-30========================
舉個粟子,已知
,
,則
?的歐氏距離為
,挺容易理解的吧!
K 值的選擇
首先說明一下K值的選擇對最終的結果有很大的影響!!!
? ? ? 如果選擇的k過小,則預測的結果對近鄰的實例點非常敏感,如果近鄰剛好是噪聲,則預測就會出錯,例如k=1,很難保證最近的一個點就是正確的預測,亦即容易發生過擬合!如果選擇的k過大,則會忽略掉訓練實例中的大量有用信息,例如k=N,那么無論輸入實例是什么最終的結果都將是訓練實例中最多的類。
? ? ? 關于分類決策規則這里就不再贅述,正常情況下直接采用多數表決即可,如果覺得結果不滿意的話,可以加入各個類的先驗概率進去融合!
?
3. K近鄰的實現
該小節書本中用到了KD樹,通過構造平衡KD樹來方便快速查找訓練數據中離測試實例最近的點,不過構造這顆樹本身是一個比較繁瑣的過程(其實是本人代碼能力實在太菜了,真的覺得把KD樹寫下來需要花太多時間了,而且KD樹中每增加一個新數據又要進行節點插入操作,實在不方便,直接放棄),所以直接用最土豪的方法,時間復雜度差就差了,咱有的是CPU!!!
在這里直接套用書中例子,不過實現上就用其它算法了。稍等,我勒個去!書中的例子只是用于構造KD樹的,李航兄你不厚道啊,說好的K近鄰怎么變成這樣了,不能直接引用書中例子了,自己再編一個得了。
例子:
訓練數據集中,正樣本點有
,負樣本點有
,現要求判斷實例
屬于哪個類別,如下圖所示:
假設取K=3,則距離
最近的3個點為
,按照多數表決規則可得出
應該屬于正類。
為了表示咱們不是拍腦袋給出的結果,下面給出具體的代碼實現
package org.juefan.knn; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import org.juefan.basic.FileIO; import org.juefan.data.Data; public class SimpleKnn { public static final int K = 3 ; public static int P = 2; // 距離函數的選擇,P=2即歐氏距離 public class LabelDistance{ public double distance = 0 ; public int label; public LabelDistance( double d, int l){ distance = d; label = l; } } public sort compare = new sort(); public class sort implements Comparator<LabelDistance> { public int compare(LabelDistance arg0, LabelDistance arg1) { return arg0.distance < arg1.distance ? -1 : 1; // JDK1.7的新特性,返回值必須是一對正負數 } } /** * 倆個實例間的距離函數 * @param a * @param b * @return 返回距離值,如果倆個實例的維度不一致則返回一個極大值 */ public double getLdistance(Data a, Data b){ if (a.x.size() != b.x.size()) return Double.MAX_VALUE; double inner = 0 ; for ( int i = 0; i < P; i++ ){ inner += Math.pow((a.x.get(i) - b.x.get(i)) , P); } return Math.pow(inner, ( double )1/ P); } /** * 計算實例與訓練集的距離并返回最終判斷結果 * @param d 待判斷實例 * @param tran 訓練集 * @return 實例的判斷結果 */ public int getLabelvalue(Data d, ArrayList<Data> tran){ ArrayList <LabelDistance> labelDistances= new ArrayList<> (); Map <Integer, Integer> map = new HashMap<> (); int label = 0 ; int count = 0 ; for (Data data: tran){ labelDistances.add( new LabelDistance(getLdistance(d, data), data.y)); } Collections.sort(labelDistances, compare); for ( int i = 0; i < K & i < labelDistances.size(); i++ ){ //System.out.println(labelDistances.get(i).distance + "\t" + labelDistances.get(i).label); int tmplabel = labelDistances.get(i).label; if (map.containsKey(tmplabel)){ map.put(tmplabel, map.get(tmplabel) + 1 ); } else { map.put(tmplabel, 1 ); } } for ( int key: map.keySet()){ if (map.get(key) > count){ count = map.get(key); label = key; } } return label; } public static void main(String[] args) { SimpleKnn knn = new SimpleKnn(); ArrayList <Data> datas = new ArrayList<> (); FileIO fileIO = new FileIO(); fileIO.setFileName( ".//file//knn.txt" ); fileIO.FileRead(); for (String data: fileIO.fileList){ datas.add( new Data(data)); } Data data = new Data(); data.x.add( 2); data.x.add(1 ); System.out.println(knn.getLabelvalue(data, datas)); } }
?
?
對代碼有興趣的可以上本人的GitHub查看: https://github.com/JueFan/StatisticsLearningMethod/
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
