決策樹簡單介紹(二) Accord.Net中決策樹的實現和使用


決策樹介紹

      決策樹是一類機器學習算法,可以實現對數據集的分類、預測等。具體請閱讀我另一篇博客(http://www.cnblogs.com/twocold/p/5424517.html)。

Accord.Net

      Accord.Net(http://accord-framework.net/)是一個開源的.Net環境下實現的機器學習算法庫。並且還包括了計算機視覺、圖像處理、數據分析等等許多算法,並且基本上都是用C#編寫的,對於.Net程序員十分友好。代碼在Github托管,並且現在仍在維護中。(https://github.com/accord-net/framework)。此處不再具體介紹,有興趣的可以去官網或者Github下載文檔和代碼深入了解。此處只簡單介紹決策樹部分的實現和使用方法。

決策樹結構

      決策樹、顧名思義,肯定是一個和樹結構,作為最基礎的數據結構之一,我們深知樹結構的靈活性。那么Accord.Net是如何實現這種結構的呢?看類圖

    

        首先觀察樹結構中最重要的一個結構,Node類的類圖如下:

      簡單介紹下主要屬性方法。

 

屬性

含義

IsLeaf

是否為葉子節點

IsRoot

是否為根節點

Output

指示結點的類別信息(葉子節點可用)

Value

為非根節點時,表示其父節點分割特征的值

Branches

為非葉子節點時,表示其子結點的集合

 

 

      還有樹結構:

    

 

屬性、方法

含義

Root

根節點

Attributes

標識各個特征的信息(連續、離散、范圍)

InputCount

特征個數

OutputClasses

輸出類別種數

Compute()

計算出某一樣本的類別信息

Load(),Save()

將決策樹存儲到文件或者讀出

ToAssembly()

存儲到dll程序集中

 

      還有其他依賴項就不再逐一介紹了,Accord的官方文檔里都有更加清晰的講解。

      主要想要說的是ID3Learning和C45Learning兩個類。這是Accord.Net實現的兩個決策樹學習(訓練)算法,ID3算法和C4.5算法(ID為Iterative Dichotomiser的縮寫,迭代二分器;C是Classifier的縮寫,即第4.5代分類器)。后面會介紹兩者的區別。

決策樹學習算法:

      這里以一個經典的打網球的例子,介紹ID3算法的學習過程。要理解下面的代碼可能需要對決策樹的學習過程有個基本的了解,可以參考開頭給出的鏈接學習下決策樹的基本概念。

     

Mitchell's Tennis Example

Day

Outlook

Temperature

Humidity

Wind

PlayTennis

D1

Sunny

Hot

High

Weak

No

D2

Sunny

Hot

High

Strong

No

D3

Overcast

Hot

High

Weak

Yes

D4

Rain

Mild

High

Weak

Yes

D5

Rain

Cool

Normal

Weak

Yes

D6

Rain

Cool

Normal

Strong

No

D7

Overcast

Cool

Normal

Strong

Yes

D8

Sunny

Mild

High

Weak

No

D9

Sunny

Cool

Normal

Weak

Yes

D10

Rain

Mild

Normal

Weak

Yes

D11

Sunny

Mild

Normal

Strong

Yes

D12

Overcast

Mild

High

Strong

Yes

D13

Overcast

Hot

Normal

Weak

Yes

D14

Rain

Mild

High

Strong

No

      

      首先,為了后面進一步構造決策樹,我們需要把上面的數據簡化一下,以字符串存儲和進行比較會消耗大量的內存空間,並且降低效率。考慮到所有特征都為離散特征,可以直接用最簡單的整型表示就行,只要保存下數字和字符串的對應關系就行。Accord.Net用了CodeBook來實現,這里也就不具體介紹了。然后需要對樹的一些屬性進行初始化,比如特征的個數(InputCount),類別數(OutputClasses)。還有每個特征可能的取值個數。接下來就可以利用上面codebook轉義過的樣本數據進行構造了。

      下面貼出ID3算法中遞歸方法的偽代碼,大致講解下其實現邏輯(注:此代碼刪去了很多細節,因此無法運行,只大概了解其實現邏輯。)。

 

 

        /// <summary>
        /// 決策樹學習的分割構造遞歸方法
        /// </summary>
        /// <param name="root">當前遞歸結點</param>
        /// <param name="input">輸入樣本特征</param>
        /// <param name="output">樣本對應類別</param>
        /// <param name="height">當前結點層數</param>
        private void split(DecisionNode root, int[][] input, int[] output, int height)
        {
            //遞歸return條件

            //1.如果output[]都相等,就是說當前所有樣本類別相同,則遞歸結束。結點標記為葉子節點,output值標識為樣本類別值           

            double entropy = Statistics.Tools.Entropy(output, outputClasses);

            if (entropy == 0)
            {
                if (output.Length > 0)
                    root.Output = output[0];
                return;
            }

            //2.如果當前路徑上所有特征都用過一次了,也就是說現在所有樣本在所有特征上取值相同,也就沒法划分了;遞歸結束。結點標記為葉子節點,output值標識為樣本類別值最多的那個

            //這個變量存儲的是還未使用的特征個數
            int candidateCount = attributeUsageCount.Count(x => x < 1);

            if (candidateCount == 0)
            {
                root.Output = Statistics.Tools.Mode(output);
                return;
            }


            // 如果需要繼續分裂,則首先尋找最優分裂特征,
            // 存儲剩余所有可以特征的信息增益大小
            double[] scores = new double[candidateCount];
            // 循環計算每個特征分裂時的信息增益存儲到scores里

            Parallel.For(0, scores.Length, i =>

            {
                scores[i] = computeGainRatio(input, output, candidates[i],
                    entropy, out partitions[i], out outputSubs[i]);
            }

            // 獲取到最大信息增益對應的特征
            int maxGainIndex = scores.Max();
            // 接下來 需要按照特征的值分割當前的dataset,然后傳遞給子節點 遞歸
            DecisionNode[] children = new DecisionNode[maxGainPartition.Length];

            for (int i = 0; i < children.Length; i++)
            {
                int[][] inputSubset = input.Submatrix(maxGainPartition[i]);

                split(children[i], inputSubset, outputSubset, height + 1); // 遞歸每個子節點

            }

            root.Branches.AddRange(children);

        }

 

 

      此代碼僅為方便理解,具體實現細節請自行下載Accord源代碼閱讀,相信您會有不少收獲。

      C4.5的實現與ID3算法流程基本相同,有幾個不同之處

      1) 在選擇最優分割特征時,ID3算法采用的是信息增益,C4.5采用的是增益率。

      2) C4.5支持連續型特征,因此,在遞歸進行之前,要采用二分法計算出n-1個候選划分點,將這些划分點當做離散變量處理就和ID3過程一致了。同樣是因為連續型變量,這樣一條路徑下連續型特征可以多次用來分割,而離散型特征每個只能用一次。

      3) C4.5支持缺失值的處理,遺憾的是Accord中並沒有加入這一特性。

     Accord.Net中還給出了簡單的剪枝算法,有興趣可以自行閱讀。

      

     以上面的打網球例子,這里給出Accord.Net中構造和訓練決策樹的代碼示例。

           //數據輸入 存儲為DataTable
             DataTable data = new DataTable("Mitchell's Tennis Example");
            data.Columns.Add("Day");
            data.Columns.Add("Outlook");
            data.Columns.Add("Temperature");
            data.Columns.Add("Humidity");
            data.Columns.Add("Wind");
            data.Columns.Add("PlayTennis");

            data.Rows.Add("D1", "Sunny", "Hot", "High", "Weak", "No");
            data.Rows.Add("D2", "Sunny", "Hot", "High", "Strong", "No");
            data.Rows.Add("D3", "Overcast", "Hot", "High", "Weak", "Yes");
            data.Rows.Add("D4", "Rain", "Mild", "High", "Weak", "Yes");
            data.Rows.Add("D5", "Rain", "Cool", "Normal", "Weak", "Yes");
            data.Rows.Add("D6", "Rain", "Cool", "Normal", "Strong", "No");
            data.Rows.Add("D7", "Overcast", "Cool", "Normal", "Strong", "Yes");
            data.Rows.Add("D8", "Sunny", "Mild", "High", "Weak", "No");
            data.Rows.Add("D9", "Sunny", "Cool", "Normal", "Weak", "Yes");
            data.Rows.Add("D10", "Rain", "Mild", "Normal", "Weak", "Yes");
            data.Rows.Add("D11", "Sunny", "Mild", "Normal", "Strong", "Yes");
            data.Rows.Add("D12", "Overcast", "Mild", "High", "Strong", "Yes");
            data.Rows.Add("D13", "Overcast", "Hot", "Normal", "Weak", "Yes");
            data.Rows.Add("D14", "Rain", "Mild", "High", "Strong", "No");
            // 創建一個CodeBook對象,用於將data中的字符串“翻譯”成整型
            Codification codebook = new Codification(data,
              "Outlook", "Temperature", "Humidity", "Wind", "PlayTennis");
            // 將data中的樣本特征數據部分和類別信息分別轉換成數組
            DataTable symbols = codebook.Apply(data);
            int[][] inputs = Matrix.ToArray<double>(symbols, "Outlook", "Temperature", "Humidity", "Wind");
            int[] outputs = Matrix.ToArray<int>(symbols, "PlayTennis");
            //分析得出每個特征的信息,如,每個特征的可取值個數。
           DecisionVariable[] attributes = DecisionVariable.FromCodebook(codebook, "Outlook", "Temperature", "Humidity", "Wind");

           int classCount = 2; //兩種可能的輸出,打網球和不打

            //根據參數初始化一個樹結構
            DecisionTree tree = new DecisionTree(attributes, classCount);

            // 創建一個ID3訓練方法
            ID3Learning id3learning = new ID3Learning(tree);

            // 訓練該決策樹
            id3learning.Run(inputs, outputs);

            //現在即可使用訓練完成的決策樹預測一個樣本,並借助codebook“翻譯”回來
            string answer = codebook.Translate("PlayTennis",tree.Compute(codebook.Translate("Sunny", "Hot", "High", "Strong")));

    貼一張利用決策樹做的小例子。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM