Weka演算法Classifier-trees-REPTree源碼分析(二)

來源:互聯網
上載者:User

標籤:機器學習   分類器   weka   演算法   源碼   

(接上篇)


一、剪枝過程

上篇分析完了tree節點的構建過程,在REPTree.buildClassifier之後如果設定了剪枝選項,則還有一個剪枝和backfit過程。

    if (!m_NoPruning) {      m_Tree.insertHoldOutSet(prune);      m_Tree.reducedErrorPrune();      m_Tree.backfitHoldOutSet();    }


其中insertHoldOutSet就是把剪枝用到的資料集傳進去,不具體的區跟代碼了。

重點卡一下reducedErrorPrune和backfitHoldOutSet過程。


二、Tree.reducedErrorPrune

    protected double reducedErrorPrune() throws Exception {<span style="white-space:pre"></span>//這個函數會返回該樹及其子樹的一個錯誤情況,如果是枚舉類型返回的是分錯的instance數量,數實值型別返回的是與正確值的偏差的平方和      // 如果是葉子節點就不做任何操作      if (m_Attribute == -1) {return m_HoldOutError;//簡單的說一下這個error怎麼計算來的,使用<span style="font-size:18px;">insertHoldOutSet傳入資料時會根據原先訓練時的分布,來預測出傳入資料的class,然後根據這個結果和真正的class值進行比對,就知道是否分的正確了</span>      }      //計算一下所有的子樹的偏差      double errorTree = 0;      for (int i = 0; i < m_Successors.length; i++) {errorTree += m_Successors[i].reducedErrorPrune();      }      if (errorTree >= m_HoldOutError) {m_Attribute = -1;//如果子樹偏差大於本身的偏差,那子樹就沒啥存在的意義了,直接去掉。m_Successors = null;return m_HoldOutError;      } else {return errorTree;      }    }
可以看出,這個剪枝過程和J48相比還是簡單不少的。


三、Tree.backfitHoldOutSet

protected void backfitHoldOutSet() throws Exception {            // Insert instance into hold-out class distribution      if (m_Info.classAttribute().isNominal()) {// Nominal caseif (m_ClassProbs == null) {  m_ClassProbs = new double[m_Info.numClasses()];}System.arraycopy(m_Distribution, 0, m_ClassProbs, 0, m_Info.numClasses());        for (int i = 0; i < m_HoldOutDist.length; i++) {          m_ClassProbs[i] += m_HoldOutDist[i];        }        if (Utils.sum(m_ClassProbs) > 0) {          Utils.normalize(m_ClassProbs);        } else {          m_ClassProbs = null;        }      } else {// Numeric case        double sumOfWeightsTrainAndHoldout = m_Distribution[1] + m_HoldOutDist[0];        if (sumOfWeightsTrainAndHoldout <= 0) {          return;        }if (m_ClassProbs == null) {  m_ClassProbs = new double[1];} else {          m_ClassProbs[0] *= m_Distribution[1];        }m_ClassProbs[0] += m_HoldOutDist[1];m_ClassProbs[0] /= sumOfWeightsTrainAndHoldout;      }            // The process is recursive      if (m_Attribute != -1) {        for (int i = 0; i < m_Successors.length; i++) {          m_Successors[i].backfitHoldOutSet();        }      }    }
可以看出,就是一個根據新傳入的資料集對原資料的分布進行重新計算,並且再對子樹進行遞迴的調用backfit的過程,不再詳細對代碼進行注釋了。


四、REPTree和J48的比較

同樣都是分類樹,REPTree和J48有很多不同點,下面簡單的說一說這些差異。

1、對連續值排序的處理

J48在處理連續值的時候,每一個subset都要進行排序,而REPTree是先在主流程中對所有屬性進行排序,並產生index傳給Tree節點來進行處理的。

因此J48所耗時間比較長,而REPTree則佔用較大記憶體(資料數量*資料屬性列數量,因此也可以看到REPTree的代碼中不斷的有顯式置空去嘗試釋放記憶體的操作),這是一個典型的時間和空間的tradeoff。

2、遞迴允出準則

J48的分裂停止條件有5個,

(1)所有的instances已經屬於同一個分類(selectModel裡)

(2)instances數量小於2*minNoObj(selectModel裡)

(3)一個分裂產生的資訊增益石0(selectModel裡)

(4)對離散值進行分裂節點的計算時,超過一個的Bag裡的instance數量小於minNoObj(spliter裡)

(5)對連續值進行分裂計算時,有效instances數量小於2*minNoObj(spliter裡)

REPTree的停止條件有4個

(1)訓練集數量小於2*minNum

(2)如果枚舉類型,且在一個類中

(3)如果數值類型,方差小於一個給定值

(4)達到最大深度

可以看出,主要的不同在於REPTree使用方差來判斷連續值是否結束分裂。

3、節點選擇方式

J48使用資訊增益率,REPTree使用資訊增益

4、剪枝與backfit

J48的剪枝較為複雜,分成了collapse()和prune()兩個操作,而REPTree的剪枝從邏輯上講只是J48的collapse操作,並沒有子樹上提等較為激進的剪枝策略。

J48沒有backfit,REPTree有backfit,這是因為J48就自己獨立的classifyInstance過程並不依賴樣本集的分布,而J48的classifyInstance是調用基類過程,需要自己儲存一個分布,進而使用backfit來防止過擬合。







Weka演算法Classifier-trees-REPTree源碼分析(二)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.