1. 程式人生 > >Weka演算法Classifier-meta-Bagging原始碼分析

Weka演算法Classifier-meta-Bagging原始碼分析

一、Bagging演算法

嚴格來看Bagging並不能算是一種分類演算法,Bagging和Boosting一樣,是一種組合基本分類器的方法,也就是使用多個基分類器來獲取更為強大的分類器,其核心思想是有放回的抽樣。

Bagging演算法的訓練流程:

1、從樣本集中有放回的抽樣M個樣本。

2、用這M個樣本訓練基分類器C。

3、重複這個過程X次,得到若干個基分類器。

Bagging演算法的預測流程:

1、對於新傳入例項A,用這X個新分類器得到一個分類結果的列表。

2、若待分類屬性是數值型(迴歸),求這個列表的算數平均值作為結果返回。

3、若待分類屬性是列舉型別(分類),按這個列表對分類結果進行投票,返回票數最高的。

二、Weka程式碼實現

(1)基分類器

Weka中的預設基分類器使用的是REPTree,也就是Fast decision tree learner,至於這個具體是個什麼,後面我再寫文章進行分析。

  1. public Bagging() {  
  2.    m_Classifier = new weka.classifiers.trees.REPTree();  
  3.  }  
(2)構建過程BuildClassifier

整個BuildClassifier都是圍繞標m_CalcOutOfBag來展開的,這個m_CalcOutOfBag標識的意思是:是否計算OutofBag的錯誤比例。

假如我們對訓練集M進行抽樣,抽樣的數量和M的數量是一樣的,那麼肯定會有一些樣本並沒有被抽到(為什麼?因為是有放回的抽樣),這個標識就是用來評測這些沒抽到的樣本的準確率,如果沒有這個標,那麼這個準確率到後面就不會被計算了。

  1. if (m_CalcOutOfBag && (m_BagSizePercent != 100)) {  
  2.       thrownew IllegalArgumentException("Bag size needs to be 100% if "
  3.           + "out-of-bag error is to be calculated!");  
  4.     }  
  5.     int bagSize = data.numInstances() * m_BagSizePercent / 100;  
  6.     Random random = new Random(m_Seed);  
  7.     boolean[][] inBag = null;  
  8.     if (m_CalcOutOfBag)  
  9.       inBag = newboolean[m_Classifiers.length][];  
  10.     for (int j = 0; j < m_Classifiers.length; j++) {  
  11.       Instances bagData = null;  
  12.       // create the in-bag dataset
  13.       if (m_CalcOutOfBag) {  
  14.         inBag[j] = newboolean[data.numInstances()];  
  15.         // bagData = resampleWithWeights(data, random, inBag[j]);
  16.         bagData = data.resampleWithWeights(random, inBag[j]);  
  17.       } else {  
  18.         bagData = data.resampleWithWeights(random);  
  19.         if (bagSize < data.numInstances()) {  
  20.           bagData.randomize(random);  
  21.           Instances newBagData = new Instances(bagData, 0, bagSize);  
  22.           bagData = newBagData;  
  23.         }  
  24.       }  
這一部分是抽樣,首先如果有m_CalcOutOfBag標,則必須要求抽樣比例是100%。

其次算出要抽樣的大小。

inBag陣列是用來記錄Instances中哪些樣本被抽到了哪些沒被抽到。

data.resampleWithWeight就是進行有放回的抽樣。

  1. if (m_Classifier instanceof Randomizable) {  
  2.   ((Randomizable) m_Classifiers[j]).setSeed(random.nextInt());  
  3. }  
  4. // build the classifier
  5. m_Classifiers[j].buildClassifier(bagData);  
接著是構建分類樹的過程,呼叫具體classifier的buildClassifier方法。

最後是計算OutOfBag的過程,程式碼我已寫註釋。

  1. if (getCalcOutOfBag()) { //如果有這個標就計算
  2.       double outOfBagCount = 0.0//錯誤的權重和
  3.       double errorSum = 0.0;//錯誤的偏差值的和
  4.       boolean numeric = data.classAttribute().isNumeric();//是否是連續數值
  5.       for (int i = 0; i < data.numInstances(); i++) {  
  6.         double vote;//代表投票結果
  7.         double[] votes;//代表投票
  8.         if (numeric)  
  9.           votes = newdouble[1];//如果是數值,則取平均數,計算平均數的過程一個數組單元就夠了
  10.         else
  11.           votes = newdouble[data.numClasses()];//否則則要進行投票
  12.         // determine predictions for instance
  13.         int voteCount = 0;  
  14.         for (int j = 0; j < m_Classifiers.length; j++) {  
  15.           if (inBag[j][i])  
  16.             continue;//如果已經被取樣,就忽略,因為要計算的是OutOfBag
  17.           voteCount++;//記錄有多少樣本被計算
  18.           if (numeric) {  
  19.             votes[0] = m_Classifiers[j].classifyInstance(data.instance(i));//數值型則直接把預測結果累加
  20.           } else {  
  1. double[] newProbs = m_Classifiers[j].distributionForInstance(data  
  2.             .instance(i));  
  3.         for (int k = 0; k < newProbs.length; k++) {  
  4.           votes[k] += newProbs[k]; //列舉型則要把所有列舉概率進行累加
  5.         }  
  6.       }  
  7.     }  
  8.     // "vote"
  9.     if (numeric) {  
  10.       vote = votes[0];  
  11.       if (voteCount > 0) {  
  12.         vote /= voteCount; // 數值型取均值
  13.       }  
  14.     } else {  
  15.       if (Utils.eq(Utils.sum(votes), 0)) {  
  16.       } else {  
  17.         Utils.normalize(votes);//歸一化
  18.       }  
  19.       vote = Utils.maxIndex(votes); // 選出最大的index
  20.     }  
  21.     outOfBagCount += data.instance(i).weight();//累加權重
  22.     if (numeric) {  
  23.       errorSum += StrictMath.abs(vote - data.instance(i).classValue())  
  24.           * data.instance(i).weight();//累加錯誤偏差
  25.     } else {  
  26.       if (vote != data.instance(i).classValue())  
  27.         errorSum += data.instance(i).weight();//如果是列舉就對出錯進行計數
  28.     }  
  29.   }  
  30.   m_OutOfBagError = errorSum / outOfBagCount;//最後取個平均值
  31. else {  
  32.   m_OutOfBagError = 0;//如果沒有那個標就不計算了
  33. }  
三、根據權重進行無放回抽樣的過程

也就是 data.resampleWithWeights(random, inBag[j]);這個方法,感覺看了一下還挺有意思的,就放上來剖析一下。

過載形式有3個,前兩個都會呼叫第三個:

  1. public Instances resampleWithWeights(Random random, double[] weights) {  
  2.   return resampleWithWeights(random, weights, null);  
  3. }  

  1. public Instances resampleWithWeights(Random random, boolean[] sampled) {  
  2.   double[] weights = newdouble[numInstances()];  
  3.   for (int i = 0; i < weights.length; i++) {  
  4.     weights[i] = instance(i).weight();  
  5.   }  
  6.   return resampleWithWeights(random, weights, sampled);  
  7. }  
  1. public Instances resampleWithWeights(Random random, double[] weights,  
  2.     boolean[] sampled) {  
  3.     if (weights.length != numInstances()) {  
  4.       thrownew IllegalArgumentException("weights.length != numInstances.");  
  5.     }  
  6.     Instances newData = new Instances(this, numInstances());  
  7.     if (numInstances() == 0) {  
  8.       return newData;  
  9.     }  
  10.     // Walker's method, see pp. 232 of "Stochastic Simulation" by B.D. Ripley
  11.     double[] P = newdouble[weights.length];  
  12.     System.arraycopy(weights, 0, P, 0, weights.length);  
  13.     Utils.normalize(P);  
  14.     double[] Q = newdouble[weights.length];  
  15.     int[] A = newint[weights.length];  
  16.     int[] W = newint[weights.length];  
  17.     int M = weights.length;  
  18.     int NN = -1;  
  19.     int NP = M;  
  20.     for (int I = 0; I < M; I++) {  
  21.       if (P[I] < 0) {  
  22.         thrownew IllegalArgumentException("Weights have to be positive.");  
  23.       }  
  24.       Q[I] = M * P[I];  
  25.       if (Q[I] < 1.0) {  
  26.         W[++NN] = I;  
  27.       } else {  
  28.         W[--NP] = I;  
  29.       }  
  30. 相關推薦

    Weka演算法Classifier-meta-Bagging原始碼分析

    一、Bagging演算法 嚴格來看Bagging並不能算是一種分類演算法,Bagging和Boosting一樣,是一種組合基本分類器的方法,也就是使用多個基分類器來獲取更為強大的分類器,其核心思想是有放回的抽樣。 Bagging演算法的訓練流程: 1、從樣本集中有放回的抽樣M個樣本。 2、用這M

    Weka演算法Classifier-trees-RandomTree原始碼分析

    一、RandomTree演算法 在網上搜了一下,並沒有找到RandomTree的嚴格意義上的演算法描述,因此我覺得RandomTree充其量只是一種構建樹的思路,和普通決策樹相比,RandomTree會隨機的選擇若干屬性來進行構建而不是選取所有的屬性。

    Weka演算法Classifier-tree-J48原始碼分析(一)演算法和基本資料結構

    大概一年沒打理部落格了,重新拿起筆不知道該從哪裡寫起,想來想去就從最近手頭用的Weka寫起吧。 Weka為一個Java基礎上的機器學習工具,上手簡單,並提供圖形化介面,提供如分類、聚類、頻繁項挖掘等工具,本篇文章主要寫一下分類器演算法中的J48演算法及其實現。 一、演算

    區塊鏈教程Fabric1.0原始碼分析流言演算法Gossip服務端二

      區塊鏈教程Fabric1.0原始碼分析流言演算法Gossip服務端二 Fabric 1.0原始碼筆記 之 gossip(流言演算法) #GossipServer(Gossip服務端) 5.2、commImpl結構體方法 //conn.serviceConnection(),啟動連線服務 func (

    區塊鏈教程Fabric1.0原始碼分析流言演算法Gossip服務端一

      區塊鏈教程Fabric1.0原始碼分析流言演算法Gossip服務端一,2018年下半年,區塊鏈行業正逐漸褪去發展之初的浮躁、迴歸理性,表面上看相關人才需求與身價似乎正在回落。但事實上,正是初期泡沫的漸退,讓人們更多的關注點放在了區塊鏈真正的技術之上。 Fabric 1.0原始碼筆記 之 gossip(流

    OpenCV學習筆記(31)KAZE 演算法原理與原始碼分析(五)KAZE的原始碼優化及與SIFT的比較

      KAZE系列筆記: 1.  OpenCV學習筆記(27)KAZE 演算法原理與原始碼分析(一)非線性擴散濾波 2.  OpenCV學習筆記(28)KAZE 演算法原理與原始碼分析(二)非線性尺度空間構建 3.  Op

    OpenCV學習筆記(30)KAZE 演算法原理與原始碼分析(四)KAZE特徵的效能分析與比較

          KAZE系列筆記: 1.  OpenCV學習筆記(27)KAZE 演算法原理與原始碼分析(一)非線性擴散濾波 2.  OpenCV學習筆記(28)KAZE 演算法原理與原始碼分析(二)非線性尺度空間構

    SURF演算法原理與原始碼分析

    如果說SIFT演算法中使用DOG對LOG進行了簡化,提高了搜尋特徵點的速度,那麼SURF演算法則是對DoH的簡化與近似。雖然SIFT演算法已經被認為是最有效的,也是最常用的特徵點提取的演算法,但如果不借助於硬體的加速和專用影象處理器的配合,SIFT演算法以現有的計算機仍然很難達到實時的程度。對於需要

    區塊鏈教程Fabric1.0原始碼分析ECDSA橢圓曲線數字簽名演算法

      兄弟連區塊鏈教程Fabric1.0原始碼分析ECDSA橢圓曲線數字簽名演算法,2018年下半年,區塊鏈行業正逐漸褪去發展之初的浮躁、迴歸理性,表面上看相關人才需求與身價似乎正在回落。但事實上,正是初期泡沫的漸退,讓人們更多的關注點放在了區塊鏈真正的技術之上。 Fabric 1.0原始碼筆記 之 ECDS

    64.ImageLoader原始碼分析-磁碟命名和圖片快取演算法

    一. 前言 ImageLoader的圖片快取分成磁碟和記憶體兩種,這裡分析一下磁碟快取以及圖片檔名演算法的實現 預設是不儲存在磁碟上的,需要手動開啟開關 如下 DisplayImageOptions options = new DisplayImageOptions.Builder()

    63.ImageLoader原始碼分析-記憶體快取演算法

    一. 前言 圖片記憶體快取可以提高圖片顯示速度,但是有些問題,比如佔用記憶體,如果不加以控制,甚至可能會OOM 所以,需要提供各種各樣的演算法來控制記憶體的使用,以適應不同的使用場景,目前,ImageLoader提供了若干記憶體管理演算法。 預設記憶體快取是關閉的,需要手動開啟 二. 繼承關係圖

    java併發之原子操作類(AtomicLong原始碼分析)和非阻塞演算法

      背景 近年來,在併發演算法領域的大多數研究都側重於非阻塞演算法,這種演算法用底層的原子機器指令(例如比較併發交換指令)代替鎖來確保資料在併發訪問中的一致性。非阻塞演算法被廣泛的用於在作業系統和JVM中實現執行緒/程序排程機制、垃圾回收機制以及鎖和其他併發資料結構。 與基於鎖

    【轉】【java原始碼分析】Map中的hash演算法分析

    全網把Map中的hash()分析的最透徹的文章,別無二家。 2018年05月09日 09:08:08 閱讀數:957 你知道HashMap中hash方法的具體實現嗎?你知道HashTable、ConcurrentHashMap中hash方法

    DAGScheduler原始碼分析stage劃分演算法,task最佳位置計算演算法

    在DAGScheduler類中的HandleJobSubmitted是job排程的核心入口 進入了newStage()方法它會建立一個stage物件 進入submitStage()方法 進入getMissingParentStages方法() 進入s

    STL原始碼分析之copy演算法

    前言 在前面分析順序容器和關聯容器時, 總會遇到copy這個函式, 當時並沒有去分析這個函式, 畢竟都能知道他是什麼功能, 本節就來揭開它面紗. copy分析 copy函式原始碼在stl_algobase.h中, 該結構中還有很多其他的演算法實現, 我只是從中挑選出了copy

    Openck_Swift原始碼分析——新增、刪除裝置時演算法詳細的實現過程

    1 初始加入裝置後、上傳Object的詳細流程  前幾篇部落格中,我們講到環的基本原理即詳細的實現過程,加入我們在初始建立Ring是執行例如以下幾條命令: •swift-ring-builder object.builder 

    105 - kube-scheduler原始碼分析 - predicate演算法註冊

    一、predicate註冊過程  今天我們來聊聊predicate函式是怎麼被註冊進去的,也就是要執行的一堆predicate是怎麼成為“選中的孩子”。  程式碼位置:pkg/scheduler/factory/plugins.go:111

    Android版資料結構與演算法(五):LinkedHashMap核心原始碼徹底分析

    上一篇基於雜湊表實現HashMap核心原始碼徹底分析 分析了HashMap的原始碼,主要分析了擴容機制,如果感興趣的可以去看看,擴容機制那幾行最難懂的程式碼真是花費了我很大的精力。  好了本篇我們分析一下HashMap的兒子LinkedHashMap的核心原始碼,提到LinkedHashMap做安卓的同學肯

    redis原始碼分析與思考(三)——字典中鍵的兩種hash演算法

          在Redis字典中,得到鍵的hash值顯得尤為重要,因為這個不僅關乎到是否字典能做到負載均衡,以及在效能上優勢是否突出,一個良好的hash演算法在此時就能發揮出巨大的作用。而一個良好的has

    【Go 原始碼分析】從 sort.go 看排序演算法的工程實踐

    go version go1.11 darwin/amd64file: src/sort/sort.go 排序演算法有很多種類,比如快排、堆排、插入排序等。各種排序演算法各有其優劣性,在實際生產過程中用到的排序演算法(或者說 Sort 函式)通常是由幾種排序演算法組