1. 程式人生 > >KNN演算法Hadoop實現及kaggle digit recognition資料測試

KNN演算法Hadoop實現及kaggle digit recognition資料測試

軟體版本:
Hadoop2.6,MyEclipse10.0 , Maven 3.3.2

原始碼下載地址:https://github.com/fansy1990/knn 。

1. KNN演算法思路

如果一個樣本在特徵空間中的k個最相似(即特徵空間中最鄰近)的樣本中的大多數屬於某一個類別,則該樣本也屬於這個類別。KNN演算法中,所選擇的鄰居都是已經正確分類的物件。該方法在定類決策上只依據最鄰近的一個或者幾個樣本的類別來決定待分樣本所屬的類別。-- 摘自《鄰近演算法》,百度百科

2. KNN演算法MR實現:

Hadoop實現KNN演算法,最主要的就是設計Mapper和Reducer,使資料流可以套用Hadoop的MR框架,即<K1,V1>--> <K2,V2>  , <K2,List<V2>>--> <K3,V3>;

2.1.Mapper設計

Mapper 有三個函式setup(),map(),cleanup(),其中setup()函式在最開始執行一次,cleanup函式在最後執行一次,map函式針對每條記錄每次處理一次;這裡輸入檔案設定為訓練資料集,即如下格式:

Label,x1,x2,...,xn
第一列為樣本類別,其他列為樣本屬性;
1)在setup()函式中讀取測試資料,測試資料格式如下:
x1,x2,...,xn 
同時初始化一個和測試資料容量大小一樣的陣列List<Type,Distance>,用於儲存每個測試樣本的近鄰資料。近鄰資料包含k個樣本類別以及對應的距離;

2)接著,在map函式中讀取每個訓練樣本,針對訓練樣本,來更新所有測試樣本的鄰近資料,即List<Type,Label>,最開始初始化Type=[-1,-1,-1,...,-1],Label=[MaxDouble,MaxDouble,...,MaxDouble].

更新具體做法:
當前訓練樣本資料tr_i以及類別tr_type,當前測試樣本te_i,以及對應的te_i_<type[],distance[]>,
a. 計算tr_i和te_i的距離distance_tr_te;
b. 遍歷te_i_<type[],distance[]>的distance[]
        find distance[]中最大的max_distance以及下標index_max_distance;
if max_distance> distance_tr_te then
  //替換
  distance[index_max_distance]=distance_tr_te;
  type[index_max_distance]=tr_type;
end
    end
3) 最後,在cleanup()函式中,輸出List<Type,Lable>中的每一條記錄,這裡預設test的資料是一個檔案,所以這裡可以直接使用List的下標代表每一個數據;即最後Mapper的輸出為<id,<type[],distance[]>>,每個id代表一個測試資料,<type[],distance[]>代表當前測試資料的鄰近類別以及對應的距離;

2.2.Reducer設計

 Reducer 只設計reduce函式即可,reduce函式需要做的就是針對同一個測試樣本id,統計彙總後的鄰近類別以及對應的距離資料,同時需要再次整理這些資料,保留距離最小的k個類別值;然後同時這個k個類別的眾數,即最後測試樣本id的類別值,輸出即可;

2.3. Combiner設計

Combiner,這裡可以新增一個Combiner操作,Combiner操作就是map端的reduce操作,可以先把資料彙總一次,然後再發往reducer端,減少網路IO。Combiner需要輸入/輸出的格式一直,即輸入為<id,<type[],distance[]>>,輸出也需要是這樣的格式。這裡可以把reducer的彙總整理程式碼直接拷貝過來即可,同時需要注意這裡就不需要求眾數了。

3. 測試

資料使用Kaggle中的digit recognition的資料;資料下載:https://www.kaggle.com/c/digit-recognizer/data 。
在測試演算法時,首先截取了較少的資料進行測試,測試資料18個樣本,訓練樣本第一次50多個樣本,第二次8.9M(約5k左右樣本)的樣本;

得到的結果對比:

            

上面的測試資料使用訓練資料擷取類別得到的,上面兩張圖左邊是預測的結果,右邊是實際類別。從圖1中可以看到(訓練資料比較少)其預測準確率很低,但是在訓練資料量增加後(圖2的8.9M)時就有很好的預測效果了(準確率為100%);

使用上面的演算法來對kaggle的資料進行測試(訓練集70M,測試集40M),資料可以從上面的url中下載;

Hadoop叢集情況:

本地叢集情況:

node101  (主節點,namenode,datanode,ResourceManager,NodeManager,SecondaryNamenode,3.7G,2核)

node102  (資料/計算節點,datanode,NodeManager,1G,1核)

上面兩個機器是虛擬機器,本機是windows7系統4核8G記憶體;

耗時:

得到的預測結果,提交到Kaggle官網,可以得到預測的準確率,如下:

準確率為92%左右,同時可以看到排名為557,這個很後了。

4. 總結

1. knn演算法由於需要計算全部訓練資料集以及測試資料集的距離,所以演算法比較耗時(這裡可以看到一共有110M的資料耗時11小時左右),這裡沒有對該演算法進行調優,可以參考國外的一些論文對此進行修改,比如《Efficient Parallel kNN Joins for Large Data in MapReduce》;2. 不同資料針對的問題不一樣,這裡kaggle的數字識別,一般會使用隨機森林來做;