Weka演算法Classifier-meta-Bagging源碼分析

來源:互聯網
上載者:User

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


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,至於這個具體是個什麼,後面我再寫文章進行分析。

 public Bagging() {    m_Classifier = new weka.classifiers.trees.REPTree();  }


(2)構建過程BuildClassifier

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

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

if (m_CalcOutOfBag && (m_BagSizePercent != 100)) {      throw new IllegalArgumentException("Bag size needs to be 100% if "          + "out-of-bag error is to be calculated!");    }    int bagSize = data.numInstances() * m_BagSizePercent / 100;    Random random = new Random(m_Seed);    boolean[][] inBag = null;    if (m_CalcOutOfBag)      inBag = new boolean[m_Classifiers.length][];    for (int j = 0; j < m_Classifiers.length; j++) {      Instances bagData = null;      // create the in-bag dataset      if (m_CalcOutOfBag) {        inBag[j] = new boolean[data.numInstances()];        // bagData = resampleWithWeights(data, random, inBag[j]);        bagData = data.resampleWithWeights(random, inBag[j]);      } else {        bagData = data.resampleWithWeights(random);        if (bagSize < data.numInstances()) {          bagData.randomize(random);          Instances newBagData = new Instances(bagData, 0, bagSize);          bagData = newBagData;        }      }
這一部分是抽樣,首先如果有m_CalcOutOfBag標,則必須要求抽樣比例是100%。

其次算出要抽樣的大小。

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

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

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

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

if (getCalcOutOfBag()) { //如果有這個標就計算      double outOfBagCount = 0.0; //錯誤的權重和      double errorSum = 0.0;//錯誤的偏差值的和      boolean numeric = data.classAttribute().isNumeric();//是否是連續數值      for (int i = 0; i < data.numInstances(); i++) {        double vote;//代表投票結果        double[] votes;//代表投票        if (numeric)          votes = new double[1];//如果是數值,則取平均數,計算平均數的過程一個數組單元就夠了        else          votes = new double[data.numClasses()];//否則則要進行投票        // determine predictions for instance        int voteCount = 0;        for (int j = 0; j < m_Classifiers.length; j++) {          if (inBag[j][i])            continue;//如果已經被採樣,就忽略,因為要計算的是OutOfBag          voteCount++;//記錄有多少樣本被計算          if (numeric) {            votes[0] = m_Classifiers[j].classifyInstance(data.instance(i));//數值型則直接把預測結果累加          } else {
            double[] newProbs = m_Classifiers[j].distributionForInstance(data                .instance(i));            for (int k = 0; k < newProbs.length; k++) {              votes[k] += newProbs[k]; //枚舉型則要把所有枚舉機率進行累加            }          }        }        // "vote"        if (numeric) {          vote = votes[0];          if (voteCount > 0) {            vote /= voteCount; // 數值型取均值          }        } else {          if (Utils.eq(Utils.sum(votes), 0)) {          } else {            Utils.normalize(votes);//歸一化          }          vote = Utils.maxIndex(votes); // 選出最大的index        }        outOfBagCount += data.instance(i).weight();//累加權重        if (numeric) {          errorSum += StrictMath.abs(vote - data.instance(i).classValue())              * data.instance(i).weight();//累加錯誤偏差        } else {          if (vote != data.instance(i).classValue())            errorSum += data.instance(i).weight();//如果是枚舉就對出錯進行計數        }      }      m_OutOfBagError = errorSum / outOfBagCount;//最後取個平均值    } else {      m_OutOfBagError = 0;//如果沒有那個標就不計算了    }


三、根據權重進行無放回抽樣的過程

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

重載形式有3個,前兩個都會調用第三個:

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

  public Instances resampleWithWeights(Random random, boolean[] sampled) {    double[] weights = new double[numInstances()];    for (int i = 0; i < weights.length; i++) {      weights[i] = instance(i).weight();    }    return resampleWithWeights(random, weights, sampled);  }


public Instances resampleWithWeights(Random random, double[] weights,    boolean[] sampled) {    if (weights.length != numInstances()) {      throw new IllegalArgumentException("weights.length != numInstances.");    }    Instances newData = new Instances(this, numInstances());    if (numInstances() == 0) {      return newData;    }    // Walker's method, see pp. 232 of "Stochastic Simulation" by B.D. Ripley    double[] P = new double[weights.length];    System.arraycopy(weights, 0, P, 0, weights.length);    Utils.normalize(P);    double[] Q = new double[weights.length];    int[] A = new int[weights.length];    int[] W = new int[weights.length];    int M = weights.length;    int NN = -1;    int NP = M;    for (int I = 0; I < M; I++) {      if (P[I] < 0) {        throw new IllegalArgumentException("Weights have to be positive.");      }      Q[I] = M * P[I];      if (Q[I] < 1.0) {        W[++NN] = I;      } else {        W[--NP] = I;      }    }    if (NN > -1 && NP < M) {      for (int S = 0; S < M - 1; S++) {        int I = W[S];        int J = W[NP];        A[I] = J;        Q[J] += Q[I] - 1.0;        if (Q[J] < 1.0) {          NP++;        }        if (NP >= M) {          break;        }      }      // A[W[M]] = W[M];    }    for (int I = 0; I < M; I++) {      Q[I] += I;    }    for (int i = 0; i < numInstances(); i++) {      int ALRV;      double U = M * random.nextDouble();      int I = (int) U;      if (U < Q[I]) {        ALRV = I;      } else {        ALRV = A[I];      }      newData.add(instance(ALRV));      if (sampled != null) {        sampled[ALRV] = true;      }      newData.instance(newData.numInstances() - 1).setWeight(1);    }    return newData;  }

這個所謂的
Walker's method, see pp. 232 of "Stochastic Simulation" by B.D. Ripley
我找了半天也不知道是個啥演算法,代碼也沒啥注釋,大體一看沒看懂,等下次有機會再把這個函數的演算法補上吧。









Weka演算法Classifier-meta-Bagging源碼分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.