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

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

一、RandomTree演算法

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

Weka在實現上,對於隨機屬性的選取、生成分裂點的過程是這樣的:

1、設定一個要選取的屬性的數量K

2、在全域屬性中無放回的對屬性進行抽樣

3、算出該屬性的資訊增益(注意不是資訊增益率)

4、重複K次,選出資訊增益最大的當分裂節點。

5、構建該節點的孩子子樹。

二、具體程式碼實現

(1)buildClassifier

  1. publicvoid buildClassifier(Instances data) throws Exception {  
  2.    // 如果傳入的K不合理,把K放到一個合理的範圍裡
  3.    if (m_KValue > data.numAttributes() - 1)  
  4.      m_KValue = data.numAttributes() - 1;  
  5.    if (m_KValue < 1)  
  6.      m_KValue = (int) Utils.log2(data.numAttributes()) + 1;//這個是K的預設值
  7.    // 判斷一下該分類器是否有能力處理這個資料集,如果沒能力直接就在testWithFail裡拋異常退出了
  8.    getCapabilities().testWithFail(data);  
  9.    // 刪除掉missClass
  10.    data = new Instances(data);  
  11.    data.deleteWithMissingClass();  
  12.    // 如果只有一列,就build一個ZeroR模型,之後就結束了。ZeroR模型分類是這樣的:如果是連續型,總是返回期望,如果離散型,總是返回訓練集中出現最多的那個
  13.    if (data.numAttributes() == 1) {  
  14.      System.err  
  15.          .println("Cannot build model (only class attribute present in data!), "
  16.              + "using ZeroR model instead!");  
  17.      m_zeroR = new weka.classifiers.rules.ZeroR();  
  18.      m_zeroR.buildClassifier(data);  
  19.      return;  
  20.    } else {  
  21.      m_zeroR = null;  
  22.    }  
  23.    // 如果m_NumFlods大於0,則會把資料集分為兩部分,一部分用於train,一部分用於test,也就是backfit
  1. //分的方式和多折交叉驗證是一樣的,例如m_NumFlods是10的話,則train佔90%,backfit佔10%
  2.   Instances train = null;  
  3.   Instances backfit = null;  
  4.   Random rand = data.getRandomNumberGenerator(m_randomSeed);  
  5.   if (m_NumFolds <= 0) {  
  6.     train = data;  
  7.   } else {  
  8.     data.randomize(rand);  
  9.     data.stratify(m_NumFolds);  
  10.     train = data.trainCV(m_NumFolds, 1, rand);  
  11.     backfit = data.testCV(m_NumFolds, 1);  
  12.   }  
  13.   // 生成所有的可選屬性
  14.   int[] attIndicesWindow = newint[data.numAttributes() - 1];  
  15.   int j = 0;  
  16.   for (int i = 0; i < attIndicesWindow.length; i++) {  
  17.     if (j == data.classIndex())  
  18.       j++; // 忽略掉classIndex
  19.     attIndicesWindow[i] = j++;//這段程式碼有點奇怪,i和j是相等的,為啥不用attIndicesWindow=i?
  20.   }  
  21.   // 算出每個class的頻率,也就是每個分類出現的次數(更正確的說法應該是權重,但權重預設都是1)
  22.   double[] classProbs = newdouble[train.numClasses()];  
  23.   for (int i = 0; i < train.numInstances(); i++) {  
  24.     Instance inst = train.instance(i);  
  25.     classProbs[(int) inst.classValue()] += inst.weight();  
  26.   }  
  27.   // Build tree
  28.   m_Tree = new Tree();  
  29.   m_Info = new Instances(data, 0);  
  30.   m_Tree.buildTree(train, classProbs, attIndicesWindow, rand, 0);//呼叫tree的build方法,在後面單獨分析
  31.   // Backfit if required
  32.   if (backfit != null) {  
  33.     m_Tree.backfitData(backfit);//在後面單獨分析
  34.   }  
  35. }  

這個Tree物件是RandomTree的一個子類,之前我還以為會複用其餘的決策樹模型(比如J48),但weka沒這麼做,很驚奇的是RandomTree和J48的作者還是同一個,不知道為啥這麼設計。

(2)tree.buildTree

  1. protectedvoid buildTree(Instances data, double[] classProbs,  
  2.        int[] attIndicesWindow, Random random, int depth) throws Exception {  
  3.      //首先判斷一下是否有instance,如果沒有的話直接就返回
  4.      if (data.numInstances() == 0) {  
  5.        m_Attribute = -1;  
  6.        m_ClassDistribution = null;  
  7.        m_Prop = null;  
  8.        return;  
  9.      }  
  10.      m_ClassDistribution = classProbs.clone();  
  11.      if (Utils.sum(m_ClassDistribution) < 2 * m_MinNum  
  12.          || Utils.eq(m_ClassDistribution[Utils.maxIndex(m_ClassDistribution)],  
  13.              Utils.sum(m_ClassDistribution))  
  14.          || ((getMaxDepth() > 0) && (depth >= getMaxDepth()))) {  
  15.        // 遞迴結束的條件有3個 1、instance數量小於2*m_Minnum  2、instance都已經在同一個類中 3、達到最大的深度
  1. //前兩個條件和j48的遞迴結束條件很相似,相關內容可參考我之前的幾篇部落格。
  2.   m_Attribute = -1;  
  3.   m_Prop = null;  
  4.   return;  
  5. }  
  6. double val = -Double.MAX_VALUE;  
  7. double split = -Double.MAX_VALUE;  
  8. double[][] bestDists = null;  
  9. double[] bestProps = null;  
  10. int bestIndex = 0;  
  11. double[][] props = newdouble[1][0];  
  12. double[][][] dists = newdouble[1][0][0];//這個陣列第一列只有下標為0的被用到,不知道為啥這麼設計
  13. int attIndex = 0;//儲存被選擇到的屬性
  14. int windowSize = attIndicesWindow.length;//儲存目前可選擇的屬性的數量
  15. int k = m_KValue;//k代表還能選擇的屬性的數量
  16. boolean gainFound = false;//是否發現了一個有資訊增益的節點
  17. while ((windowSize > 0) && (k-- > 0 || !gainFound)) {//此迴圈退出條件有2個 1、沒有節點可以選了 2、已經選了k個屬性了並且找到了一個有用的屬性 換句話說,如果K次迭代沒有找到可以分裂的隨機節點,迴圈也會繼續下去

相關推薦

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

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

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

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

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 函式)通常是由幾種排序演算法組